Compare commits

...

189 Commits

Author SHA1 Message Date
Jeremy Bícha
1cc8082c0a releasing package freerdp2 version 2.11.7+dfsg1-6 2024-12-18 10:11:19 -05:00
Adrien Nader
b607683919 * d/tests/connect: use /cert-tofu to avoid errors with proxies 2024-12-18 10:09:53 -05:00
Jeremy Bícha
dc059a2d39 releasing package freerdp2 version 2.11.7+dfsg1-5 2024-12-16 22:57:31 -05:00
Jeremy Bícha
cc9c0a66c8 autopkgtest: add Depends: ca-certificates 2024-12-16 22:15:07 -05:00
Jeremy Bícha
4d650bf630 releasing package freerdp2 version 2.11.7+dfsg1-4 2024-10-04 16:22:31 -04:00
Jeremy Bícha
48be888513 Replace autopkgtests with the tests used by freerdp3 2024-10-04 16:21:27 -04:00
Jeremy Bícha
6187297b6e releasing package freerdp2 version 2.11.7+dfsg1-3 2024-10-03 11:12:15 -04:00
Jeremy Bícha
47c0f4de25 Apply CVE-2024-32661 patch from Ubuntu 2024-10-03 11:10:17 -04:00
Bernhard Übelacker
5685a9eca1 Apply multiple fixes to autopkgtests
Closes: #1079025
2024-10-03 09:54:40 -04:00
Jeremy Bícha
40ac300cbc Remove obsolete time transition lintian overrides 2024-10-03 09:41:37 -04:00
Sébastien Noel
4930b843f5 Add patch to fix build with ffmpeg 7
Closes: #1072413
2024-10-03 09:40:14 -04:00
Jeremy Bícha
66e976dd46 Cherry-pick several patches to fix build with gcc-14
Closes: #1074969
2024-10-03 09:39:57 -04:00
Mike Gabriel
7a0cfc871a upload to unstable (debian/2.11.7+dfsg1-2) 2024-07-20 15:37:51 +02:00
Mike Gabriel
d8fe268285 debian/tests/control: Add xauth. Fix tests on Debian, where xvfb does not pull-in xauth as dependency (other than in Ubuntu). 2024-07-20 15:36:23 +02:00
Mike Gabriel
22e2e0315b upload to unstable (debian/2.11.7+dfsg1-1) 2024-07-15 16:51:34 +02:00
Mike Gabriel
f78f13ecf5 Update upstream source from tag 'upstream/2.11.7+dfsg1'
Update to upstream version '2.11.7+dfsg1'
with Debian dir 64ec704343
2024-07-15 16:44:16 +02:00
Mike Gabriel
ce01c78202 New upstream version 2.11.7+dfsg1 2024-07-15 16:44:11 +02:00
Mike Gabriel
3d3a1415b7 prepare new upstream release (v2.11.7) 2024-07-15 16:43:36 +02:00
Nathan Pratta Teodosio
df721c20b4 Add autopkgtest to test whether a client can connect
to an XRDP server via freerdp2 and that the login screen shows up

Closes: #1073156
LP: #2060976

Gbp-Dch: Full
2024-06-13 13:26:42 -04:00
Mike Gabriel
eeaac3f057 upload to unstable (debian/2.11.5+dfsg1-1) 2024-03-25 16:33:39 +01:00
Mike Gabriel
2d6a9f3b9b debian/control: Switch from pkg-config to pkgconf. Thanks, lintian. 2024-03-25 16:26:12 +01:00
Mike Gabriel
6fe4ba798f Update upstream source from tag 'upstream/2.11.5+dfsg1'
Update to upstream version '2.11.5+dfsg1'
with Debian dir 3a144157ec
2024-03-25 16:13:55 +01:00
Mike Gabriel
995fbfcdd7 New upstream version 2.11.5+dfsg1 2024-03-25 16:13:49 +01:00
Mike Gabriel
a0544fd1f6 debian/watch: Adjust so we only see 2.x release. 2024-03-25 16:13:02 +01:00
Mike Gabriel
1c5b0b32c3 prepare new upstream release (v2.11.5) 2024-03-25 16:08:59 +01:00
Lukas Märdian
382aa6b66a NMU to experimental (debian/2.11.2+dfsg1-1.1~exp2) 2024-03-25 16:04:28 +01:00
Lukas Märdian
bdad2ddbfa NMU to experimental (debian/2.11.2+dfsg1-1.1~exp1) 2024-03-25 16:04:07 +01:00
Mike Gabriel
da7dfbb2d6 upload to unstable (debian/2.11.2+dfsg1-1) 2023-10-01 23:52:38 +02:00
Mike Gabriel
682454acf9 debian/control: Add B-D: libkrb5-dev. 2023-10-01 23:36:38 +02:00
Mike Gabriel
577316d7c0 debian/rules: Add -DWITH_KERBEROS=ON configure option. (Closes: #1036095). 2023-10-01 23:34:51 +02:00
Mike Gabriel
928c8abca7 debian/watch: Rework file. Find all released versions of freerdp2. (Closes: #1053317). 2023-10-01 23:33:48 +02:00
Mike Gabriel
5bbfde9671 debian/patches: Drop 0001_fix_ftbfs_1041377.patch. Applied upstream. 2023-10-01 23:21:11 +02:00
Mike Gabriel
057b4985ff Update upstream source from tag 'upstream/2.11.2+dfsg1'
Update to upstream version '2.11.2+dfsg1'
with Debian dir d56d512921
2023-10-01 23:20:10 +02:00
Mike Gabriel
4bb5bc077f New upstream version 2.11.2+dfsg1 2023-10-01 23:19:42 +02:00
Mike Gabriel
3d5ae03c6a prepare new upstream release (v2.11.2) 2023-10-01 23:19:33 +02:00
Héctor Orón Martínez
d260e3c398 include upstream fix for FTBFS with FFmpeg 6.0
Fixes DebianBug #1041377

Signed-off-by: Héctor Orón Martínez <zumbi@debian.org>
2023-08-04 11:30:55 +02:00
Mike Gabriel
3a365cab32 upload to unstable (debian/2.10.0+dfsg1-1) 2023-02-26 22:47:29 +01:00
Mike Gabriel
a98f5e3e7c debian/libfreerdp2-2.symbols: Update symbols. 2023-02-26 22:46:13 +01:00
Mike Gabriel
67a51fdf54 debian/copyright: Update copyright attributions. 2023-02-26 22:30:32 +01:00
Mike Gabriel
05945da048 debian/copyright: Update auto-generated copyright.in file. 2023-02-26 22:27:57 +01:00
Mike Gabriel
4781bcfcda Update upstream source from tag 'upstream/2.10.0+dfsg1'
Update to upstream version '2.10.0+dfsg1'
with Debian dir b038285fe6
2023-02-26 21:53:37 +01:00
Mike Gabriel
2d5b821574 New upstream version 2.10.0+dfsg1 2023-02-26 21:53:19 +01:00
Mike Gabriel
ab16b2e2e4 debian/control: Bump Standards-Version: to 4.6.2. No changes needed. 2023-02-26 21:51:36 +01:00
Mike Gabriel
1a6267125c prepare new upstream release (v2.10.0) 2023-02-26 21:51:08 +01:00
Mike Gabriel
ac3e8bd4ac upload to unstable (debian/2.9.0+dfsg1-1) 2022-11-28 10:14:33 +01:00
Mike Gabriel
9f4041a26f debian/*.symbols: Update .symbols files. 2022-11-28 10:03:09 +01:00
Mike Gabriel
c0ca3d2d26 debian/copyright: Update auto-generated copyright.in file. 2022-11-28 09:51:53 +01:00
Mike Gabriel
ca0db20d36 debian/copyright: Update copyright attributions. 2022-11-28 09:51:36 +01:00
Mike Gabriel
8e69b04d95 Update upstream source from tag 'upstream/2.9.0+dfsg1'
Update to upstream version '2.9.0+dfsg1'
with Debian dir c712c5d91d
2022-11-28 09:30:26 +01:00
Mike Gabriel
97496cbb22 New upstream version 2.9.0+dfsg1 2022-11-28 09:30:00 +01:00
Mike Gabriel
307d2915d6 prepare new upstream release (v2.9.0) 2022-11-28 09:29:38 +01:00
Mike Gabriel
d556b6eca0 upload to unstable (debian/2.8.1+dfsg1-1) 2022-10-12 23:34:24 +02:00
Mike Gabriel
f37e46dc33 Update upstream source from tag 'upstream/2.8.1+dfsg1'
Update to upstream version '2.8.1+dfsg1'
with Debian dir 84624410bb
2022-10-12 23:28:40 +02:00
Mike Gabriel
03a18ec27e New upstream version 2.8.1+dfsg1 2022-10-12 23:28:31 +02:00
Mike Gabriel
9cec8baad9 debian/patches: Drop 1001_amend-DumpThreadHandles-inclusion.patch. Resolved upstream. 2022-10-12 23:26:41 +02:00
Mike Gabriel
cf6d35cc6a prepare new upstream release (v2.8.1) 2022-10-12 23:26:41 +02:00
Mike Gabriel
0bae4013ec debian/changelog: post-upload update with missing item. 2022-09-21 22:30:49 +02:00
Mike Gabriel
c232eabd62 upload to unstable (debian/2.8.0+dfsg1-1) 2022-09-21 22:24:45 +02:00
Mike Gabriel
833412e07b debian/*.symbols: Update .symbols files. 2022-09-21 22:24:31 +02:00
Mike Gabriel
d332a69cd6 debian/control: Bump Standards-Version: to 4.6.1. No changes needed. 2022-09-21 22:20:48 +02:00
Mike Gabriel
ce847dee67 debian/patches/: Drop 1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch. Applied upstream, but only partially. Add 1001_amend-DumpThreadHandles-inclusion.patch. Amend missing adjustment in thread.h. 2022-09-21 22:03:35 +02:00
Mike Gabriel
cfbb8ebcbd New upstream version 2.8.0+dfsg1 2022-09-21 21:49:18 +02:00
Mike Gabriel
e8d0f1c676 New upstream version 2.8.0+dfsg1 2022-08-16 23:18:01 +02:00
Mike Gabriel
f26a873894 debian/copyright: Update copyright attributions. 2022-08-16 23:04:46 +02:00
Mike Gabriel
1742e02337 debian/copyright: Update auto-generated copyright.in file. 2022-08-16 23:04:16 +02:00
Mike Gabriel
04e3d1c061 upload to unstable (debian/2.7.0+dfsg1-1) 2022-04-27 17:17:20 +02:00
Mike Gabriel
069a421a52 debian/*.symbols: Update .symbols for 2.7.0. 2022-04-27 16:55:15 +02:00
Mike Gabriel
f9cf50afd8 debian/copyright: Update copyright attributions. 2022-04-27 16:49:31 +02:00
Mike Gabriel
0caf470244 debian/copyright: Update auto-generated copyright.in file. 2022-04-27 16:49:20 +02:00
Mike Gabriel
af4000f101 Update upstream source from tag 'upstream/2.7.0+dfsg1'
Update to upstream version '2.7.0+dfsg1'
with Debian dir 85455a6037
2022-04-27 16:47:19 +02:00
Mike Gabriel
b937a3a632 New upstream version 2.7.0+dfsg1 2022-04-27 16:46:57 +02:00
Mike Gabriel
2f23bb8b95 prepare new upstream release (v2.7.0) 2022-04-27 16:46:01 +02:00
Mike Gabriel
f8793d5c6e upload to unstable (debian/2.6.1+dfsg1-3) 2022-03-08 08:43:43 +01:00
Mike Gabriel
30905452ca Revert "debian/libwinpr2-2.symbols: Update symbols."
This reverts commit 8d7afd7dd0.
2022-03-08 08:42:29 +01:00
Mike Gabriel
f726052dd4 debian/patches: Add 1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch. Keep DumpThreadHandles as a symbol even if WITH_DEBUG_THREADS is OFF. 2022-03-08 08:42:29 +01:00
Mike Gabriel
c13d353c77 upload to unstable (debian/2.6.1+dfsg1-2) 2022-03-08 08:12:07 +01:00
Bernhard Miklautz
8d7afd7dd0 debian/libwinpr2-2.symbols: Update symbols. 2022-03-08 08:06:37 +01:00
Bernhard Miklautz
a90b67e6c0 debian/rules: Disable additional debug logging. (Closes: #1006683). 2022-03-08 08:01:58 +01:00
Bernhard Miklautz
0b71f55532 debian/rules: Use ffmpeg for audio decoding if available to support additional audio formats. 2022-03-08 08:01:19 +01:00
Bernhard Miklautz
11fa5f7311 debian/control: Drop unused gstreamer dependencies libgstreamer1.0-dev and
libgstreamer-plugins-base1.0-dev.
2022-03-08 07:55:34 +01:00
Mike Gabriel
53c06fa209 upload to unstable (debian/2.6.1+dfsg1-1) 2022-03-08 07:49:51 +01:00
Mike Gabriel
ce43920f22 debian/copyright: Update copyright attributions. 2022-03-08 07:41:52 +01:00
Mike Gabriel
9292e895f0 debian/copyright.in: Update auto-generated copyright.in file. 2022-03-08 07:41:33 +01:00
Mike Gabriel
834bae447c debian/patches: Drop 2001-fake-git-revision.patch. Not required anymore. 2022-03-08 07:37:38 +01:00
Mike Gabriel
8fc6ef2a66 Update upstream source from tag 'upstream/2.6.1+dfsg1'
Update to upstream version '2.6.1+dfsg1'
with Debian dir 788e1fd09a
2022-03-08 07:35:08 +01:00
Mike Gabriel
f2ecc9e1e9 New upstream version 2.6.1+dfsg1 2022-03-08 07:34:48 +01:00
Mike Gabriel
167ff6dfdc prepare new upstream release (v2.6.1) 2022-03-08 07:34:42 +01:00
Mike Gabriel
85e7b6936c upload to unstable (debian/2.6.0+dfsg1-1) 2022-02-26 22:33:45 +01:00
Mike Gabriel
85472f7e5f debian/libfreerdp-server2-2.symbols: Update symbols. 2022-02-26 22:27:38 +01:00
Mike Gabriel
f7a9ffba9f rebase copyright 2022-02-26 22:20:57 +01:00
Mike Gabriel
63d3311554 debian/copyright: Update copyright attributions. 2022-02-26 21:55:22 +01:00
Mike Gabriel
c7cf752140 debian/copyright.in: Update auto-generated copyright.in file. 2022-02-26 21:55:08 +01:00
Mike Gabriel
4ab6e978fe Update upstream source from tag 'upstream/2.6.0+dfsg1'
Update to upstream version '2.6.0+dfsg1'
with Debian dir e82f2caa6e
2022-02-26 21:44:29 +01:00
Mike Gabriel
45f744e4b0 New upstream version 2.6.0+dfsg1 2022-02-26 21:44:23 +01:00
Mike Gabriel
cf66ce7ac6 debian/copyright: Update list of files in Files-Excluded: field. 2022-02-26 21:41:23 +01:00
Mike Gabriel
0f88669b15 prepare new upstream release (v2.6.0) 2022-02-26 21:14:11 +01:00
Mike Gabriel
0547b4933a upload to unstable (debian/2.5.0+dfsg1-1) 2022-02-14 08:31:43 +01:00
Mike Gabriel
ae4ce05b6b debian/copyright: Update copyright attributions. 2022-02-14 08:25:32 +01:00
Mike Gabriel
4f40975b3a debian/copyright: Update auto-generated copyright.in file. 2022-02-14 08:15:25 +01:00
Mike Gabriel
bbef5038b1 debian/patches/2001-fake-git-revision.patch: Mark patch as non-forwardable. 2022-02-14 08:15:25 +01:00
Mike Gabriel
b049925296 New upstream version 2.5.0+dfsg1 2022-02-14 08:15:25 +01:00
Mike Gabriel
1aaad2c68f New upstream version 2.5.0+dfsg1 2022-02-14 08:03:24 +01:00
Mike Gabriel
58e356d6f6 prepare new upstreak release (v2.5.0) 2022-02-14 08:02:55 +01:00
Mike Gabriel
a73b15bc0d upload to unstable (debian/2.4.1+dfsg1-1) 2021-12-09 23:22:33 +01:00
Mike Gabriel
a375cb6a81 debian/copyright: Update copyright attributions. 2021-12-09 23:16:29 +01:00
Mike Gabriel
2558cdec15 debian/copyright: Update auto-generated copyright.in reference file. 2021-12-09 23:16:17 +01:00
Mike Gabriel
12d8c44ea9 debian/libwinpr2-2.symbols: Update symbols. 2021-12-09 23:05:23 +01:00
Mike Gabriel
b6a6ec6f80 Update upstream source from tag 'upstream/2.4.1+dfsg1'
Update to upstream version '2.4.1+dfsg1'
with Debian dir 0b5f7144f0
2021-12-09 22:57:24 +01:00
Mike Gabriel
4e5cdbea0a New upstream version 2.4.1+dfsg1 2021-12-09 22:57:15 +01:00
Mike Gabriel
65144c4ee4 prepare new upstream release (v2.4.1) 2021-12-09 22:56:48 +01:00
Mike Gabriel
90d92d21f0 debian/patches/: Drop all patches pulled in from upstream recently. All part of 2.4.0. 2021-09-13 22:33:47 +02:00
Mike Gabriel
6378eb1d42 debian/copyright: Update auto-generated copyright.in template/reference file. 2021-09-13 22:33:47 +02:00
Mike Gabriel
55feba579f debian/control: Bump Standards-Version: to 4.6.0. No changes needed. 2021-09-13 22:33:38 +02:00
Mike Gabriel
2ef323aa69 New upstream version 2.4.0+dfsg1 2021-09-13 22:33:38 +02:00
Mike Gabriel
68e1ca324f New upstream version 2.4.0+dfsg1 2021-09-13 22:31:48 +02:00
Mike Gabriel
a2fc9432ec prepare new upstream release (2.4.0) 2021-09-13 22:25:21 +02:00
Mike Gabriel
21d2367ceb upload to unstable (debian/2.3.0+dfsg1-2) 2021-05-16 23:57:27 +02:00
Mike Gabriel
1a69e83215 debian/patches: Add 0035-Fixed-6989-Use-X509_STORE_set_default_paths.patch. Fix Windows 10 logon when using an internal trusted root CA. 2021-05-16 23:37:01 +02:00
Mike Gabriel
91e29c5e59 debian/patches: Add 0034-Fixed-6938-Remote-app-mode-clipboard-fix.patch. In remote app mode the _FREERDP_TIMESTAMP_PROPERTY does not work. Therefore ignore it. 2021-05-16 23:32:35 +02:00
Mike Gabriel
ff70cab82f debian/patches: add forgotten patch files 2021-04-29 12:34:37 +02:00
Mike Gabriel
2d7707f3f8 debian/changelog: update from Git history 2021-04-29 12:18:15 +02:00
Mike Gabriel
fc8bd9add6 debian/patches: Backport changes from 2.3.2 (bound checks, API compat fixes, Smartcard issues fixes, etc.).
0001-Added-compatibility-define.patch
    0003-Reverted-connectErrorCode-removal.patch
    0004-Fixed-a-leak-on-mouse-cursor-updates.patch
    0007-Fixed-format-string-in-smartcard_trace_state_return.patch
    0008-Fixed-linking-dependencies-for-client-geometry-chann.patch
    0010-Fixed-smartcard_convert_string_list-with-0-length.patch
    0012-Parse-on-a-copy-of-the-argument-string-for-printer.patch
    0015-Fix-xf_Pointer_SetPosition-with-smart-sizing.patch
    0017-Backported-6865-Disable-websockets-command-line-opti.patch
    0019-Check-smartcard_convert_string_list-for-NULL-string.patch
    0020-Use-specific-names-for-drive-hotplug-special-values.patch
    0021-Filter-RDPDR-types-other-than-drives-on-windows-hotp.patch
    0023-use-tlsOut-BIO-when-using-websocket-in-rdg_bio_ctrl.patch
    0024-Added-bounds-checks-to-gfx-commands.patch
    0025-Added-bounds-check-in-rdpgfx_recv_wire_to_surface_1_.patch
    0026-Added-fuzzying-test-for-planar-decoder.patch
    0027-Added-missing-bounds-check.patch
    0028-Fixed-mac-issues-with-smartcard-context-cleanup-6890.patch
    0031-Fix-monitor-list.patch
    0032-Fixed-CodeQL-warnings.patch
    0033-Reverted-winpr_BinToHexString-argument-change.patch
2021-04-29 12:05:39 +02:00
Mike Gabriel
a58a05cff9 debian/watch: Fix Github watch URL. 2021-04-29 11:54:12 +02:00
Mike Gabriel
702fe3f9aa upload to unstable (debian/2.3.0+dfsg1-1) 2021-02-25 16:50:58 +01:00
Mike Gabriel
bf9eaf6dde debian/control: Bump to Standards-Version: 4.5.1. No changes needed. 2021-02-25 16:16:25 +01:00
Mike Gabriel
4a2c5cc4fa debian/watch: Switch to format version 4. 2021-02-25 16:15:48 +01:00
Mike Gabriel
1fc6dbb280 debian/*.symbols: Update symbols for FreeRDP 2.3.0. 2021-02-25 16:14:28 +01:00
Mike Gabriel
69806bec69 debian/patches: Revert upstream's removal of the connectErrorCode symbol via 2002_revert-e4b30a5cb6100a8ea4f320b829c9c5712ed4a783.patch. This re-instates ABI compatibility with FreeRDP 2.2.0. 2021-02-25 16:14:02 +01:00
Mike Gabriel
5243d7ecba debian/patches: Drop 1001_spelling-fixes.patch. Applied upstream. 2021-02-25 16:13:02 +01:00
Mike Gabriel
6e36b45ff9 debian/copyright: Update copyright attributions: 2021-02-25 16:12:08 +01:00
Mike Gabriel
98586d2380 debian/copyright: Update auto-generated copyright.in file. 2021-02-25 16:11:54 +01:00
Mike Gabriel
0dc851016e Update upstream source from tag 'upstream/2.3.0+dfsg1'
Update to upstream version '2.3.0+dfsg1'
with Debian dir aaa97caffc
2021-02-25 15:19:16 +01:00
Mike Gabriel
3685742385 New upstream version 2.3.0+dfsg1 2021-02-25 15:19:08 +01:00
Mike Gabriel
ed9b274020 prepare new upstream release (v2.3.0+dfsg1) 2021-02-25 15:07:23 +01:00
Mike Gabriel
6d198059a2 Merge branch 'fix-backports-deps' into 'master'
Add missed binary version deps to avoid issue in some cases like upgrade to -backports

See merge request debian-remote-team/freerdp2!4
2021-02-25 14:05:13 +00:00
Fabio Fantoni
7966d9219f Add missed binary version deps to avoid issue in some cases like upgrade to -backports
In some cases like upgrade to -backports don't update all deps correctly
causing issues.
I already had in past, doing for example:
sudo apt -t buster-backports install freerdp2-x11
and latest times I workaround it with:
sudo apt -t buster-backports install freerdp2-x11 libfreerdp-client2-2
libfreerdp2-2 libwinpr2-2

This commit solve this issue adding binary version dependency on any
component (not only for x11 client but also wayland client, server and
other components used by other software, for example remmina).
Also avoided to add duplicate entries (if already present in other deps
of the component)

Closes: #964147
2021-02-15 15:51:02 +01:00
Mike Gabriel
b87910fc96 upload to unstable (debian/2.2.0+dfsg1-1) 2020-08-25 09:47:07 +02:00
Mike Gabriel
c118a0148b debian/libfreerdp-server2-2.symbols: Update symbols. 2020-08-25 09:45:26 +02:00
Mike Gabriel
cd9ec0da61 debian/libfreerdp2-2.symbols: Update symbols. 2020-08-25 09:35:27 +02:00
Mike Gabriel
fe6378ecd3 debian/copyright: Update copyright attributions. 2020-08-25 09:35:15 +02:00
Mike Gabriel
5c9c6b6890 debian/patches: Drop 0001-mask-CACHED_BRUSH-when-checking-brush-style.patch. Applied upstream. 2020-08-25 09:22:25 +02:00
Mike Gabriel
34e4ef129f Update upstream source from tag 'upstream/2.2.0+dfsg1'
Update to upstream version '2.2.0+dfsg1'
with Debian dir e498d308dc
2020-08-25 09:16:29 +02:00
Mike Gabriel
11e004d268 New upstream version 2.2.0+dfsg1 2020-08-25 09:16:19 +02:00
Mike Gabriel
f5d19a26c6 prepare new upstream release (v2.2.0) 2020-08-25 09:08:20 +02:00
Mike Gabriel
e6ef80167b upload to unstable (debian/2.1.2+dfsg1-2) 2020-07-02 15:06:17 +02:00
Konstantin Demin
8baebc39b4 debian/patches: add 0001-mask-CACHED_BRUSH-when-checking-brush-style.patch. Fix regression introduced in 2.1.2. 2020-07-02 15:02:26 +02:00
Mike Gabriel
e07d692f0f upload to unstable (debian/2.1.2+dfsg1-1) 2020-06-29 14:15:29 +02:00
Mike Gabriel
71cb74df5f debian/libwinpr2-2.symbols: Update symbols. 2020-06-29 14:10:04 +02:00
Mike Gabriel
e7fbbcca00 debian/copyright: Update copyright attributions. 2020-06-29 14:03:29 +02:00
Mike Gabriel
5f504f040f debian/copyright: Update auto-generated copyright.in file. 2020-06-29 14:03:13 +02:00
Mike Gabriel
1b42d1864a Update upstream source from tag 'upstream/2.1.2+dfsg1'
Update to upstream version '2.1.2+dfsg1'
with Debian dir fec582cd6d
2020-06-29 13:56:29 +02:00
Mike Gabriel
e672a1bc07 New upstream version 2.1.2+dfsg1 2020-06-29 13:56:21 +02:00
Mike Gabriel
2bba749e9d prepare new upstream release (v2.1.2) 2020-06-29 13:53:19 +02:00
Mike Gabriel
724b0ca3fd upload to unstable (debian/2.1.1+dfsg1-1) 2020-05-28 00:18:10 +02:00
Mike Gabriel
3c49534da9 New upstream version 2.1.1+dfsg1 2020-05-28 00:18:10 +02:00
Mike Gabriel
0136a1e751 debian/copyright: Update copyright attributions. 2020-05-28 00:18:10 +02:00
Mike Gabriel
7acf8c267f debian/copyright: Update auto-generated copyright.in file. 2020-05-28 00:18:10 +02:00
Mike Gabriel
e8c8aa4315 debian/control: Bump DH compat level to version 13. 2020-05-28 00:18:09 +02:00
Mike Gabriel
8e3d922b3a debian/rules: Re-add get-orig-source target for developers' convenience. 2020-05-28 00:18:09 +02:00
Mike Gabriel
912dda7d3e New upstream version 2.1.1+dfsg1 2020-05-28 00:16:30 +02:00
Mike Gabriel
7b93d179a4 debian/control: Add B-D: libpam0g-dev. (Closes: #958230). 2020-05-27 21:51:03 +02:00
Mike Gabriel
087a78eaf3 debian/changelog: update from Git log, bump upstream version to 2.1.1 2020-05-27 21:50:08 +02:00
Mike Gabriel
71289074c9 Merge branch 'wip-2.0.0' into 'master'
new upstream stable release 2.1.0

See merge request debian-remote-team/freerdp2!1
2020-05-16 09:36:32 +00:00
Konstantin Demin
c23d6e5522
debian/*.symbols: Update symbols files. 2020-05-15 10:30:15 +03:00
Konstantin Demin
7097255046
debian/rules: enable extended debug logging in freerdp2 itself. 2020-05-15 09:40:27 +03:00
Konstantin Demin
520a960178
debian/rules: fix build-time headers. 2020-05-15 09:39:14 +03:00
Konstantin Demin
d79d3435f1
debian/rules: specify correct build type 2020-05-15 01:03:34 +03:00
Konstantin Demin
febc688034
debian/rules: don't build freerdp-proxy so far 2020-05-15 01:02:46 +03:00
Konstantin Demin
682b29838a
debian/{control,rules}: enable image scaling support in freerdp. 2020-05-15 01:01:05 +03:00
Konstantin Demin
2ccf2b990b
debian/rules: rework layout. 2020-05-15 00:57:51 +03:00
Konstantin Demin
810f50e374
debian/patches: add 2001-fake-git-revision.patch. avoid Git interaction during build. 2020-05-15 00:35:24 +03:00
Konstantin Demin
9810fe2325
debian/{copyright,rules,watch}: use upstream tarball instead of Git snapshot. 2020-05-15 00:32:26 +03:00
Konstantin Demin
c533b1b395
debian/control: wrap-and-sort Build-Depends 2020-05-15 00:23:54 +03:00
Konstantin Demin
a249cc0471
debian/copyright: update upstream Source URL scheme to https. 2020-05-15 00:17:47 +03:00
Konstantin Demin
2feae26618
debian/control: update Homepage URL scheme to https. 2020-05-15 00:14:34 +03:00
Konstantin Demin
55aaa4bce0
debian/control: Bump Standards-Version: to 4.5.0. No changes needed. 2020-05-15 00:13:23 +03:00
Konstantin Demin
2bad0fc101
debian/patches: refresh 1001_spelling-fixes.patch. 2020-05-15 00:10:27 +03:00
Konstantin Demin
cd773f0284
debian/patches: drop 0002_fix-channels-smartcard-fix-statusw-call.patch. Applied upstream. 2020-05-15 00:07:53 +03:00
Konstantin Demin
9f7715c3c1
debian/patches: drop 0001_CVE-2019-17177.patch. Applied upstream. 2020-05-15 00:06:51 +03:00
Konstantin Demin
4ade698d02
new upstream stable version 2.1.0 2020-05-15 00:05:20 +03:00
Mike Gabriel
faaa641fab Merge branch 'drop-dbus-glib' into 'master'
debian/control: drop needless libdbus-glib-1-dev

As libdbus-glib-1-dev is deprecated in Bug#895291 [1], and dbus-glib
is not used at all, so it was removed from debian/control.
This commit fixes Bug#955840 unnecessarily Build-Depends on deprecated
dbus-glib. [2]

[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=895291
[2] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=955840

See merge request debian-remote-team/freerdp2!2
2020-05-14 19:55:03 +00:00
Kentaro Hayashi
0a5c52c556 debian/control: drop needless libdbus-glib-1-dev
As libdbus-glib-1-dev is deprecated in Bug#895291 [1], and dbus-glib
is not used at all, so it was removed from debian/control.
This commit fixes Bug#955840 unnecessarily Build-Depends on deprecated
dbus-glib. [2]

[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=895291
[2] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=955840
2020-05-10 15:50:16 +09:00
Mike Gabriel
4ab566bb23 debian/patches: Add 0002_fix-channels-smartcard-fix-statusw-call.patch. Fix smartcard login failures. (Closes: #919281). 2019-12-18 23:03:05 +01:00
Mike Gabriel
97e4118d5b upload to unstable (debian/2.0.0~git20190204.1.2693389a+dfsg1-2) 2019-12-16 11:34:35 +01:00
Mike Gabriel
a67bf7a39d debian/rules: Drop dbgsym:migration dh_strip overrides. 2019-12-16 11:32:54 +01:00
Mike Gabriel
94e4a9adb8 debian/patches: Add 0001_CVE-2019-17177.patch. Fix realloc return handling. (CVE-2019-17177). 2019-12-16 11:25:08 +01:00
Mike Gabriel
b7f902f748 debian/control: Add Rules-Requires-Root: field and set it to no. 2019-10-23 21:56:30 +02:00
Mike Gabriel
aa06bd72da debian/control: Bump Standards-Version: to 4.4.1. No changes needed. 2019-10-23 21:56:21 +02:00
Mike Gabriel
29326a1671 New upstream version 2.0.0~git20190204.1.2693389a+dfsg1 2019-02-04 10:00:57 +01:00
1498 changed files with 180807 additions and 186469 deletions

124
.clang-format Normal file
View File

@ -0,0 +1,124 @@
---
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: ForIndentation
...
Language: Cpp
Standard: Auto
NamespaceIndentation: All
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
...
Language: ObjC
PointerBindsToType: false
SortIncludes: false
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
...
Language: Java
BreakAfterJavaFieldAnnotations: false
...
Language: JavaScript
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
...
Language: Proto
...
Language: TableGen
...
Language: TextProto
...

25
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,25 @@
## Found a bug? - We would like to help you and smash the bug away.
1. __Please don't "report" questions as bugs.__
* We are reachable via IRC _#freerdp on freenode_
* We are reachable via mailing list <freerdp-devel@lists.sourceforge.net>
* Try our mailing list for discussions/questions
1. Before reporting a bug have a look into our issue tracker to see if the bug was already reported and you can add some additional information.
1. If it's a __new__ bug - create a new issue.
1. For more details see https://github.com/FreeRDP/FreeRDP/wiki/BugReporting
## To save time and help us identify the issue a bug report should at least contain the following:
* a useful description of the bug - "It's not working" isn't good enough - you must try harder ;)
* the steps to reproduce the bug
* command line you have used
* to what system did you connect to? (win8, 2008, ..)
* what did you expect to happen?
* what actually happened?
* freerdp version (e.g. xfreerdp --version) or package version or git commit
* freerdp configuration (e.g. xfreerdp --buildconfig)
* operating System, architecture, distribution e.g. linux, amd64, debian
* if you built it yourself add some notes which branch you have used, also your cmake parameters can help
* extra information helping us to find the bug
## Please remove this text before submitting your issue!
_Thank you for reporting a bug!_

56
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,56 @@
---
name: Bug report
about: Create a report to help us improve
---
**Found a bug? - We would like to help you and smash the bug away.**
1. __Please don't "report" questions as bugs. For these (questions/build instructions/...) please use one of the following means of contact:__
* We are reachable via IRC _#freerdp on freenode_
* We are reachable via mailing list <freerdp-devel@lists.sourceforge.net>
* Try our mailing list for discussions/questions
1. Before reporting a bug have a look into our issue tracker to see if the bug was already reported and you can add some additional information.
1. If it's a __new__ bug - create a new issue.
1. For more details see https://github.com/FreeRDP/FreeRDP/wiki/BugReporting
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Application details**
* Version of FreeRDP
* Command line used
* output of `/buildconfig`
* OS version connecting to
* If available the log output from a run with `/log-level:trace`
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
** Please remove this text before submitting your issue!
_Thank you for reporting a bug!_

View File

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

25
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,25 @@
## This is how are pull requests handled by FreeRDP
1. Every new pull request needs to build and pass the unit tests at https://ci.freerdp.com
1. At least 1 (better two) people need to review and test a pull request and agree to accept
## Preparations before creating a pull
* Rebase your branch to current master, no merges allowed!
* Try to clean up your commit history, group changes to commits
* Check your formatting! A _clang-format_ script can be found at ```.clang-format```
* The cmake target ```clangformat``` reformats the whole codebase
* Optional (but higly recommended)
* Run a clang scanbuild before and after your changes to avoid introducing new bugs
* Run your compiler at pedantic level to check for new warnings
## To ease accepting your contribution
* Give the pull request a proper name so people looking at it have an basic idea what it is for
* Add at least a brief description what it does (or should do :) and what it's good for
* Give instructions on how to test your changes
* Ideally add unit tests if adding new features
## What you should be prepared for
* fix issues found during the review phase
* Joining IRC _#freerdp_ to talk to other developers or help them test your pull might accelerate acceptance
* Joining our mailing list <freerdp-devel@lists.sourceforge.net> may be helpful too.
## Please remove this text before submitting your pull!

71
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master, stable* ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master, stable* ]
schedule:
- cron: '30 8 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
# - name: Autobuild
# uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
- run: |
sudo apt update
sudo apt install libxrandr-dev libxinerama-dev libusb-1.0-0-dev xserver-xorg-dev libswscale-dev libswresample-dev libavutil-dev libavcodec-dev libcups2-dev libpulse-dev libasound2-dev libpcsclite-dev xsltproc libxcb-cursor-dev libxcursor-dev libcairo2-dev libfaac-dev libfaad-dev libjpeg-dev libgsm1-dev ninja-build libxfixes-dev libxkbcommon-dev libwayland-dev libpam0g-dev libxdamage-dev libxcb-damage0-dev ccache libxtst-dev libfuse-dev libsystemd-dev libcairo2-dev libsoxr-dev
mkdir ci-build
cd ci-build
cmake -GNinja ../ci/cmake-preloads/config-linux-all.txt ..
cmake --build .
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

154
.gitignore vendored Normal file
View File

@ -0,0 +1,154 @@
#ninja
.ninja_deps
.ninja_log
build.ninja
rules.ninja
# CMake
CMakeFiles/
CMakeScripts/
CMakeCache.txt
config.h
install_manifest*.txt
CTestTestfile.cmake
*.pc
Makefile
Testing
cmake_install.cmake
CPackConfig.cmake
CPackSourceConfig.cmake
DartConfiguration.tcl
CMakeCPackOptions.cmake
_CPack_Packages
LICENSE.txt
/external/*
!external/README
*Config.cmake
*ConfigVersion.cmake
include/freerdp/version.h
include/freerdp/build-config.h
buildflags.h
*.a.objlist.cmake
*.a.objlist
*.a.objdir
*_dummy.c
*_dummy.c.base
# Eclipse
*.project
*.cproject
*.settings
nbproject/
compile_commands.json
# .rdp files
*.rdp
*.RDP
# Documentation
docs/api
client/X11/xfreerdp.1
client/X11/xfreerdp.1.xml
# Mac OS X
.DS_Store
*.xcodeproj/
DerivedData/
# iOS
FreeRDP.build
Debug-*
Release-*
# Windows
*.vcxproj
*.vcxproj.*
*.vcproj
*.vcproj.*
*.aps
*.sdf
*.sln
*.suo
*.ncb
*.opensdf
Thumbs.db
ipch
Debug
RelWithDebInfo
*.lib
*.exp
*.pdb
*.dll
*.ilk
*.resource.txt
*.embed.manifest*
*.intermediate.manifest*
version.rc
*.VC.db
*.VC.opendb
# Binaries
*.a
*.o
*.so
*.so.*
*.dylib
bin
libs
cunit/test_freerdp
client/X11/xfreerdp
client/Mac/xcode
client/Sample/sfreerdp
client/Wayland/wlfreerdp
server/Sample/sfreerdp-server
server/X11/xfreerdp-server
server/proxy/freerdp-proxy
xcode
libfreerdp/codec/test/TestOpenH264ASM
# Other
*~
*.dir
Release
Win32
build*/
*.orig
*.msrcIncident
default.log
*Amplifier XE*
*Inspector XE*
*.cbp
*.txt.user
*.autosave
# etags
TAGS
# generated packages
*.zip
*.exe
#*.sh
*.deb
*.rpm
*.dmg
*.tar.Z
*.tar.gz
# packaging related files
!packaging/**.sh
packaging/deb/freerdp-nightly/freerdp-nightly
packaging/deb/freerdp-nightly/freerdp-nightly-dev
packaging/deb/freerdp-nightly/freerdp-nightly-dbg
.source_version
#
.idea
# VisualStudio Code
.vscode
cache/

View File

@ -1 +0,0 @@
2693389a+debian

View File

@ -41,14 +41,16 @@ addons:
- libgsm1-dev
- libavcodec-dev
- libavutil-dev
- libx264-dev
- libxext-dev
- ninja-build
- libsystemd-dev
- libwayland-dev
before_script:
- ulimit -c unlimited -S
script:
- sudo hostname travis-ci.local
- cmake -G "Unix Makefiles" -C ci/cmake-preloads/config-linux-all.txt -D CMAKE_BUILD_TYPE=Debug -DWITH_LIBSYSTEMD=OFF -DWITH_WAYLAND=OFF .
- cmake -G Ninja -C ci/cmake-preloads/config-linux-all.txt -D CMAKE_BUILD_TYPE=Debug .
- make
- make test

View File

@ -34,9 +34,9 @@ if(NOT DEFINED FREERDP_VENDOR)
set(FREERDP_VENDOR 1)
endif()
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
option(CMAKE_COLOR_MAKEFILE "colorful CMake makefile" ON)
option(CMAKE_VERBOSE_MAKEFILE "verbose CMake makefile" ON)
option(CMAKE_POSITION_INDEPENDENT_CODE "build with position independent code (-fPIC or -fPIE)" ON)
# Include our extra modules
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
@ -51,6 +51,10 @@ endif()
include(CheckCmakeCompat)
# Include cmake modules
if(WITH_CLANG_FORMAT)
include(ClangFormat)
endif()
include(CheckIncludeFiles)
include(CheckLibraryExists)
include(CheckSymbolExists)
@ -70,6 +74,10 @@ include(InstallFreeRDPMan)
include(GetGitRevisionDescription)
include(SetFreeRDPCMakeInstallDir)
if (DEFINE_NO_DEPRECATED)
add_definitions(-DDEFINE_NO_DEPRECATED)
endif()
# Soname versioning
set(BUILD_NUMBER 0)
if ($ENV{BUILD_NUMBER})
@ -77,22 +85,22 @@ if ($ENV{BUILD_NUMBER})
endif()
set(WITH_LIBRARY_VERSIONING "ON")
set(RAW_VERSTION_STRING "2.0.0-dev5")
set(RAW_VERSION_STRING "2.11.7")
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSTION_STRING)
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
elseif(USE_VERSION_FROM_GIT_TAG)
git_get_exact_tag(_GIT_TAG --tags --always)
if (NOT ${_GIT_TAG} STREQUAL "n/a")
set(RAW_VERSTION_STRING ${_GIT_TAG})
set(RAW_VERSION_STRING ${_GIT_TAG})
endif()
endif()
string(STRIP ${RAW_VERSTION_STRING} RAW_VERSTION_STRING)
string(STRIP ${RAW_VERSION_STRING} RAW_VERSION_STRING)
set(VERSION_REGEX "^.?([0-9]+)\\.([0-9]+)\\.([0-9]+)-?(.*)")
string(REGEX REPLACE "${VERSION_REGEX}" "\\1" FREERDP_VERSION_MAJOR "${RAW_VERSTION_STRING}")
string(REGEX REPLACE "${VERSION_REGEX}" "\\2" FREERDP_VERSION_MINOR "${RAW_VERSTION_STRING}")
string(REGEX REPLACE "${VERSION_REGEX}" "\\3" FREERDP_VERSION_REVISION "${RAW_VERSTION_STRING}")
string(REGEX REPLACE "${VERSION_REGEX}" "\\4" FREERDP_VERSION_SUFFIX "${RAW_VERSTION_STRING}")
string(REGEX REPLACE "${VERSION_REGEX}" "\\1" FREERDP_VERSION_MAJOR "${RAW_VERSION_STRING}")
string(REGEX REPLACE "${VERSION_REGEX}" "\\2" FREERDP_VERSION_MINOR "${RAW_VERSION_STRING}")
string(REGEX REPLACE "${VERSION_REGEX}" "\\3" FREERDP_VERSION_REVISION "${RAW_VERSION_STRING}")
string(REGEX REPLACE "${VERSION_REGEX}" "\\4" FREERDP_VERSION_SUFFIX "${RAW_VERSION_STRING}")
set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}")
set(FREERDP_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}.${FREERDP_VERSION_REVISION}")
@ -103,6 +111,24 @@ else()
endif()
message("FREERDP_VERSION=${FREERDP_VERSION_FULL}")
if(EXISTS "${PROJECT_SOURCE_DIR}/.source_version" )
file(READ ${PROJECT_SOURCE_DIR}/.source_version GIT_REVISION)
string(STRIP ${GIT_REVISION} GIT_REVISION)
elseif(USE_VERSION_FROM_GIT_TAG)
git_get_exact_tag(GIT_REVISION --tags --always)
if (${GIT_REVISION} STREQUAL "n/a")
git_rev_parse (GIT_REVISION --short)
endif()
endif()
if (NOT GIT_REVISION)
set(GIT_REVISION ${FREERDP_VERSION})
endif()
message(STATUS "Git Revision ${GIT_REVISION}")
set(FREERDP_INCLUDE_DIR "include/freerdp${FREERDP_VERSION_MAJOR}/")
# Compatibility options
@ -139,25 +165,11 @@ if(CCACHE AND WITH_CCACHE)
endif()
endif(CCACHE AND WITH_CCACHE)
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_version" )
file(READ ${CMAKE_SOURCE_DIR}/.source_version GIT_REVISION)
string(STRIP ${GIT_REVISION} GIT_REVISION)
else()
git_get_exact_tag(GIT_REVISION --tags --always)
if (${GIT_REVISION} STREQUAL "n/a")
git_rev_parse (GIT_REVISION --short)
endif()
endif()
if(CMAKE_CROSSCOMPILING)
SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
endif(CMAKE_CROSSCOMPILING)
# /Allow to search the host machine for git/ccache
message(STATUS "Git Revision ${GIT_REVISION}")
# Turn on solution folders (2.8.4+)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@ -213,7 +225,7 @@ endif()
if(MSVC)
include(MSVCRuntime)
if(NOT DEFINED MSVC_RUNTIME)
set(MSVC_RUNTIME "dynamic")
set(MSVC_RUNTIME "dynamic" CACHE STRING "MSVC runtime type [dynamic|static]")
endif()
if(MSVC_RUNTIME STREQUAL "static")
if(BUILD_SHARED_LIBS)
@ -337,106 +349,99 @@ if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
endif()
endif()
set(THREAD_PREFER_PTHREAD_FLAG TRUE)
if(NOT IOS)
find_package(Threads REQUIRED)
endif()
if(NOT WIN32 AND NOT IOS)
CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
CHECK_LIBRARY_EXISTS(pthreads pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
if (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
set(HAVE_PTHREAD_MUTEX_TIMEDLOCK ON)
endif (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
endif()
# Enable address sanitizer, where supported and when required
if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_REQUIRED_FLAGS_SAVED ${CMAKE_REQUIRED_FLAGS})
CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer)
if (fno-omit-frame-pointer)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer")
endif()
set(CMAKE_REQUIRED_LINK_OPTIONS_SAVED ${CMAKE_REQUIRED_LINK_OPTIONS})
file(WRITE ${CMAKE_BINARY_DIR}/foo.txt "")
if(WITH_SANITIZE_ADDRESS)
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=address")
CHECK_C_COMPILER_FLAG ("-fsanitize=address" fsanitize-address)
CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist)
CHECK_C_COMPILER_FLAG ("-fsanitize-address-use-after-scope" fsanitize-address-use-after-scope)
unset(CMAKE_REQUIRED_FLAGS)
if(fsanitize-address)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
if(fsanitize-blacklist)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-address-sanitizer.txt")
endif(fsanitize-blacklist)
if(fsanitize-blacklist)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-address-sanitizer.txt")
endif(fsanitize-blacklist)
if(fsanitize-address-use-after-scope)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-address-use-after-scope")
endif(fsanitize-address-use-after-scope)
else(fsanitize-address)
message(WARNING "Missing support for address sanitizer!")
endif(fsanitize-address)
if(fno-omit-frame-pointer)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer")
endif()
if(fsanitize-address-use-after-scope)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-address-use-after-scope")
endif(fsanitize-address-use-after-scope)
elseif(WITH_SANITIZE_MEMORY)
set(CMAKE_REQUIRED_FLAGS "-fsanitize=memory")
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=memory")
CHECK_C_COMPILER_FLAG ("-fsanitize=memory" fsanitize-memory)
CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist)
CHECK_C_COMPILER_FLAG ("-fsanitize-memory-use-after-dtor" fsanitize-memory-use-after-dtor)
CHECK_C_COMPILER_FLAG ("-fsanitize-memory-track-origins" fsanitize-memory-track-origins)
unset(CMAKE_REQUIRED_FLAGS)
if(fsanitize-memory)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=memory")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=memory")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory")
if(fsanitize-blacklist)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-memory-sanitizer.txt")
endif(fsanitize-blacklist)
if(fsanitize-blacklist)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-memory-sanitizer.txt")
endif(fsanitize-blacklist)
if (fsanitize-memory-use-after-dtor)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-use-after-dtor")
endif(fsanitize-memory-use-after-dtor)
if (fsanitize-memory-use-after-dtor)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-use-after-dtor")
endif(fsanitize-memory-use-after-dtor)
if (fsanitize-memory-track-origins)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins")
endif(fsanitize-memory-track-origins)
else(fsanitize-memory)
message(WARNING "Missing support for memory sanitizer!")
endif(fsanitize-memory)
if(fno-omit-frame-pointer)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer")
endif()
if (fsanitize-memory-track-origins)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins")
endif(fsanitize-memory-track-origins)
elseif(WITH_SANITIZE_THREAD)
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=thread")
CHECK_C_COMPILER_FLAG ("-fsanitize=thread" fsanitize-thread)
CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist)
unset(CMAKE_REQUIRED_FLAGS)
if(fsanitize-thread)
set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=thread")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread")
if(fsanitize-blacklist)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-thread-sanitizer.txt")
endif(fsanitize-blacklist)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
else(fsanitize-thread)
message(WARNING "Missing support for thread sanitizer!")
endif(fsanitize-thread)
if(fno-omit-frame-pointer)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread")
if(fsanitize-blacklist)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-thread-sanitizer.txt")
endif(fsanitize-blacklist)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
endif()
file(REMOVE ${CMAKE_BINARY_DIR}/foo.txt)
set(CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS_SAVED})
if (WITH_NO_UNDEFINED)
set(CMAKE_REQUIRED_FLAGS "-Wl,--no-undefined")
CHECK_C_COMPILER_FLAG (-Wl,--no-undefined no-undefined)
unset(CMAKE_REQUIRED_FLAGS)
if(no-undefined)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined" )
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" )
endif()
endif()
set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVED})
endif()
if(MSVC)
@ -493,7 +498,7 @@ if(WIN32)
string(TIMESTAMP RC_VERSION_YEAR "%Y")
if(NOT DEFINED CMAKE_WINDOWS_VERSION)
set(CMAKE_WINDOWS_VERSION "WINXP")
set(CMAKE_WINDOWS_VERSION "WIN7")
endif()
if(CMAKE_WINDOWS_VERSION STREQUAL "WINXP")
@ -510,7 +515,7 @@ if(WIN32)
set(RC_VERSION_VENDOR ${VENDOR})
set(RC_VERSION_PRODUCT ${PRODUCT})
set(RC_VERSION_PATCH ${BUILD_NUMBER})
set(RC_VERSION_DESCRIPTION "${FREERDP_VERSION_FULL} ${GIT_REVISION} ${CMAKE_WINDOWS_VERSION} ${CMAKE_SYSTEM_PROCESSOR}")
set(RC_VERSION_DESCRIPTION "${FREERDP_VERSION_FULL} ${GIT_REVISION} ${CMAKE_WINDOWS_VERSION} ${CMAKE_SYSTEM_PROCESSOR}")
if (FREERDP_EXTERNAL_SSL_PATH)
set(OPENSSL_ROOT_DIR ${FREERDP_EXTERNAL_SSL_PATH})
@ -527,7 +532,6 @@ add_definitions(-DWINPR_EXPORTS -DFREERDP_EXPORTS)
if(NOT IOS)
check_include_files(fcntl.h HAVE_FCNTL_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(execinfo.h HAVE_EXECINFO_H)
check_include_files(inttypes.h HAVE_INTTYPES_H)
check_include_files(sys/modem.h HAVE_SYS_MODEM_H)
check_include_files(sys/filio.h HAVE_SYS_FILIO_H)
@ -535,6 +539,18 @@ if(NOT IOS)
check_include_files(sys/strtio.h HAVE_SYS_STRTIO_H)
check_include_files(sys/select.h HAVE_SYS_SELECT_H)
check_include_files(syslog.h HAVE_SYSLOG_H)
check_include_files(execinfo.h HAVE_EXECINFO_HEADER)
if (HAVE_EXECINFO_HEADER)
check_symbol_exists(backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)
check_symbol_exists(backtrace_symbols execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS)
check_symbol_exists(backtrace_symbols_fd execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD)
# Some implementations (e.g. Android NDK API < 33) provide execinfo.h but do not define
# the backtrace functions. Disable detection for these cases
if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS AND HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD)
set(HAVE_EXECINFO_H ON)
endif()
endif()
else()
set(HAVE_FCNTL_H 1)
set(HAVE_UNISTD_H 1)
@ -593,6 +609,11 @@ if(ANDROID)
set (WITH_NEON OFF)
endif()
if(ANDROID_ABI STREQUAL arm64-v8a)
# https://github.com/android/ndk/issues/910
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=softfp")
endif()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(-DNDK_DEBUG=1)
@ -611,7 +632,7 @@ if(ANDROID)
endif()
endif()
list (APPEND CMAKE_INCLUDE_PATH ${FREERDP_EXTERNAL_PATH}/include)
list (APPEND CMAKE_INCLUDE_PATH ${FREERDP_EXTERNAL_PATH}/${ANDROID_ABI}/include)
list (APPEND CMAKE_LIBRARY_PATH ${FREERDP_EXTERNAL_PATH}/${ANDROID_ABI}/ )
set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH )
set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH )
@ -622,26 +643,6 @@ if(ANDROID)
endif(WITH_GPROF)
endif()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
if(NOT IOS)
find_package(Threads REQUIRED)
endif()
if(NOT WIN32)
CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL)
if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
CHECK_LIBRARY_EXISTS(pthreads pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB)
if (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
set(HAVE_PTHREAD_MUTEX_TIMEDLOCK ON)
endif (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS)
endif()
if(WITH_VALGRIND_MEMCHECK)
check_include_files(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
else()
@ -667,6 +668,11 @@ if(UNIX OR CYGWIN)
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES m)
set(X11_FEATURE_TYPE "RECOMMENDED")
set(WAYLAND_FEATURE_TYPE "RECOMMENDED")
include(CheckFunctionExists)
check_function_exists(getlogin_r HAVE_GETLOGIN_R)
check_function_exists(getpwuid_r HAVE_GETPWUID_R)
else()
set(X11_FEATURE_TYPE "DISABLED")
set(WAYLAND_FEATURE_TYPE "DISABLED")
@ -706,15 +712,15 @@ set(ALSA_FEATURE_TYPE "RECOMMENDED")
set(ALSA_FEATURE_PURPOSE "sound")
set(ALSA_FEATURE_DESCRIPTION "audio input, audio output and multimedia redirection")
set(PULSE_FEATURE_TYPE "OPTIONAL")
set(PULSE_FEATURE_TYPE "RECOMMENDED")
set(PULSE_FEATURE_PURPOSE "sound")
set(PULSE_FEATURE_DESCRIPTION "audio input, audio output and multimedia redirection")
set(CUPS_FEATURE_TYPE "OPTIONAL")
set(CUPS_FEATURE_TYPE "RECOMMENDED")
set(CUPS_FEATURE_PURPOSE "printing")
set(CUPS_FEATURE_DESCRIPTION "printer device redirection")
set(PCSC_FEATURE_TYPE "OPTIONAL")
set(PCSC_FEATURE_TYPE "RECOMMENDED")
set(PCSC_FEATURE_PURPOSE "smart card")
set(PCSC_FEATURE_DESCRIPTION "smart card device redirection")
@ -724,15 +730,7 @@ set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback
set(VAAPI_FEATURE_TYPE "OPTIONAL")
set(VAAPI_FEATURE_PURPOSE "multimedia")
set(VAAPI_FEATURE_DESCRIPTION "VA-API hardware acceleration for video playback")
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia")
set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version")
set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED")
set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia")
set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
set(VAAPI_FEATURE_DESCRIPTION "[experimental] VA-API hardware acceleration for video playback")
set(IPP_FEATURE_TYPE "OPTIONAL")
set(IPP_FEATURE_PURPOSE "performance")
@ -742,14 +740,14 @@ set(JPEG_FEATURE_TYPE "OPTIONAL")
set(JPEG_FEATURE_PURPOSE "codec")
set(JPEG_FEATURE_DESCRIPTION "use JPEG library")
set(X264_FEATURE_TYPE "OPTIONAL")
set(X264_FEATURE_PURPOSE "codec")
set(X264_FEATURE_DESCRIPTION "use x264 library")
set(OPENH264_FEATURE_TYPE "OPTIONAL")
set(OPENH264_FEATURE_PURPOSE "codec")
set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library")
set(OPENCL_FEATURE_TYPE "OPTIONAL")
set(OPENCL_FEATURE_PURPOSE "codec")
set(OPENCL_FEATURE_DESCRIPTION "[experimental] use OpenCL library")
set(GSM_FEATURE_TYPE "OPTIONAL")
set(GSM_FEATURE_PURPOSE "codec")
set(GSM_FEATURE_DESCRIPTION "GSM audio codec library")
@ -764,7 +762,7 @@ set(FAAD2_FEATURE_DESCRIPTION "FAAD2 AAC audio codec library")
set(FAAC_FEATURE_TYPE "OPTIONAL")
set(FAAC_FEATURE_PURPOSE "codec")
set(FAAC_FEATURE_DESCRIPTION "FAAC AAC audio codec library")
set(FAAC_FEATURE_DESCRIPTION "[experimental] FAAC AAC audio codec library")
set(SOXR_FEATURE_TYPE "OPTIONAL")
set(SOXR_FEATURE_PURPOSE "codec")
@ -772,7 +770,7 @@ set(SOXR_FEATURE_DESCRIPTION "SOX audio resample library")
set(GSSAPI_FEATURE_TYPE "OPTIONAL")
set(GSSAPI_FEATURE_PURPOSE "auth")
set(GSSAPI_FEATURE_DESCRIPTION "add kerberos support")
set(GSSAPI_FEATURE_DESCRIPTION "[experimental] add kerberos support")
if(WIN32)
set(X11_FEATURE_TYPE "DISABLED")
@ -785,15 +783,12 @@ if(WIN32)
set(PCSC_FEATURE_TYPE "DISABLED")
set(FFMPEG_FEATURE_TYPE "DISABLED")
set(VAAPI_FEATURE_TYPE "DISABLED")
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
set(OPENSLES_FEATURE_TYPE "DISABLED")
endif()
if(APPLE)
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
set(VAAPI_FEATURE_TYPE "DISABLED")
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
set(X11_FEATURE_TYPE "OPTIONAL")
set(WAYLAND_FEATURE_TYPE "DISABLED")
set(OSS_FEATURE_TYPE "DISABLED")
@ -803,8 +798,6 @@ if(APPLE)
set(PULSE_FEATURE_TYPE "DISABLED")
set(CUPS_FEATURE_TYPE "DISABLED")
set(PCSC_FEATURE_TYPE "DISABLED")
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
endif()
set(OPENSLES_FEATURE_TYPE "DISABLED")
endif()
@ -832,10 +825,7 @@ if(ANDROID)
set(PULSE_FEATURE_TYPE "DISABLED")
set(CUPS_FEATURE_TYPE "DISABLED")
set(PCSC_FEATURE_TYPE "DISABLED")
set(FFMPEG_FEATURE_TYPE "DISABLED")
set(VAAPI_FEATURE_TYPE "DISABLED")
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
set(OPENSLES_FEATURE_TYPE "REQUIRED")
endif()
@ -856,12 +846,9 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION})
find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION})
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION})
find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION})
find_feature(OpenCL ${OPENCL_FEATURE_TYPE} ${OPENCL_FEATURE_PURPOSE} ${OPENCL_FEATURE_DESCRIPTION})
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
find_feature(LAME ${LAME_FEATURE_TYPE} ${LAME_FEATURE_PURPOSE} ${LAME_FEATURE_DESCRIPTION})
find_feature(FAAD2 ${FAAD2_FEATURE_TYPE} ${FAAD2_FEATURE_PURPOSE} ${FAAD2_FEATURE_DESCRIPTION})
@ -871,7 +858,7 @@ find_feature(soxr ${SOXR_FEATURE_TYPE} ${SOXR_FEATURE_PURPOSE} ${SOXR_FEATURE_DE
find_feature(GSSAPI ${GSSAPI_FEATURE_TYPE} ${GSSAPI_FEATURE_PURPOSE} ${GSSAPI_FEATURE_DESCRIPTION})
if (WITH_OPENH264 AND NOT WITH_OPENH264_LOADING)
set(WITH_OPENH264_LOADING OFF)
option(WITH_OPENH264_LOADING "Use LoadLibrary to load openh264 at runtime" OFF)
endif (WITH_OPENH264 AND NOT WITH_OPENH264_LOADING)
if ((WITH_FFMPEG OR WITH_DSP_FFMPEG) AND NOT FFMPEG_FOUND)
@ -885,18 +872,23 @@ if (WITH_DSP_FFMPEG)
# Deactivate FFmpeg backend for sound, if the version is too old.
# See libfreerdp/codec/dsp_ffmpeg.h
file(STRINGS "${AVCODEC_INCLUDE_DIR}/libavcodec/version.h" AV_VERSION_FILE REGEX "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+")
if (EXISTS "${AVCODEC_INCLUDE_DIR}/libavcodec/version_major.h")
file(STRINGS "${AVCODEC_INCLUDE_DIR}/libavcodec/version_major.h" AV_VERSION_FILE2 REGEX "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+")
list(APPEND AV_VERSION_FILE ${AV_VERSION_FILE2})
endif()
FOREACH(item ${AV_VERSION_FILE})
STRING(REGEX MATCH "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+" litem ${item})
IF(litem)
string(REGEX REPLACE "[ \t]+" ";" VSPLIT_LINE ${litem})
list(LENGTH VSPLIT_LINE VSPLIT_LINE_LEN)
if (NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
message(ERROR "invalid entry in libavcodec version header ${item}")
endif(NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
list(GET VSPLIT_LINE 0 VNAME)
list(GET VSPLIT_LINE 1 VVALUE)
set(${VNAME} ${VVALUE})
ENDIF(litem)
IF(litem)
string(REGEX REPLACE "[ \t]+" ";" VSPLIT_LINE ${litem})
list(LENGTH VSPLIT_LINE VSPLIT_LINE_LEN)
if (NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
message(ERROR "invalid entry in libavcodec version header ${item}")
endif(NOT "${VSPLIT_LINE_LEN}" EQUAL "2")
list(GET VSPLIT_LINE 0 VNAME)
list(GET VSPLIT_LINE 1 VVALUE)
set(${VNAME} ${VVALUE})
ENDIF(litem)
ENDFOREACH(item ${AV_VERSION_FILE})
set(AVCODEC_VERSION "${LIBAVCODEC_VERSION_MAJOR}.${LIBAVCODEC_VERSION_MINOR}.${LIBAVCODEC_VERSION_MICRO}")
@ -945,11 +937,7 @@ if(MBEDTLS_FOUND)
add_definitions("-DWITH_MBEDTLS")
endif()
if (TARGET_ARCH MATCHES "sparc")
set(HAVE_ALIGNED_REQUIRED 1)
endif()
if (WITH_X264 OR WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG)
if (WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG OR WITH_MEDIACODEC)
set(WITH_GFX_H264 ON)
else()
set(WITH_GFX_H264 OFF)
@ -957,32 +945,42 @@ endif()
# Android expects all libraries to be loadable
# without paths.
if (ANDROID)
set(FREERDP_DATA_PATH "share")
set(FREERDP_INSTALL_PREFIX ".")
set(FREERDP_LIBRARY_PATH ".")
set(FREERDP_PLUGIN_PATH ".")
set(FREERDP_ADDIN_PATH ".")
else (ANDROID)
if (ANDROID OR WIN32 OR MAC_BUNDLE)
set(FREERDP_DATA_PATH "share")
if (NOT FREERDP_INSTALL_PREFIX)
set(FREERDP_INSTALL_PREFIX ".")
endif()
set(FREERDP_LIBRARY_PATH ".")
set(FREERDP_PLUGIN_PATH ".")
else()
set(FREERDP_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/freerdp${FREERDP_VERSION_MAJOR}")
set(FREERDP_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
if (NOT FREERDP_INSTALL_PREFIX)
set(FREERDP_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
endif()
set(FREERDP_LIBRARY_PATH "${CMAKE_INSTALL_LIBDIR}")
set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}")
set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}")
endif(ANDROID)
endif()
set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}")
# Path to put extensions
set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}/extensions")
# Proxy plugins path
if(NOT DEFINED PROXY_PLUGINDIR)
message("using default plugins location")
set(FREERDP_PROXY_PLUGINDIR "${CMAKE_BINARY_DIR}/server/proxy/plugins")
else()
set(FREERDP_PROXY_PLUGINDIR "${PROXY_PLUGINDIR}")
endif()
# Declare we have config.h, generated later on.
add_definitions("-DHAVE_CONFIG_H")
# Include directories
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
# Configure files
add_definitions("-DHAVE_CONFIG_H")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
# RPATH configuration
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
@ -992,7 +990,16 @@ if (APPLE)
else (APPLE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
if (NOT FREEBSD)
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..")
if (NOT BUILTIN_CHANNELS)
if (NOT DEFINED WITH_PLUGIN_RPATH_ONLY)
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..:\$ORIGIN/../${FREERDP_PLUGIN_PATH}")
else()
# we need to supply this run path, even if not using RPATH in general
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${FREERDP_PLUGIN_PATH}")
endif()
else()
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..")
endif()
endif()
endif(APPLE)
@ -1055,15 +1062,6 @@ add_subdirectory(include)
add_subdirectory(libfreerdp)
if (IOS)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.0")
if (IOS_PLATFORM MATCHES "SIMULATOR")
set(CMAKE_OSX_SYSROOT "iphonesimulator")
else()
set(CMAKE_OSX_SYSROOT "iphoneos")
endif()
endif()
# RdTk
include_directories("${CMAKE_SOURCE_DIR}/rdtk/include")
include_directories("${CMAKE_BINARY_DIR}/rdtk/include")
@ -1098,6 +1096,9 @@ if(WITH_SERVER)
add_subdirectory(server)
endif()
# Configure files - Add last so all symbols are defined
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
# Packaging
set(CMAKE_CPACK_INCLUDE_FILE "CMakeCPack.cmake")

54714
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,22 @@
FreeRDP: A Remote Desktop Protocol Implementation
=================================================
# FreeRDP: A Remote Desktop Protocol Implementation
FreeRDP is a free implementation of the Remote Desktop Protocol (RDP), released under the Apache license.
Enjoy the freedom of using your software wherever you want, the way you want it, in a world where
interoperability can finally liberate your computing experience.
Resources
---------
## Resources
Project website: https://www.freerdp.com/
Issue tracker: https://github.com/FreeRDP/FreeRDP/issues
Sources: https://github.com/FreeRDP/FreeRDP/
Downloads: https://pub.freerdp.com/releases/
Wiki: https://github.com/FreeRDP/FreeRDP/wiki
API documentation: https://pub.freerdp.com/api/
Project website: https://www.freerdp.com/
Issue tracker: https://github.com/FreeRDP/FreeRDP/issues
Sources: https://github.com/FreeRDP/FreeRDP/
Downloads: https://pub.freerdp.com/releases/
Wiki: https://github.com/FreeRDP/FreeRDP/wiki
API documentation: https://pub.freerdp.com/api/
IRC channel: #freerdp @ irc.freenode.net
IRC channel: #freerdp @ irc.freenode.net
Mailing list: https://lists.sourceforge.net/lists/listinfo/freerdp-devel
Microsoft Open Specifications
-----------------------------
## Microsoft Open Specifications
Information regarding the Microsoft Open Specifications can be found at:
http://www.microsoft.com/openspecifications/
@ -27,8 +24,7 @@ http://www.microsoft.com/openspecifications/
A list of reference documentation is maintained here:
https://github.com/FreeRDP/FreeRDP/wiki/Reference-Documentation
Compilation
-----------
## Compilation
Instructions on how to get started compiling FreeRDP can be found on the wiki:
https://github.com/FreeRDP/FreeRDP/wiki/Compilation

View File

@ -32,7 +32,8 @@ macro(define_channel_options)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}" CHANNEL_OPTION)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" CHANNEL_CLIENT_OPTION)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_SERVER" CHANNEL_SERVER_OPTION)
string(TOUPPER "${CHANNEL_TYPE}" CHANNEL_TYPE)
if(${${CHANNEL_CLIENT_OPTION}})
set(OPTION_CLIENT_DEFAULT ${${CHANNEL_CLIENT_OPTION}})
endif()
@ -52,23 +53,30 @@ macro(define_channel_options)
set(CHANNEL_DEFAULT ${OPTION_DEFAULT})
set(CHANNEL_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel")
option(${CHANNEL_OPTION} "${CHANNEL_OPTION_DOC}" ${CHANNEL_DEFAULT})
if ("${CHANNEL_TYPE}" STREQUAL "DYNAMIC")
CMAKE_DEPENDENT_OPTION(${CHANNEL_OPTION} "${CHANNEL_OPTION_DOC}" ${CHANNEL_DEFAULT} "CHANNEL_DRDYNVC" OFF)
else()
option(${CHANNEL_OPTION} "${CHANNEL_OPTION_DOC}" ${CHANNEL_DEFAULT})
endif()
endmacro(define_channel_options)
macro(define_channel_client_options _channel_client_default)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" CHANNEL_CLIENT_OPTION)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}" CHANNEL_OPTION)
set(CHANNEL_CLIENT_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel client")
option(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}" ${_channel_client_default})
cmake_dependent_option(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}"
CMAKE_DEPENDENT_OPTION(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}"
${_channel_client_default} "${CHANNEL_OPTION}" OFF)
endmacro(define_channel_client_options)
macro(define_channel_server_options _channel_server_default)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_SERVER" CHANNEL_SERVER_OPTION)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}" CHANNEL_OPTION)
set(CHANNEL_SERVER_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel server")
option(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}" ${_channel_server_default})
cmake_dependent_option(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}"
CMAKE_DEPENDENT_OPTION(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}"
${_channel_server_default} "${CHANNEL_OPTION}" OFF)
endmacro(define_channel_server_options)
@ -167,7 +175,12 @@ macro(client_channel_install _targets _destination)
endmacro(client_channel_install)
macro(add_channel_client_library _module_prefix _module_name _channel_name _dynamic _entry)
if(${_dynamic} AND (NOT BUILTIN_CHANNELS))
set(_lnk_dir ${${_module_prefix}_LINK_DIRS})
if (NOT "${_lnk_dir}" STREQUAL "")
link_directories(${_lnk_dir})
endif()
if(${_dynamic} AND (NOT BUILTIN_CHANNELS))
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
@ -185,22 +198,30 @@ macro(add_channel_client_library _module_prefix _module_name _channel_name _dyna
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
add_library(${_module_name} ${${_module_prefix}_SRCS})
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE)
set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE)
set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE)
add_library(${_module_name} STATIC ${${_module_prefix}_SRCS})
if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS)
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
endif()
endif()
add_library(${_module_name} ${${_module_prefix}_SRCS})
target_link_libraries(${_module_name} ${${_module_prefix}_LIBS})
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE)
set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE)
set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE)
add_library(${_module_name} STATIC ${${_module_prefix}_SRCS})
target_link_libraries(${_module_name} ${${_module_prefix}_LIBS})
if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS)
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
endif()
endif()
endmacro(add_channel_client_library)
macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_name _type _dynamic _entry)
if(${_dynamic} AND (NOT BUILTIN_CHANNELS))
set(_lnk_dir ${${_module_prefix}_LINK_DIRS})
if (NOT "${_lnk_dir}" STREQUAL "")
link_directories(${_lnk_dir})
endif()
if(${_dynamic} AND (NOT BUILTIN_CHANNELS))
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
@ -218,21 +239,29 @@ macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_
set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
add_library(${_module_name} ${${_module_prefix}_SRCS})
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE)
set(${_module_prefix}_TYPE ${_type} PARENT_SCOPE)
add_library(${_module_name} STATIC ${${_module_prefix}_SRCS})
if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS)
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
endif()
endif()
add_library(${_module_name} ${${_module_prefix}_SRCS})
target_link_libraries(${_module_name} ${${_module_prefix}_LIBS})
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE)
set(${_module_prefix}_TYPE ${_type} PARENT_SCOPE)
add_library(${_module_name} STATIC ${${_module_prefix}_SRCS})
target_link_libraries(${_module_name} ${${_module_prefix}_LIBS})
if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS)
client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH})
endif()
endif()
endmacro(add_channel_client_subsystem_library)
macro(add_channel_server_library _module_prefix _module_name _channel_name _dynamic _entry)
if(${_dynamic} AND (NOT BUILTIN_CHANNELS))
set(_lnk_dir ${${_module_prefix}_LINK_DIRS})
if (NOT "${_lnk_dir}" STREQUAL "")
link_directories(${_lnk_dir})
endif()
if(${_dynamic} AND (NOT BUILTIN_CHANNELS))
# On windows create dll version information.
# Vendor, product and year are already set in top level CMakeLists.txt
if (WIN32)
@ -266,6 +295,23 @@ endmacro(add_channel_server_library)
set(FILENAME "ChannelOptions.cmake")
file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
# We need special treatement for drdynvc:
# It needs to be the first entry so that every
# dynamic channel has the dependent options available.
set(DRDYNVC_MATCH "")
foreach(FILEPATH ${FILEPATHS})
if(${FILEPATH} MATCHES "^([^/]*)drdynvc/+${FILENAME}")
set(DRDYNVC_MATCH ${FILEPATH})
endif()
endforeach()
if (NOT "${DRDYNVC_MATCH}" STREQUAL "")
list(REMOVE_ITEM FILEPATHS ${DRDYNVC_MATCH})
list(APPEND FILEPATHS ${DRDYNVC_MATCH})
list(REVERSE FILEPATHS) # list PREPEND is not available on old CMake3
endif()
foreach(FILEPATH ${FILEPATHS})
if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}")
string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" DIR ${FILEPATH})

View File

@ -1,7 +1,8 @@
# FreeRDP cmake android options
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2013 Thincast Technologies GmbH
# Copyright 2013 Bernhard Miklautz <bernhard.miklautz@thincast.com>
# Copyright 2022 Armin Novak <anovak@thincast.com>
# Copyright 2022 Thincast Technologies GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,8 +16,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
option(WITH_OPENSLES "Enable sound and microphone redirection using OpenSLES" ON)
define_channel("ainput")
set(ANDROID_APP_TARGET_SDK 21 CACHE STRING "Application target android SDK")
set(ANDROID_APP_MIN_SDK 14 CACHE STRING "Application minimum android SDK requirement")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

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

View File

@ -0,0 +1,34 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Armin Novak <anovak@thincast.com>
# Copyright 2022 Thincast Technologies GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_client("ainput")
set(${MODULE_PREFIX}_SRCS
ainput_main.c
ainput_main.h)
include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS)
install(FILES ${PROJECT_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols)
endif()
target_link_libraries(${MODULE_NAME} winpr)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")

View File

@ -0,0 +1,315 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Advanced Input Virtual Channel Extension
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#include "ainput_main.h"
#include <freerdp/channels/log.h>
#include <freerdp/client/ainput.h>
#include <freerdp/channels/ainput.h>
#include "../common/ainput_common.h"
#define TAG CHANNELS_TAG("ainput.client")
typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK;
struct AINPUT_CHANNEL_CALLBACK_
{
IWTSVirtualChannelCallback iface;
IWTSPlugin* plugin;
IWTSVirtualChannelManager* channel_mgr;
IWTSVirtualChannel* channel;
};
typedef struct AINPUT_LISTENER_CALLBACK_ AINPUT_LISTENER_CALLBACK;
struct AINPUT_LISTENER_CALLBACK_
{
IWTSListenerCallback iface;
IWTSPlugin* plugin;
IWTSVirtualChannelManager* channel_mgr;
AINPUT_CHANNEL_CALLBACK* channel_callback;
};
typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN;
struct AINPUT_PLUGIN_
{
IWTSPlugin iface;
AINPUT_LISTENER_CALLBACK* listener_callback;
IWTSListener* listener;
UINT32 MajorVersion;
UINT32 MinorVersion;
BOOL initialized;
};
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
{
UINT16 type;
AINPUT_PLUGIN* ainput;
AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback;
WINPR_ASSERT(callback);
WINPR_ASSERT(data);
ainput = (AINPUT_PLUGIN*)callback->plugin;
WINPR_ASSERT(ainput);
if (Stream_GetRemainingLength(data) < 2)
return ERROR_NO_DATA;
Stream_Read_UINT16(data, type);
switch (type)
{
case MSG_AINPUT_VERSION:
if (Stream_GetRemainingLength(data) < 8)
return ERROR_NO_DATA;
Stream_Read_UINT32(data, ainput->MajorVersion);
Stream_Read_UINT32(data, ainput->MinorVersion);
break;
default:
WLog_WARN(TAG, "Received unsupported message type 0x%04" PRIx16, type);
break;
}
return CHANNEL_RC_OK;
}
static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y)
{
AINPUT_PLUGIN* ainput;
AINPUT_CHANNEL_CALLBACK* callback;
BYTE buffer[32] = { 0 };
UINT64 time;
wStream sbuffer = { 0 };
wStream* s = &sbuffer;
Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
WINPR_ASSERT(s);
WINPR_ASSERT(context);
time = GetTickCount64();
ainput = (AINPUT_PLUGIN*)context->handle;
WINPR_ASSERT(ainput);
WINPR_ASSERT(ainput->listener_callback);
if (ainput->MajorVersion != AINPUT_VERSION_MAJOR)
{
WLog_WARN(TAG, "Unsupported channel version %" PRIu32 ".%" PRIu32 ", aborting.",
ainput->MajorVersion, ainput->MinorVersion);
return CHANNEL_RC_UNSUPPORTED_VERSION;
}
callback = ainput->listener_callback->channel_callback;
WINPR_ASSERT(callback);
{
char buffer[128] = { 0 };
WLog_VRB(TAG, "[%s] sending timestamp=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32,
__FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y);
}
/* Message type */
Stream_Write_UINT16(s, MSG_AINPUT_MOUSE);
/* Event data */
Stream_Write_UINT64(s, time);
Stream_Write_UINT64(s, flags);
Stream_Write_INT32(s, x);
Stream_Write_INT32(s, y);
Stream_SealLength(s);
/* ainput back what we have received. AINPUT does not have any message IDs. */
WINPR_ASSERT(callback->channel);
WINPR_ASSERT(callback->channel->Write);
return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s),
NULL);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback;
free(callback);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
AINPUT_CHANNEL_CALLBACK* callback;
AINPUT_LISTENER_CALLBACK* listener_callback = (AINPUT_LISTENER_CALLBACK*)pListenerCallback;
WINPR_ASSERT(listener_callback);
WINPR_UNUSED(Data);
WINPR_UNUSED(pbAccept);
callback = (AINPUT_CHANNEL_CALLBACK*)calloc(1, sizeof(AINPUT_CHANNEL_CALLBACK));
if (!callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
callback->iface.OnDataReceived = ainput_on_data_received;
callback->iface.OnClose = ainput_on_close;
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = &callback->iface;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT status;
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
WINPR_ASSERT(ainput);
if (ainput->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
ainput->listener_callback =
(AINPUT_LISTENER_CALLBACK*)calloc(1, sizeof(AINPUT_LISTENER_CALLBACK));
if (!ainput->listener_callback)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection;
ainput->listener_callback->plugin = pPlugin;
ainput->listener_callback->channel_mgr = pChannelMgr;
status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0,
&ainput->listener_callback->iface, &ainput->listener);
ainput->listener->pInterface = ainput->iface.pInterface;
ainput->initialized = status == CHANNEL_RC_OK;
return status;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
{
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
if (ainput && ainput->listener_callback)
{
IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, ainput->listener);
}
if (ainput)
{
free(ainput->listener_callback);
free(ainput->iface.pInterface);
}
free(ainput);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define DVCPluginEntry ainput_DVCPluginEntry
#else
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#endif
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
UINT status = CHANNEL_RC_OK;
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput");
if (!ainput)
{
AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext));
ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN));
if (!ainput || !context)
{
free(context);
free(ainput);
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
ainput->iface.Initialize = ainput_plugin_initialize;
ainput->iface.Terminated = ainput_plugin_terminated;
context->handle = (void*)ainput;
context->AInputSendInputEvent = ainput_send_input_event;
ainput->iface.pInterface = (void*)context;
status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface);
}
return status;
}

View File

@ -0,0 +1,43 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Advanced Input Virtual Channel Extension
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H
#define FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/channels/log.h>
#define DVC_TAG CHANNELS_TAG("ainput.client")
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__)
#else
#define DEBUG_DVC(...) \
do \
{ \
} while (0)
#endif
#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H */

View File

@ -0,0 +1,59 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Input Redirection Virtual Channel
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_INT_AINPUT_COMMON_H
#define FREERDP_INT_AINPUT_COMMON_H
#include <winpr/string.h>
#include <freerdp/channels/ainput.h>
static INLINE const char* ainput_flags_to_string(UINT64 flags, char* buffer, size_t size)
{
char number[32] = { 0 };
if (flags & AINPUT_FLAGS_HAVE_REL)
winpr_str_append("AINPUT_FLAGS_HAVE_REL", buffer, size, "|");
if (flags & AINPUT_FLAGS_WHEEL)
winpr_str_append("AINPUT_FLAGS_WHEEL", buffer, size, "|");
if (flags & AINPUT_FLAGS_MOVE)
winpr_str_append("AINPUT_FLAGS_MOVE", buffer, size, "|");
if (flags & AINPUT_FLAGS_DOWN)
winpr_str_append("AINPUT_FLAGS_DOWN", buffer, size, "|");
if (flags & AINPUT_FLAGS_REL)
winpr_str_append("AINPUT_FLAGS_REL", buffer, size, "|");
if (flags & AINPUT_FLAGS_BUTTON1)
winpr_str_append("AINPUT_FLAGS_BUTTON1", buffer, size, "|");
if (flags & AINPUT_FLAGS_BUTTON2)
winpr_str_append("AINPUT_FLAGS_BUTTON2", buffer, size, "|");
if (flags & AINPUT_FLAGS_BUTTON3)
winpr_str_append("AINPUT_FLAGS_BUTTON3", buffer, size, "|");
if (flags & AINPUT_XFLAGS_BUTTON1)
winpr_str_append("AINPUT_XFLAGS_BUTTON1", buffer, size, "|");
if (flags & AINPUT_XFLAGS_BUTTON2)
winpr_str_append("AINPUT_XFLAGS_BUTTON2", buffer, size, "|");
_snprintf(number, sizeof(number), "[0x%08" PRIx64 "]", flags);
winpr_str_append(number, buffer, size, " ");
return buffer;
}
#endif /* FREERDP_INT_AINPUT_COMMON_H */

View File

@ -0,0 +1,27 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Armin Novak <anovak@thincast.com>
# Copyright 2022 Thincast Technologies GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_server("ainput")
set(${MODULE_PREFIX}_SRCS
ainput_main.c)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View File

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

View File

@ -87,34 +87,36 @@ static snd_pcm_format_t audin_alsa_format(UINT32 wFormatTag, UINT32 bitPerChanne
}
}
static BOOL audin_alsa_set_params(AudinALSADevice* alsa,
snd_pcm_t* capture_handle)
static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle)
{
int error;
SSIZE_T s;
UINT32 channels = alsa->aformat.nChannels;
snd_pcm_hw_params_t* hw_params;
snd_pcm_format_t format = audin_alsa_format(alsa->aformat.wFormatTag, alsa->aformat.wBitsPerSample);
snd_pcm_format_t format =
audin_alsa_format(alsa->aformat.wFormatTag, alsa->aformat.wBitsPerSample);
if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_hw_params_malloc (%s)",
snd_strerror(error));
WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_hw_params_malloc (%s)", snd_strerror(error));
return FALSE;
}
snd_pcm_hw_params_any(capture_handle, hw_params);
snd_pcm_hw_params_set_access(capture_handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(capture_handle, hw_params, format);
snd_pcm_hw_params_set_rate_near(capture_handle, hw_params,
&alsa->aformat.nSamplesPerSec, NULL);
snd_pcm_hw_params_set_channels_near(capture_handle, hw_params,
&channels);
snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &alsa->aformat.nSamplesPerSec, NULL);
snd_pcm_hw_params_set_channels_near(capture_handle, hw_params, &channels);
snd_pcm_hw_params(capture_handle, hw_params);
snd_pcm_hw_params_free(hw_params);
snd_pcm_prepare(capture_handle);
alsa->aformat.nChannels = channels;
alsa->bytes_per_frame = snd_pcm_format_size(format, 1) * channels;
if (channels > UINT16_MAX)
return FALSE;
s = snd_pcm_format_size(format, 1);
if ((s < 0) || (s > UINT16_MAX))
return FALSE;
alsa->aformat.nChannels = (UINT16)channels;
alsa->bytes_per_frame = (size_t)s * channels;
return TRUE;
}
@ -123,12 +125,11 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg)
long error;
BYTE* buffer;
snd_pcm_t* capture_handle = NULL;
AudinALSADevice* alsa = (AudinALSADevice*) arg;
AudinALSADevice* alsa = (AudinALSADevice*)arg;
DWORD status;
WLog_Print(alsa->log, WLOG_DEBUG, "in");
if ((error = snd_pcm_open(&capture_handle, alsa->device_name,
SND_PCM_STREAM_CAPTURE, 0)) < 0)
if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0)
{
WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_open (%s)", snd_strerror(error));
error = CHANNEL_RC_INITIALIZATION_ERROR;
@ -141,7 +142,8 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg)
goto out;
}
buffer = (BYTE*) calloc(alsa->frames_per_packet + alsa->aformat.nBlockAlign, alsa->bytes_per_frame);
buffer =
(BYTE*)calloc(alsa->frames_per_packet + alsa->aformat.nBlockAlign, alsa->bytes_per_frame);
if (!buffer)
{
@ -181,12 +183,13 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg)
break;
}
error = alsa->receive(&alsa->aformat,
buffer, error * alsa->bytes_per_frame, alsa->user_data);
error =
alsa->receive(&alsa->aformat, buffer, error * alsa->bytes_per_frame, alsa->user_data);
if (error)
{
WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_thread_receive failed with error %ld", error);
WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_thread_receive failed with error %ld",
error);
break;
}
}
@ -200,8 +203,7 @@ out:
WLog_Print(alsa->log, WLOG_DEBUG, "out");
if (error && alsa->rdpcontext)
setChannelError(alsa->rdpcontext, error,
"audin_alsa_thread_func reported an error");
setChannelError(alsa->rdpcontext, error, "audin_alsa_thread_func reported an error");
ExitThread(error);
return error;
@ -214,7 +216,7 @@ out:
*/
static UINT audin_alsa_free(IAudinDevice* device)
{
AudinALSADevice* alsa = (AudinALSADevice*) device;
AudinALSADevice* alsa = (AudinALSADevice*)device;
if (alsa)
free(alsa->device_name);
@ -223,8 +225,7 @@ static UINT audin_alsa_free(IAudinDevice* device)
return CHANNEL_RC_OK;
}
static BOOL audin_alsa_format_supported(IAudinDevice* device,
const AUDIO_FORMAT* format)
static BOOL audin_alsa_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
{
if (!device || !format)
return FALSE;
@ -232,8 +233,7 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device,
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM:
if (format->cbSize == 0 &&
(format->nSamplesPerSec <= 48000) &&
if (format->cbSize == 0 && (format->nSamplesPerSec <= 48000) &&
(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
(format->nChannels == 1 || format->nChannels == 2))
{
@ -242,10 +242,6 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device,
break;
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
return TRUE;
default:
return FALSE;
}
@ -261,7 +257,7 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device,
static UINT audin_alsa_set_format(IAudinDevice* device, const AUDIO_FORMAT* format,
UINT32 FramesPerPacket)
{
AudinALSADevice* alsa = (AudinALSADevice*) device;
AudinALSADevice* alsa = (AudinALSADevice*)device;
if (!alsa || !format)
return ERROR_INVALID_PARAMETER;
@ -280,10 +276,9 @@ static UINT audin_alsa_set_format(IAudinDevice* device, const AUDIO_FORMAT* form
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive,
void* user_data)
static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* user_data)
{
AudinALSADevice* alsa = (AudinALSADevice*) device;
AudinALSADevice* alsa = (AudinALSADevice*)device;
if (!device || !receive || !user_data)
return ERROR_INVALID_PARAMETER;
@ -297,8 +292,7 @@ static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive,
goto error_out;
}
if (!(alsa->thread = CreateThread(NULL, 0,
audin_alsa_thread_func, alsa, 0, NULL)))
if (!(alsa->thread = CreateThread(NULL, 0, audin_alsa_thread_func, alsa, 0, NULL)))
{
WLog_Print(alsa->log, WLOG_ERROR, "CreateThread failed!");
goto error_out;
@ -319,7 +313,7 @@ error_out:
static UINT audin_alsa_close(IAudinDevice* device)
{
UINT error = CHANNEL_RC_OK;
AudinALSADevice* alsa = (AudinALSADevice*) device;
AudinALSADevice* alsa = (AudinALSADevice*)device;
if (!alsa)
return ERROR_INVALID_PARAMETER;
@ -331,7 +325,8 @@ static UINT audin_alsa_close(IAudinDevice* device)
if (WaitForSingleObject(alsa->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_Print(alsa->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_Print(alsa->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "",
error);
return error;
}
@ -346,28 +341,24 @@ static UINT audin_alsa_close(IAudinDevice* device)
return error;
}
static COMMAND_LINE_ARGUMENT_A audin_alsa_args[] =
{
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_alsa_parse_addin_args(AudinALSADevice* device,
ADDIN_ARGV* args)
static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* args)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinALSADevice* alsa = (AudinALSADevice*) device;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON |
COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv,
audin_alsa_args, flags, alsa, NULL, NULL);
AudinALSADevice* alsa = (AudinALSADevice*)device;
COMMAND_LINE_ARGUMENT_A audin_alsa_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv, audin_alsa_args, flags, alsa, NULL,
NULL);
if (status < 0)
return ERROR_INVALID_PARAMETER;
@ -379,8 +370,7 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device,
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "dev")
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev")
{
alsa->device_name = _strdup(arg->Value);
@ -391,16 +381,15 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device,
}
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry
#else
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#endif
/**
@ -408,13 +397,12 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device,
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS
pEntryPoints)
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
{
ADDIN_ARGV* args;
AudinALSADevice* alsa;
UINT error;
alsa = (AudinALSADevice*) calloc(1, sizeof(AudinALSADevice));
alsa = (AudinALSADevice*)calloc(1, sizeof(AudinALSADevice));
if (!alsa)
{
@ -433,8 +421,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS
if ((error = audin_alsa_parse_addin_args(alsa, args)))
{
WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_parse_addin_args failed with errorcode %"PRIu32"!",
error);
WLog_Print(alsa->log, WLOG_ERROR,
"audin_alsa_parse_addin_args failed with errorcode %" PRIu32 "!", error);
goto error_out;
}
@ -456,10 +444,10 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS
alsa->aformat.wFormatTag = WAVE_FORMAT_PCM;
alsa->aformat.nSamplesPerSec = 44100;
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin,
(IAudinDevice*) alsa)))
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)alsa)))
{
WLog_Print(alsa->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error);
WLog_Print(alsa->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!",
error);
goto error_out;
}

View File

@ -39,16 +39,22 @@
#include <winpr/stream.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/channels/audin.h>
#include "audin_main.h"
#define MSG_SNDIN_VERSION 0x01
#define MSG_SNDIN_FORMATS 0x02
#define MSG_SNDIN_OPEN 0x03
#define MSG_SNDIN_OPEN_REPLY 0x04
#define MSG_SNDIN_DATA_INCOMING 0x05
#define MSG_SNDIN_DATA 0x06
#define MSG_SNDIN_FORMATCHANGE 0x07
#define SNDIN_VERSION 0x02
enum
{
MSG_SNDIN_VERSION = 0x01,
MSG_SNDIN_FORMATS = 0x02,
MSG_SNDIN_OPEN = 0x03,
MSG_SNDIN_OPEN_REPLY = 0x04,
MSG_SNDIN_DATA_INCOMING = 0x05,
MSG_SNDIN_DATA = 0x06,
MSG_SNDIN_FORMATCHANGE = 0x07
} MSG_SNDIN_CMD;
typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK;
struct _AUDIN_LISTENER_CALLBACK
@ -100,12 +106,17 @@ struct _AUDIN_PLUGIN
FREERDP_DSP_CONTEXT* dsp_context;
wLog* log;
IWTSListener* listener;
BOOL initialized;
UINT32 version;
};
static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args);
static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStream* out,
BOOL freeStream)
BOOL freeStream)
{
UINT error;
@ -116,9 +127,8 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre
return ERROR_INTERNAL_ERROR;
Stream_SealLength(out);
error = callback->channel->Write(callback->channel,
Stream_Length(out),
Stream_Buffer(out), NULL);
error =
callback->channel->Write(callback->channel, Stream_Length(out), Stream_Buffer(out), NULL);
if (freeStream)
Stream_Free(out, TRUE);
@ -126,7 +136,6 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre
return error;
}
/**
* Function description
*
@ -135,24 +144,26 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre
static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s)
{
wStream* out;
const UINT32 ClientVersion = 0x01;
const UINT32 ClientVersion = SNDIN_VERSION;
UINT32 ServerVersion;
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, ServerVersion);
WLog_Print(audin->log, WLOG_DEBUG, "ServerVersion=%"PRIu32", ClientVersion=%"PRIu32, ServerVersion,
ClientVersion);
WLog_Print(audin->log, WLOG_DEBUG, "ServerVersion=%" PRIu32 ", ClientVersion=%" PRIu32,
ServerVersion, ClientVersion);
/* Do not answer server packet, we do not support the channel version. */
if (ServerVersion != ClientVersion)
if (ServerVersion > ClientVersion)
{
WLog_Print(audin->log, WLOG_WARN,
"Incompatible channel version server=%"PRIu32", client supports version=%"PRIu32, ServerVersion,
ClientVersion);
"Incompatible channel version server=%" PRIu32
", client supports version=%" PRIu32,
ServerVersion, ClientVersion);
return CHANNEL_RC_OK;
}
audin->version = ServerVersion;
out = Stream_New(NULL, 5);
@ -199,11 +210,11 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, NumFormats);
WLog_Print(audin->log, WLOG_DEBUG, "NumFormats %"PRIu32"", NumFormats);
WLog_Print(audin->log, WLOG_DEBUG, "NumFormats %" PRIu32 "", NumFormats);
if ((NumFormats < 1) || (NumFormats > 1000))
{
WLog_Print(audin->log, WLOG_ERROR, "bad NumFormats %"PRIu32"", NumFormats);
WLog_Print(audin->log, WLOG_ERROR, "bad NumFormats %" PRIu32 "", NumFormats);
return ERROR_INVALID_DATA;
}
@ -271,11 +282,11 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c
goto out;
}
cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out);
cbSizeFormatsPacket = (UINT32)Stream_GetPosition(out);
Stream_SetPosition(out, 0);
Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */
Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */
Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */
Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
Stream_SetPosition(out, cbSizeFormatsPacket);
error = audin_channel_write_and_free(callback, out, FALSE);
out:
@ -296,7 +307,7 @@ out:
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_send_format_change_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback,
UINT32 NewFormat)
UINT32 NewFormat)
{
wStream* out = Stream_New(NULL, 5);
@ -337,13 +348,13 @@ static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBAC
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_receive_wave_data(const AUDIO_FORMAT* format,
const BYTE* data, size_t size, void* user_data)
static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, const BYTE* data, size_t size,
void* user_data)
{
UINT error;
BOOL compatible;
AUDIN_PLUGIN* audin;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*)user_data;
if (!callback)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
@ -382,7 +393,7 @@ static UINT audin_receive_wave_data(const AUDIO_FORMAT* format,
return CHANNEL_RC_OK;
audio_format_print(audin->log, WLOG_TRACE, audin->format);
WLog_Print(audin->log, WLOG_TRACE, "[%"PRIdz"/%"PRIdz"]", size,
WLog_Print(audin->log, WLOG_TRACE, "[%" PRIdz "/%" PRIdz "]", size,
Stream_GetPosition(audin->data) - 1);
if ((error = audin_send_incoming_data_pdu(callback)))
@ -411,12 +422,7 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb
if (!supported)
{
/* Default sample rates supported by most backends. */
const UINT32 samplerates[] = {
96000,
48000,
44100,
22050
};
const UINT32 samplerates[] = { 96000, 48000, 44100, 22050 };
BOOL test = FALSE;
format.wFormatTag = WAVE_FORMAT_PCM;
@ -425,7 +431,7 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb
if (!test)
{
size_t x;
for (x=0; x<ARRAYSIZE(samplerates); x++)
for (x = 0; x < ARRAYSIZE(samplerates); x++)
{
format.nSamplesPerSec = samplerates[x];
test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format);
@ -437,28 +443,22 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb
return FALSE;
}
IFCALLRET(audin->device->SetFormat, error,
audin->device, &format,
audin->FramesPerPacket);
IFCALLRET(audin->device->SetFormat, error, audin->device, &format, audin->FramesPerPacket);
if (error != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error);
WLog_ERR(TAG, "SetFormat failed with errorcode %" PRIu32 "", error);
return FALSE;
}
if (!supported)
{
if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format))
return FALSE;
}
if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format))
return FALSE;
IFCALLRET(audin->device->Open, error, audin->device,
audin_receive_wave_data, callback);
IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback);
if (error != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error);
WLog_ERR(TAG, "Open failed with errorcode %" PRIu32 "", error);
return FALSE;
}
@ -480,13 +480,13 @@ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* call
Stream_Read_UINT32(s, FramesPerPacket);
Stream_Read_UINT32(s, initialFormat);
WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"",
WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%" PRIu32 " initialFormat=%" PRIu32 "",
FramesPerPacket, initialFormat);
audin->FramesPerPacket = FramesPerPacket;
if (initialFormat >= callback->formats_count)
{
WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)",
WLog_Print(audin->log, WLOG_ERROR, "invalid format index %" PRIu32 " (total %d)",
initialFormat, callback->formats_count);
return ERROR_INVALID_DATA;
}
@ -523,12 +523,12 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, NewFormat);
WLog_Print(audin->log, WLOG_DEBUG, "NewFormat=%"PRIu32"", NewFormat);
WLog_Print(audin->log, WLOG_DEBUG, "NewFormat=%" PRIu32 "", NewFormat);
if (NewFormat >= callback->formats_count)
{
WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)",
NewFormat, callback->formats_count);
WLog_Print(audin->log, WLOG_ERROR, "invalid format index %" PRIu32 " (total %d)", NewFormat,
callback->formats_count);
return ERROR_INVALID_DATA;
}
@ -540,7 +540,7 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB
if (error != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error);
WLog_ERR(TAG, "Close failed with errorcode %" PRIu32 "", error);
return error;
}
}
@ -564,12 +564,12 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
UINT error;
BYTE MessageId;
AUDIN_PLUGIN* audin;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*)pChannelCallback;
if (!callback || !data)
return ERROR_INVALID_PARAMETER;
audin = (AUDIN_PLUGIN*) callback->plugin;
audin = (AUDIN_PLUGIN*)callback->plugin;
if (!audin)
return ERROR_INTERNAL_ERROR;
@ -578,7 +578,7 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
return ERROR_NO_DATA;
Stream_Read_UINT8(data, MessageId);
WLog_Print(audin->log, WLOG_DEBUG, "MessageId=0x%02"PRIx8"", MessageId);
WLog_Print(audin->log, WLOG_DEBUG, "MessageId=0x%02" PRIx8 "", MessageId);
switch (MessageId)
{
@ -599,7 +599,7 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
break;
default:
WLog_Print(audin->log, WLOG_ERROR, "unknown MessageId=0x%02"PRIx8"", MessageId);
WLog_Print(audin->log, WLOG_ERROR, "unknown MessageId=0x%02" PRIx8 "", MessageId);
error = ERROR_INVALID_DATA;
break;
}
@ -614,8 +614,8 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
*/
static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*)pChannelCallback;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)callback->plugin;
UINT error = CHANNEL_RC_OK;
WLog_Print(audin->log, WLOG_TRACE, "...");
@ -624,7 +624,7 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
IFCALLRET(audin->device->Close, error, audin->device);
if (error != CHANNEL_RC_OK)
WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error);
WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %" PRIu32 "", error);
}
audin->format = NULL;
@ -639,19 +639,19 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback)
{
AUDIN_CHANNEL_CALLBACK* callback;
AUDIN_PLUGIN* audin;
AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback;
AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*)pListenerCallback;
if (!listener_callback || !listener_callback->plugin)
return ERROR_INTERNAL_ERROR;
audin = (AUDIN_PLUGIN*) listener_callback->plugin;
audin = (AUDIN_PLUGIN*)listener_callback->plugin;
WLog_Print(audin->log, WLOG_TRACE, "...");
callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK));
callback = (AUDIN_CHANNEL_CALLBACK*)calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK));
if (!callback)
{
@ -664,7 +664,7 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
*ppCallback = (IWTSVirtualChannelCallback*) callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
@ -675,7 +675,8 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb
*/
static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
UINT rc;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin;
if (!audin)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
@ -683,8 +684,14 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag
if (!pChannelMgr)
return ERROR_INVALID_PARAMETER;
if (audin->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AUDIN_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
WLog_Print(audin->log, WLOG_TRACE, "...");
audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) calloc(1, sizeof(AUDIN_LISTENER_CALLBACK));
audin->listener_callback = (AUDIN_LISTENER_CALLBACK*)calloc(1, sizeof(AUDIN_LISTENER_CALLBACK));
if (!audin->listener_callback)
{
@ -695,8 +702,11 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag
audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection;
audin->listener_callback->plugin = pPlugin;
audin->listener_callback->channel_mgr = pChannelMgr;
return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0,
(IWTSListenerCallback*) audin->listener_callback, NULL);
rc = pChannelMgr->CreateListener(pChannelMgr, AUDIN_DVC_CHANNEL_NAME, 0,
&audin->listener_callback->iface, &audin->listener);
audin->initialized = rc == CHANNEL_RC_OK;
return rc;
}
/**
@ -706,14 +716,21 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag
*/
static UINT audin_plugin_terminated(IWTSPlugin* pPlugin)
{
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin;
UINT error = CHANNEL_RC_OK;
if (!audin)
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
WLog_Print(audin->log, WLOG_TRACE, "...");
audio_format_free(audin->fixed_format);
if (audin->listener_callback)
{
IWTSVirtualChannelManager* mgr = audin->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, audin->listener);
}
audio_formats_free(audin->fixed_format, 1);
if (audin->device)
{
@ -721,7 +738,7 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin)
if (error != CHANNEL_RC_OK)
{
WLog_Print(audin->log, WLOG_ERROR, "Free failed with errorcode %"PRIu32"", error);
WLog_Print(audin->log, WLOG_ERROR, "Free failed with errorcode %" PRIu32 "", error);
// dont stop on error
}
@ -739,7 +756,7 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin)
static UINT audin_plugin_attached(IWTSPlugin* pPlugin)
{
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin;
UINT error = CHANNEL_RC_OK;
if (!audin)
@ -751,7 +768,7 @@ static UINT audin_plugin_attached(IWTSPlugin* pPlugin)
static UINT audin_plugin_detached(IWTSPlugin* pPlugin)
{
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin;
UINT error = CHANNEL_RC_OK;
if (!audin)
@ -768,7 +785,7 @@ static UINT audin_plugin_detached(IWTSPlugin* pPlugin)
*/
static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device)
{
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin;
if (audin->device)
{
@ -791,8 +808,8 @@ static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV
PFREERDP_AUDIN_DEVICE_ENTRY entry;
FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
UINT error;
entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL,
0);
entry = (PFREERDP_AUDIN_DEVICE_ENTRY)freerdp_load_channel_addin_entry("audin", (LPSTR)name,
NULL, 0);
if (entry == NULL)
{
@ -802,14 +819,14 @@ static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV
return ERROR_INVALID_FUNCTION;
}
entryPoints.plugin = (IWTSPlugin*) audin;
entryPoints.plugin = (IWTSPlugin*)audin;
entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
entryPoints.args = args;
entryPoints.rdpcontext = audin->rdpcontext;
if ((error = entry(&entryPoints)))
{
WLog_Print(audin->log, WLOG_ERROR, "%s entry returned error %"PRIu32".", name, error);
WLog_Print(audin->log, WLOG_ERROR, "%s entry returned error %" PRIu32 ".", name, error);
return error;
}
@ -855,29 +872,28 @@ static UINT audin_set_device_name(AUDIN_PLUGIN* audin, const char* device_name)
return CHANNEL_RC_OK;
}
static COMMAND_LINE_ARGUMENT_A audin_args[] =
{
{ "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
{ "format", COMMAND_LINE_VALUE_REQUIRED, "<format>", NULL, NULL, -1, NULL, "format" },
{ "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" },
{ "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
UINT error;
COMMAND_LINE_ARGUMENT_A audin_args[] = {
{ "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
{ "format", COMMAND_LINE_VALUE_REQUIRED, "<format>", NULL, NULL, -1, NULL, "format" },
{ "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" },
{ "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
if (!args || args->argc == 1)
return TRUE;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv,
audin_args, flags, audin, NULL, NULL);
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status =
CommandLineParseArgumentsA(args->argc, args->argv, audin_args, flags, audin, NULL, NULL);
if (status != 0)
return FALSE;
@ -890,12 +906,12 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "sys")
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys")
{
if ((error = audin_set_subsystem(audin, arg->Value)))
{
WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem failed with error %"PRIu32"!", error);
WLog_Print(audin->log, WLOG_ERROR,
"audin_set_subsystem failed with error %" PRIu32 "!", error);
return FALSE;
}
}
@ -903,7 +919,8 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
{
if ((error = audin_set_device_name(audin, arg->Value)))
{
WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name failed with error %"PRIu32"!", error);
WLog_Print(audin->log, WLOG_ERROR,
"audin_set_device_name failed with error %" PRIu32 "!", error);
return FALSE;
}
}
@ -936,16 +953,15 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args)
{
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return TRUE;
}
#ifdef BUILTIN_CHANNELS
#define DVCPluginEntry audin_DVCPluginEntry
#define DVCPluginEntry audin_DVCPluginEntry
#else
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#endif
/**
@ -966,34 +982,34 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
struct SubsystemEntry entries[] =
{
#if defined(WITH_PULSE)
{"pulse", ""},
{ "pulse", "" },
#endif
#if defined(WITH_OSS)
{"oss", "default"},
{ "oss", "default" },
#endif
#if defined(WITH_ALSA)
{"alsa", "default"},
{ "alsa", "default" },
#endif
#if defined(WITH_OPENSLES)
{"opensles", "default"},
{ "opensles", "default" },
#endif
#if defined(WITH_WINMM)
{"winmm", "default"},
{ "winmm", "default" },
#endif
#if defined(WITH_MACAUDIO)
{"mac", "default"},
{ "mac", "default" },
#endif
{NULL, NULL}
{ NULL, NULL }
};
struct SubsystemEntry* entry = &entries[0];
assert(pEntryPoints);
assert(pEntryPoints->GetPlugin);
audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin");
audin = (AUDIN_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "audin");
if (audin != NULL)
return CHANNEL_RC_ALREADY_INITIALIZED;
audin = (AUDIN_PLUGIN*) calloc(1, sizeof(AUDIN_PLUGIN));
audin = (AUDIN_PLUGIN*)calloc(1, sizeof(AUDIN_PLUGIN));
if (!audin)
{
@ -1024,8 +1040,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
audin->iface.Attached = audin_plugin_attached;
audin->iface.Detached = audin_plugin_detached;
args = pEntryPoints->GetPluginData(pEntryPoints);
audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(
pEntryPoints))->instance)->context;
audin->rdpcontext =
((freerdp*)((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context;
if (args)
{
@ -1037,8 +1053,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
if ((error = audin_load_device_plugin(audin, audin->subsystem, args)))
{
WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!",
audin->subsystem, error);
WLog_Print(
audin->log, WLOG_ERROR,
"Unable to load microphone redirection subsystem %s because of error %" PRIu32 "",
audin->subsystem, error);
goto out;
}
}
@ -1048,17 +1066,20 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
if ((error = audin_set_subsystem(audin, entry->subsystem)))
{
WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem for %s failed with error %"PRIu32"!",
WLog_Print(audin->log, WLOG_ERROR,
"audin_set_subsystem for %s failed with error %" PRIu32 "!",
entry->subsystem, error);
}
else if ((error = audin_set_device_name(audin, entry->device)))
{
WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name for %s failed with error %"PRIu32"!",
WLog_Print(audin->log, WLOG_ERROR,
"audin_set_device_name for %s failed with error %" PRIu32 "!",
entry->subsystem, error);
}
else if ((error = audin_load_device_plugin(audin, audin->subsystem, args)))
{
WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!",
WLog_Print(audin->log, WLOG_ERROR,
"audin_load_device_plugin %s failed with error %" PRIu32 "!",
entry->subsystem, error);
}
@ -1067,13 +1088,19 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
}
if (audin->device == NULL)
WLog_Print(audin->log, WLOG_ERROR, "no sound device.");
{
/* If we have no audin device do not register plugin but still return OK or the client will
* just disconnect due to a missing microphone. */
WLog_Print(audin->log, WLOG_ERROR, "No microphone device could be found.");
error = CHANNEL_RC_OK;
goto out;
}
error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*)audin);
if (error == CHANNEL_RC_OK)
return error;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin);
out:
if (error != CHANNEL_RC_OK)
audin_plugin_terminated((IWTSPlugin*)audin);
audin_plugin_terminated((IWTSPlugin*)audin);
return error;
}

View File

@ -33,4 +33,3 @@
#define TAG CHANNELS_TAG("audin.client")
#endif /* FREERDP_CHANNEL_AUDIN_CLIENT_MAIN_H */

View File

@ -18,17 +18,18 @@
define_channel_client_subsystem("audin" "mac" "")
FIND_LIBRARY(CORE_AUDIO CoreAudio)
FIND_LIBRARY(AVFOUNDATION AVFoundation)
FIND_LIBRARY(AUDIO_TOOL AudioToolbox)
FIND_LIBRARY(APP_SERVICES ApplicationServices)
set(${MODULE_PREFIX}_SRCS
audin_mac.c)
audin_mac.m)
include_directories(..)
include_directories(${MAC_INCLUDE_DIRS})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set(${MODULE_PREFIX}_LIBS freerdp ${CORE_AUDIO} ${AUDIO_TOOL} ${APP_SERVICES} winpr)
set(${MODULE_PREFIX}_LIBS freerdp ${AVFOUNDATION} ${CORE_AUDIO} ${AUDIO_TOOL} ${APP_SERVICES} winpr)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -33,8 +33,14 @@
#include <winpr/debug.h>
#include <winpr/cmdline.h>
#import <AVFoundation/AVFoundation.h>
#define __COREFOUNDATION_CFPLUGINCOM__ 1
#define IUNKNOWN_C_GUTS void *_reserved; void* QueryInterface; void* AddRef; void* Release
#define IUNKNOWN_C_GUTS \
void *_reserved; \
void *QueryInterface; \
void *AddRef; \
void *Release
#include <CoreAudio/CoreAudioTypes.h>
#include <CoreAudio/CoreAudio.h>
@ -46,7 +52,7 @@
#include "audin_main.h"
#define MAC_AUDIO_QUEUE_NUM_BUFFERS 100
#define MAC_AUDIO_QUEUE_NUM_BUFFERS 100
/* Fix for #4462: Provide type alias if not declared (Mac OS < 10.10)
* https://developer.apple.com/documentation/coreaudio/audioformatid
@ -68,17 +74,18 @@ typedef struct _AudinMacDevice
int dev_unit;
AudinReceive receive;
void* user_data;
void *user_data;
rdpContext* rdpcontext;
rdpContext *rdpcontext;
bool isAuthorized;
bool isOpen;
AudioQueueRef audioQueue;
AudioStreamBasicDescription audioFormat;
AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS];
} AudinMacDevice;
static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format)
static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT *format)
{
switch (format->wFormatTag)
{
@ -90,7 +97,7 @@ static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format)
}
}
static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* format)
static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT *format)
{
switch (format->wFormatTag)
{
@ -102,10 +109,14 @@ static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* forma
}
}
static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
static BOOL audin_mac_format_supported(IAudinDevice *device, const AUDIO_FORMAT *format)
{
AudinMacDevice *mac = (AudinMacDevice *)device;
AudioFormatID req_fmt = 0;
if (!mac->isAuthorized)
return FALSE;
if (device == NULL || format == NULL)
return FALSE;
@ -122,10 +133,13 @@ static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT*
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* format,
static UINT audin_mac_set_format(IAudinDevice *device, const AUDIO_FORMAT *format,
UINT32 FramesPerPacket)
{
AudinMacDevice* mac = (AudinMacDevice*)device;
AudinMacDevice *mac = (AudinMacDevice *)device;
if (!mac->isAuthorized)
return ERROR_INTERNAL_ERROR;
if (device == NULL || format == NULL)
return ERROR_INVALID_PARAMETER;
@ -133,34 +147,35 @@ static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* forma
mac->FramesPerPacket = FramesPerPacket;
mac->format = *format;
WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]",
audio_format_get_tag_string(format->wFormatTag),
format->nChannels, format->nSamplesPerSec, format->wBitsPerSample);
audio_format_get_tag_string(format->wFormatTag), format->nChannels,
format->nSamplesPerSec, format->wBitsPerSample);
mac->audioFormat.mBitsPerChannel = format->wBitsPerSample;
if (format->wBitsPerSample == 0)
mac->audioFormat.mBitsPerChannel = 16;
mac->audioFormat.mBytesPerFrame = 0;
mac->audioFormat.mBytesPerPacket = 0;
mac->audioFormat.mChannelsPerFrame = mac->format.nChannels;
mac->audioFormat.mFramesPerPacket = 1;
mac->audioFormat.mBytesPerFrame =
mac->audioFormat.mChannelsPerFrame * (mac->audioFormat.mBitsPerChannel / 8);
mac->audioFormat.mBytesPerPacket =
mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket;
mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format);
mac->audioFormat.mFormatID = audin_mac_get_format(format);
mac->audioFormat.mFramesPerPacket = 1;
mac->audioFormat.mReserved = 0;
mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec;
return CHANNEL_RC_OK;
}
static void mac_audio_queue_input_cb(void* aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp* inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription* inPacketDesc)
static void mac_audio_queue_input_cb(void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime, UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc)
{
AudinMacDevice* mac = (AudinMacDevice*)aqData;
AudinMacDevice *mac = (AudinMacDevice *)aqData;
UINT error = CHANNEL_RC_OK;
const BYTE* buffer = inBuffer->mAudioData;
const BYTE *buffer = inBuffer->mAudioData;
int buffer_size = inBuffer->mAudioDataByteSize;
(void)inAQ;
(void)inStartTime;
@ -174,17 +189,20 @@ static void mac_audio_queue_input_cb(void* aqData,
if (error)
{
WLog_ERR(TAG, "mac->receive failed with error %"PRIu32"", error);
WLog_ERR(TAG, "mac->receive failed with error %" PRIu32 "", error);
SetLastError(ERROR_INTERNAL_ERROR);
}
}
static UINT audin_mac_close(IAudinDevice* device)
static UINT audin_mac_close(IAudinDevice *device)
{
UINT errCode = CHANNEL_RC_OK;
char errString[1024];
OSStatus devStat;
AudinMacDevice* mac = (AudinMacDevice*)device;
AudinMacDevice *mac = (AudinMacDevice *)device;
if (!mac->isAuthorized)
return ERROR_INTERNAL_ERROR;
if (device == NULL)
return ERROR_INVALID_PARAMETER;
@ -196,7 +214,7 @@ static UINT audin_mac_close(IAudinDevice* device)
if (devStat != 0)
{
errCode = GetLastError();
WLog_ERR(TAG, "AudioQueueStop failed with %s [%"PRIu32"]",
WLog_ERR(TAG, "AudioQueueStop failed with %s [%" PRIu32 "]",
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
}
@ -210,7 +228,7 @@ static UINT audin_mac_close(IAudinDevice* device)
if (devStat != 0)
{
errCode = GetLastError();
WLog_ERR(TAG, "AudioQueueDispose failed with %s [%"PRIu32"]",
WLog_ERR(TAG, "AudioQueueDispose failed with %s [%" PRIu32 "]",
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
}
@ -222,22 +240,26 @@ static UINT audin_mac_close(IAudinDevice* device)
return errCode;
}
static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* user_data)
static UINT audin_mac_open(IAudinDevice *device, AudinReceive receive, void *user_data)
{
AudinMacDevice* mac = (AudinMacDevice*)device;
AudinMacDevice *mac = (AudinMacDevice *)device;
DWORD errCode;
char errString[1024];
OSStatus devStat;
size_t index;
if (!mac->isAuthorized)
return ERROR_INTERNAL_ERROR;
mac->receive = receive;
mac->user_data = user_data;
devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb,
mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue));
devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, mac, NULL,
kCFRunLoopCommonModes, 0, &(mac->audioQueue));
if (devStat != 0)
{
errCode = GetLastError();
WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%"PRIu32"]",
WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%" PRIu32 "]",
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
goto err_out;
}
@ -251,20 +273,17 @@ static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* use
if (devStat != 0)
{
errCode = GetLastError();
WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%"PRIu32"]",
WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%" PRIu32 "]",
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
goto err_out;
}
devStat = AudioQueueEnqueueBuffer(mac->audioQueue,
mac->audioBuffers[index],
0,
NULL);
devStat = AudioQueueEnqueueBuffer(mac->audioQueue, mac->audioBuffers[index], 0, NULL);
if (devStat != 0)
{
errCode = GetLastError();
WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%"PRIu32"]",
WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%" PRIu32 "]",
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
goto err_out;
}
@ -275,7 +294,7 @@ static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* use
if (devStat != 0)
{
errCode = GetLastError();
WLog_ERR(TAG, "AudioQueueStart failed with %s [%"PRIu32"]",
WLog_ERR(TAG, "AudioQueueStart failed with %s [%" PRIu32 "]",
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
goto err_out;
}
@ -287,9 +306,9 @@ err_out:
return CHANNEL_RC_INITIALIZATION_ERROR;
}
static UINT audin_mac_free(IAudinDevice* device)
static UINT audin_mac_free(IAudinDevice *device)
{
AudinMacDevice* mac = (AudinMacDevice*)device;
AudinMacDevice *mac = (AudinMacDevice *)device;
int error;
if (device == NULL)
@ -304,28 +323,27 @@ static UINT audin_mac_free(IAudinDevice* device)
return CHANNEL_RC_OK;
}
static COMMAND_LINE_ARGUMENT_A audin_mac_args[] =
{
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args)
static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args)
{
DWORD errCode;
char errString[1024];
int status;
char* str_num, *eptr;
char *str_num, *eptr;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinMacDevice* mac = (AudinMacDevice*)device;
COMMAND_LINE_ARGUMENT_A *arg;
COMMAND_LINE_ARGUMENT_A audin_mac_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
AudinMacDevice *mac = (AudinMacDevice *)device;
if (args->argc == 1)
return CHANNEL_RC_OK;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv, audin_mac_args, flags,
mac, NULL, NULL);
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status =
CommandLineParseArgumentsA(args->argc, args->argv, audin_mac_args, flags, mac, NULL, NULL);
if (status < 0)
return ERROR_INVALID_PARAMETER;
@ -337,8 +355,7 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args)
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "dev")
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev")
{
str_num = _strdup(arg->Value);
@ -358,31 +375,30 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args)
free(str_num);
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry
#else
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#endif
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
{
DWORD errCode;
char errString[1024];
ADDIN_ARGV* args;
AudinMacDevice* mac;
ADDIN_ARGV *args;
AudinMacDevice *mac;
UINT error;
mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice));
mac = (AudinMacDevice *)calloc(1, sizeof(AudinMacDevice));
if (!mac)
{
errCode = GetLastError();
WLog_ERR(TAG, "calloc failed with %s [%"PRIu32"]",
WLog_ERR(TAG, "calloc failed with %s [%" PRIu32 "]",
winpr_strerror(errCode, errString, sizeof(errString)), errCode);
return CHANNEL_RC_NO_MEMORY;
}
@ -398,16 +414,51 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
if ((error = audin_mac_parse_addin_args(mac, args)))
{
WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %"PRIu32"!", error);
WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %" PRIu32 "!", error);
goto error_out;
}
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac)))
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice *)mac)))
{
WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "RegisterAudinDevice failed with error %" PRIu32 "!", error);
goto error_out;
}
#if defined(MAC_OS_X_VERSION_10_14)
if (@available(macOS 10.14, *))
{
@autoreleasepool {
AVAuthorizationStatus status =
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
switch (status)
{
case AVAuthorizationStatusAuthorized:
mac->isAuthorized = TRUE;
break;
case AVAuthorizationStatusNotDetermined:
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio
completionHandler:^(BOOL granted) {
if (granted == YES)
{
mac->isAuthorized = TRUE;
}
else
WLog_WARN(TAG, "Microphone access denied by user");
}];
break;
case AVAuthorizationStatusRestricted:
WLog_WARN(TAG, "Microphone access restricted by policy");
break;
case AVAuthorizationStatusDenied:
WLog_WARN(TAG, "Microphone access denied by policy");
break;
default:
break;
}
}
}
#endif
return CHANNEL_RC_OK;
error_out:
free(mac);

View File

@ -65,7 +65,7 @@ static UINT audin_opensles_close(IAudinDevice* device);
static void audin_receive(void* context, const void* data, size_t size)
{
UINT error;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) context;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)context;
if (!opensles || !data)
{
@ -86,34 +86,32 @@ static void audin_receive(void* context, const void* data, size_t size)
*/
static UINT audin_opensles_free(IAudinDevice* device)
{
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
if (!opensles)
return ERROR_INVALID_PARAMETER;
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device);
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*)device);
free(opensles->device_name);
free(opensles);
return CHANNEL_RC_OK;
}
static BOOL audin_opensles_format_supported(IAudinDevice* device,
const AUDIO_FORMAT* format)
static BOOL audin_opensles_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
{
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
if (!opensles || !format)
return FALSE;
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p", (void*) opensles, (void*) format);
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p", (void*)opensles, (void*)format);
assert(format);
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM: /* PCM */
if (format->cbSize == 0 &&
(format->nSamplesPerSec <= 48000) &&
if (format->cbSize == 0 && (format->nSamplesPerSec <= 48000) &&
(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
(format->nChannels >= 1 && format->nChannels <= 2))
{
@ -123,9 +121,8 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device,
break;
default:
WLog_Print(opensles->log, WLOG_DEBUG, "Encoding '%s' [0x%04X"PRIX16"] not supported",
audio_format_get_tag_string(format->wFormatTag),
format->wFormatTag);
WLog_Print(opensles->log, WLOG_DEBUG, "Encoding '%s' [0x%04X" PRIX16 "] not supported",
audio_format_get_tag_string(format->wFormatTag), format->wFormatTag);
break;
}
@ -137,16 +134,16 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_opensles_set_format(IAudinDevice* device,
const AUDIO_FORMAT* format, UINT32 FramesPerPacket)
static UINT audin_opensles_set_format(IAudinDevice* device, const AUDIO_FORMAT* format,
UINT32 FramesPerPacket)
{
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
if (!opensles || !format)
return ERROR_INVALID_PARAMETER;
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p, FramesPerPacket=%"PRIu32"",
(void*) device, (void*) format, FramesPerPacket);
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p, FramesPerPacket=%" PRIu32 "",
(void*)device, (void*)format, FramesPerPacket);
assert(format);
opensles->format = *format;
@ -177,13 +174,13 @@ static UINT audin_opensles_set_format(IAudinDevice* device,
break;
default:
WLog_Print(opensles->log, WLOG_ERROR, "Encoding '%"PRIu16"' [%04"PRIX16"] not supported",
format->wFormatTag,
WLog_Print(opensles->log, WLOG_ERROR,
"Encoding '%" PRIu16 "' [%04" PRIX16 "] not supported", format->wFormatTag,
format->wFormatTag);
return ERROR_UNSUPPORTED_TYPE;
}
WLog_Print(opensles->log, WLOG_DEBUG, "frames_per_packet=%"PRIu32,
WLog_Print(opensles->log, WLOG_DEBUG, "frames_per_packet=%" PRIu32,
opensles->frames_per_packet);
return CHANNEL_RC_OK;
}
@ -193,27 +190,22 @@ static UINT audin_opensles_set_format(IAudinDevice* device,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive,
void* user_data)
static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, void* user_data)
{
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
if (!opensles || !receive || !user_data)
return ERROR_INVALID_PARAMETER;
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, receive=%p, user_data=%p", (void*) device,
(void*) receive,
(void*) user_data);
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, receive=%p, user_data=%p", (void*)device,
(void*)receive, (void*)user_data);
if (opensles->stream)
goto error_out;
if (!(opensles->stream = android_OpenRecDevice(
opensles, audin_receive,
opensles->format.nSamplesPerSec,
opensles->format.nChannels,
opensles->frames_per_packet,
opensles->format.wBitsPerSample)))
opensles, audin_receive, opensles->format.nSamplesPerSec, opensles->format.nChannels,
opensles->frames_per_packet, opensles->format.wBitsPerSample)))
{
WLog_Print(opensles->log, WLOG_ERROR, "android_OpenRecDevice failed!");
goto error_out;
@ -223,7 +215,7 @@ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive,
opensles->user_data = user_data;
return CHANNEL_RC_OK;
error_out:
audin_opensles_close(opensles);
audin_opensles_close(device);
return ERROR_INTERNAL_ERROR;
}
@ -234,12 +226,12 @@ error_out:
*/
UINT audin_opensles_close(IAudinDevice* device)
{
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
if (!opensles)
return ERROR_INVALID_PARAMETER;
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device);
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*)device);
android_CloseRecDevice(opensles->stream);
opensles->receive = NULL;
opensles->user_data = NULL;
@ -247,31 +239,28 @@ UINT audin_opensles_close(IAudinDevice* device)
return CHANNEL_RC_OK;
}
static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] =
{
{
"dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
NULL, NULL, -1, NULL, "audio device name"
},
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
ADDIN_ARGV* args)
static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, ADDIN_ARGV* args)
{
UINT status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, args=%p", (void*) device, (void*) args);
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv,
audin_opensles_args, flags, opensles, NULL, NULL);
const COMMAND_LINE_ARGUMENT_A* arg;
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device;
COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = {
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL,
"audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, args=%p", (void*)device, (void*)args);
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv, audin_opensles_args, flags,
opensles, NULL, NULL);
if (status < 0)
return status;
@ -283,8 +272,7 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "dev")
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev")
{
opensles->device_name = _strdup(arg->Value);
@ -295,18 +283,15 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
}
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define freerdp_audin_client_subsystem_entry \
opensles_freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry opensles_freerdp_audin_client_subsystem_entry
#else
#define freerdp_audin_client_subsystem_entry \
FREERDP_API freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#endif
/**
@ -314,13 +299,12 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT freerdp_audin_client_subsystem_entry(
PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
{
ADDIN_ARGV* args;
AudinOpenSLESDevice* opensles;
UINT error;
opensles = (AudinOpenSLESDevice*) calloc(1, sizeof(AudinOpenSLESDevice));
opensles = (AudinOpenSLESDevice*)calloc(1, sizeof(AudinOpenSLESDevice));
if (!opensles)
{
@ -340,13 +324,14 @@ UINT freerdp_audin_client_subsystem_entry(
if ((error = audin_opensles_parse_addin_args(opensles, args)))
{
WLog_Print(opensles->log, WLOG_ERROR,
"audin_opensles_parse_addin_args failed with errorcode %"PRIu32"!", error);
"audin_opensles_parse_addin_args failed with errorcode %" PRIu32 "!", error);
goto error_out;
}
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) opensles)))
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)opensles)))
{
WLog_Print(opensles->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error);
WLog_Print(opensles->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!",
error);
goto error_out;
}

View File

@ -6,14 +6,14 @@ All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "audin_main.h"
#include "opensl_io.h"
#define CONV16BIT 32768
#define CONVMYFLT (1./32768.)
#define CONVMYFLT (1. / 32768.)
typedef struct
{
@ -66,7 +66,6 @@ struct opensl_stream
opensl_receive_t receive;
};
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context);
// creates the OpenSL ES audio engine
@ -76,22 +75,24 @@ static SLresult openSLCreateEngine(OPENSL_STREAM* p)
// create engine
result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) goto engine_end;
if (result != SL_RESULT_SUCCESS)
goto engine_end;
// realize the engine
result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) goto engine_end;
if (result != SL_RESULT_SUCCESS)
goto engine_end;
// get the engine interface, which is needed in order to create other objects
result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE,
&(p->engineEngine));
result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine));
if (result != SL_RESULT_SUCCESS) goto engine_end;
if (result != SL_RESULT_SUCCESS)
goto engine_end;
// get the volume interface - important, this is optional!
result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_DEVICEVOLUME,
&(p->deviceVolume));
result =
(*p->engineObject)->GetInterface(p->engineObject, SL_IID_DEVICEVOLUME, &(p->deviceVolume));
if (result != SL_RESULT_SUCCESS)
{
@ -169,10 +170,9 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p)
}
// configure audio source
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT, NULL
};
SLDataSource audioSrc = {&loc_dev, NULL};
SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
SLDataSource audioSrc = { &loc_dev, NULL };
// configure audio sink
int speakers;
@ -181,7 +181,8 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p)
else
speakers = SL_SPEAKER_FRONT_CENTER;
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
2 };
SLDataFormat_PCM format_pcm;
format_pcm.formatType = SL_DATAFORMAT_PCM;
format_pcm.numChannels = channels;
@ -202,41 +203,46 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p)
else
assert(0);
SLDataSink audioSnk = {&loc_bq, &format_pcm};
SLDataSink audioSnk = { &loc_bq, &format_pcm };
// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[] = {SL_BOOLEAN_TRUE};
result = (*p->engineEngine)->CreateAudioRecorder(p->engineEngine,
&(p->recorderObject), &audioSrc, &audioSnk, 1, id, req);
const SLInterfaceID id[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean req[] = { SL_BOOLEAN_TRUE };
result = (*p->engineEngine)
->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc,
&audioSnk, 1, id, req);
assert(!result);
if (SL_RESULT_SUCCESS != result) goto end_recopen;
if (SL_RESULT_SUCCESS != result)
goto end_recopen;
// realize the audio recorder
result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE);
assert(!result);
if (SL_RESULT_SUCCESS != result) goto end_recopen;
if (SL_RESULT_SUCCESS != result)
goto end_recopen;
// get the record interface
result = (*p->recorderObject)->GetInterface(p->recorderObject,
SL_IID_RECORD, &(p->recorderRecord));
result = (*p->recorderObject)
->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord));
assert(!result);
if (SL_RESULT_SUCCESS != result) goto end_recopen;
if (SL_RESULT_SUCCESS != result)
goto end_recopen;
// get the buffer queue interface
result = (*p->recorderObject)->GetInterface(p->recorderObject,
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&(p->recorderBufferQueue));
result = (*p->recorderObject)
->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&(p->recorderBufferQueue));
assert(!result);
if (SL_RESULT_SUCCESS != result) goto end_recopen;
if (SL_RESULT_SUCCESS != result)
goto end_recopen;
// register callback on the buffer queue
result = (*p->recorderBufferQueue)->RegisterCallback(p->recorderBufferQueue,
bqRecorderCallback, p);
result = (*p->recorderBufferQueue)
->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback, p);
assert(!result);
if (SL_RESULT_SUCCESS != result)
@ -245,7 +251,8 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p)
end_recopen:
return result;
}
else return SL_RESULT_SUCCESS;
else
return SL_RESULT_SUCCESS;
}
// close the OpenSL IO and destroy the audio engine
@ -299,17 +306,15 @@ static void opensles_queue_element_free(void* obj)
}
// open the android audio device for input
OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive,
int sr,
int inchannels,
int bufferframes, int bits_per_sample)
OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, int sr,
int inchannels, int bufferframes, int bits_per_sample)
{
OPENSL_STREAM* p;
if (!context || !receive)
return NULL;
p = (OPENSL_STREAM*) calloc(1, sizeof(OPENSL_STREAM));
p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
if (!p)
return NULL;
@ -337,12 +342,9 @@ OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive,
if (!p->prep || !p->next)
goto fail;
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
p->next->data, p->next->size);
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
p->prep->data, p->prep->size);
(*p->recorderRecord)->SetRecordState(p->recorderRecord,
SL_RECORDSTATE_RECORDING);
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->next->data, p->next->size);
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->prep->data, p->prep->size);
(*p->recorderRecord)->SetRecordState(p->recorderRecord, SL_RECORDSTATE_RECORDING);
return p;
fail:
android_CloseRecDevice(p);
@ -364,7 +366,7 @@ void android_CloseRecDevice(OPENSL_STREAM* p)
// this callback handler is called every time a buffer finishes recording
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
{
OPENSL_STREAM* p = (OPENSL_STREAM*) context;
OPENSL_STREAM* p = (OPENSL_STREAM*)context;
queue_element* e;
if (!p)
@ -382,7 +384,5 @@ static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
p->next = p->prep;
p->prep = e;
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
e->data, e->size);
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, e->data, e->size);
}

View File

@ -6,14 +6,14 @@ All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@ -38,25 +38,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
typedef struct opensl_stream OPENSL_STREAM;
typedef struct opensl_stream OPENSL_STREAM;
typedef void (*opensl_receive_t)(void* context, const void* data, size_t size);
typedef void (*opensl_receive_t)(void* context, const void* data, size_t size);
/*
Open the audio device with a given sampling rate (sr), input and output channels and IO buffer size
in frames. Returns a handle to the OpenSL stream
*/
FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(void* context,
opensl_receive_t receive, int sr,
int inchannels,
int bufferframes, int bits_per_sample);
/*
Close the audio device
*/
FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p);
/*
Open the audio device with a given sampling rate (sr), input and output channels and IO buffer
size in frames. Returns a handle to the OpenSL stream
*/
FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive,
int sr, int inchannels, int bufferframes,
int bits_per_sample);
/*
Close the audio device
*/
FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p);
#ifdef __cplusplus
};

View File

@ -69,11 +69,10 @@ typedef struct _AudinOSSDevice
} AudinOSSDevice;
#define OSS_LOG_ERR(_text, _error) \
if (_error != 0) \
if (_error != 0) \
WLog_ERR(TAG, "%s: %i - %s\n", _text, _error, strerror(_error));
static int audin_oss_get_format(const AUDIO_FORMAT* format)
static UINT32 audin_oss_get_format(const AUDIO_FORMAT* format)
{
switch (format->wFormatTag)
{
@ -99,8 +98,7 @@ static int audin_oss_get_format(const AUDIO_FORMAT* format)
return 0;
}
static BOOL audin_oss_format_supported(IAudinDevice* device,
const AUDIO_FORMAT* format)
static BOOL audin_oss_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
{
if (device == NULL || format == NULL)
return FALSE;
@ -108,18 +106,13 @@ static BOOL audin_oss_format_supported(IAudinDevice* device,
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM:
if (format->cbSize != 0 ||
format->nSamplesPerSec > 48000 ||
if (format->cbSize != 0 || format->nSamplesPerSec > 48000 ||
(format->wBitsPerSample != 8 && format->wBitsPerSample != 16) ||
(format->nChannels != 1 && format->nChannels != 2))
return FALSE;
break;
case WAVE_FORMAT_ALAW:
case WAVE_FORMAT_MULAW:
return TRUE;
default:
return FALSE;
}
@ -151,7 +144,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg)
char mixer_name[PATH_MAX] = "/dev/mixer";
int pcm_handle = -1, mixer_handle;
BYTE* buffer = NULL;
int tmp;
unsigned long tmp;
size_t buffer_size;
AudinOSSDevice* oss = (AudinOSSDevice*)arg;
UINT error = 0;
@ -233,8 +226,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg)
if (ioctl(pcm_handle, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1)
OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno);
buffer_size = (oss->FramesPerPacket * oss->format.nChannels *
(oss->format.wBitsPerSample / 8));
buffer_size = (oss->FramesPerPacket * oss->format.nChannels * (oss->format.wBitsPerSample / 8));
buffer = (BYTE*)calloc((buffer_size + sizeof(void*)), sizeof(BYTE));
if (NULL == buffer)
@ -246,33 +238,34 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg)
while (1)
{
SSIZE_T stmp;
status = WaitForSingleObject(oss->stopEvent, 0);
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
goto err_out;
}
if (status == WAIT_OBJECT_0)
break;
tmp = read(pcm_handle, buffer, buffer_size);
stmp = read(pcm_handle, buffer, buffer_size);
/* Error happen. */
if (tmp < 0)
if (stmp < 0)
{
OSS_LOG_ERR("read() error", errno);
continue;
}
if (tmp < buffer_size) /* Not enouth data. */
if ((size_t)stmp < buffer_size) /* Not enouth data. */
continue;
if ((error = oss->receive(&oss->format, buffer, buffer_size, oss->user_data)))
{
WLog_ERR(TAG, "oss->receive failed with error %"PRIu32"", error);
WLog_ERR(TAG, "oss->receive failed with error %" PRIu32 "", error);
break;
}
}
@ -280,8 +273,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg)
err_out:
if (error && oss && oss->rdpcontext)
setChannelError(oss->rdpcontext, error,
"audin_oss_thread_func reported an error");
setChannelError(oss->rdpcontext, error, "audin_oss_thread_func reported an error");
if (pcm_handle != -1)
{
@ -299,8 +291,7 @@ err_out:
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_oss_open(IAudinDevice* device, AudinReceive receive,
void* user_data)
static UINT audin_oss_open(IAudinDevice* device, AudinReceive receive, void* user_data)
{
AudinOSSDevice* oss = (AudinOSSDevice*)device;
oss->receive = receive;
@ -343,7 +334,7 @@ static UINT audin_oss_close(IAudinDevice* device)
if (WaitForSingleObject(oss->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
@ -366,7 +357,7 @@ static UINT audin_oss_close(IAudinDevice* device)
static UINT audin_oss_free(IAudinDevice* device)
{
AudinOSSDevice* oss = (AudinOSSDevice*)device;
int error;
UINT error;
if (device == NULL)
return ERROR_INVALID_PARAMETER;
@ -380,12 +371,6 @@ static UINT audin_oss_free(IAudinDevice* device)
return CHANNEL_RC_OK;
}
static COMMAND_LINE_ARGUMENT_A audin_oss_args[] =
{
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
/**
* Function description
*
@ -394,14 +379,18 @@ static COMMAND_LINE_ARGUMENT_A audin_oss_args[] =
static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args)
{
int status;
char* str_num, *eptr;
char *str_num, *eptr;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinOSSDevice* oss = (AudinOSSDevice*)device;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON |
COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv,
audin_oss_args, flags, oss, NULL, NULL);
COMMAND_LINE_ARGUMENT_A audin_oss_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status =
CommandLineParseArgumentsA(args->argc, args->argv, audin_oss_args, flags, oss, NULL, NULL);
if (status < 0)
return ERROR_INVALID_PARAMETER;
@ -414,8 +403,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args)
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "dev")
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev")
{
str_num = _strdup(arg->Value);
@ -434,7 +422,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args)
return CHANNEL_RC_NULL_DATA;
}
oss->dev_unit = val;
oss->dev_unit = (INT32)val;
}
if (oss->dev_unit < 0 || *eptr != '\0')
@ -443,16 +431,15 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args)
free(str_num);
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define freerdp_audin_client_subsystem_entry oss_freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry oss_freerdp_audin_client_subsystem_entry
#else
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#endif
/**
@ -460,8 +447,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args)
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS
pEntryPoints)
UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
{
ADDIN_ARGV* args;
AudinOSSDevice* oss;
@ -485,14 +471,13 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS
if ((error = audin_oss_parse_addin_args(oss, args)))
{
WLog_ERR(TAG, "audin_oss_parse_addin_args failed with errorcode %"PRIu32"!", error);
WLog_ERR(TAG, "audin_oss_parse_addin_args failed with errorcode %" PRIu32 "!", error);
goto error_out;
}
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin,
(IAudinDevice*) oss)))
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)oss)))
{
WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "RegisterAudinDevice failed with error %" PRIu32 "!", error);
goto error_out;
}

View File

@ -62,27 +62,67 @@ typedef struct _AudinPulseDevice
wLog* log;
} AudinPulseDevice;
static const char* pulse_context_state_string(pa_context_state_t state)
{
switch (state)
{
case PA_CONTEXT_UNCONNECTED:
return "PA_CONTEXT_UNCONNECTED";
case PA_CONTEXT_CONNECTING:
return "PA_CONTEXT_CONNECTING";
case PA_CONTEXT_AUTHORIZING:
return "PA_CONTEXT_AUTHORIZING";
case PA_CONTEXT_SETTING_NAME:
return "PA_CONTEXT_SETTING_NAME";
case PA_CONTEXT_READY:
return "PA_CONTEXT_READY";
case PA_CONTEXT_FAILED:
return "PA_CONTEXT_FAILED";
case PA_CONTEXT_TERMINATED:
return "PA_CONTEXT_TERMINATED";
default:
return "UNKNOWN";
}
}
static const char* pulse_stream_state_string(pa_stream_state_t state)
{
switch (state)
{
case PA_STREAM_UNCONNECTED:
return "PA_STREAM_UNCONNECTED";
case PA_STREAM_CREATING:
return "PA_STREAM_CREATING";
case PA_STREAM_READY:
return "PA_STREAM_READY";
case PA_STREAM_FAILED:
return "PA_STREAM_FAILED";
case PA_STREAM_TERMINATED:
return "PA_STREAM_TERMINATED";
default:
return "UNKNOWN";
}
}
static void audin_pulse_context_state_callback(pa_context* context, void* userdata)
{
pa_context_state_t state;
AudinPulseDevice* pulse = (AudinPulseDevice*) userdata;
AudinPulseDevice* pulse = (AudinPulseDevice*)userdata;
state = pa_context_get_state(context);
WLog_Print(pulse->log, WLOG_DEBUG, "context state %s", pulse_context_state_string(state));
switch (state)
{
case PA_CONTEXT_READY:
WLog_Print(pulse->log, WLOG_DEBUG, "PA_CONTEXT_READY");
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state);
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
default:
WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state);
break;
}
}
@ -95,7 +135,7 @@ static void audin_pulse_context_state_callback(pa_context* context, void* userda
static UINT audin_pulse_connect(IAudinDevice* device)
{
pa_context_state_t state;
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
AudinPulseDevice* pulse = (AudinPulseDevice*)device;
if (!pulse->context)
return ERROR_INVALID_PARAMETER;
@ -126,8 +166,8 @@ static UINT audin_pulse_connect(IAudinDevice* device)
if (!PA_CONTEXT_IS_GOOD(state))
{
WLog_Print(pulse->log, WLOG_ERROR, "bad context state (%d)",
pa_context_errno(pulse->context));
WLog_Print(pulse->log, WLOG_ERROR, "bad context state (%s: %d)",
pulse_context_state_string(state), pa_context_errno(pulse->context));
pa_context_disconnect(pulse->context);
return ERROR_INVALID_STATE;
}
@ -136,7 +176,7 @@ static UINT audin_pulse_connect(IAudinDevice* device)
}
pa_threaded_mainloop_unlock(pulse->mainloop);
WLog_Print(pulse->log, WLOG_DEBUG, "connected");
WLog_Print(pulse->log, WLOG_DEBUG, "connected");
return CHANNEL_RC_OK;
}
@ -147,7 +187,7 @@ static UINT audin_pulse_connect(IAudinDevice* device)
*/
static UINT audin_pulse_free(IAudinDevice* device)
{
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
AudinPulseDevice* pulse = (AudinPulseDevice*)device;
if (!pulse)
return ERROR_INVALID_PARAMETER;
@ -176,7 +216,7 @@ static UINT audin_pulse_free(IAudinDevice* device)
static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
{
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
AudinPulseDevice* pulse = (AudinPulseDevice*)device;
if (!pulse || !format)
return FALSE;
@ -187,8 +227,7 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMA
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM:
if (format->cbSize == 0 &&
(format->nSamplesPerSec <= PA_RATE_MAX) &&
if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) &&
(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
(format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
{
@ -197,18 +236,6 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMA
break;
case WAVE_FORMAT_ALAW: /* A-LAW */
case WAVE_FORMAT_MULAW: /* U-LAW */
if (format->cbSize == 0 &&
(format->nSamplesPerSec <= PA_RATE_MAX) &&
(format->wBitsPerSample == 8) &&
(format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
{
return TRUE;
}
break;
default:
return FALSE;
}
@ -225,7 +252,7 @@ static UINT audin_pulse_set_format(IAudinDevice* device, const AUDIO_FORMAT* for
UINT32 FramesPerPacket)
{
pa_sample_spec sample_spec = { 0 };
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
AudinPulseDevice* pulse = (AudinPulseDevice*)device;
if (!pulse || !format)
return ERROR_INVALID_PARAMETER;
@ -278,24 +305,22 @@ static UINT audin_pulse_set_format(IAudinDevice* device, const AUDIO_FORMAT* for
static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata)
{
pa_stream_state_t state;
AudinPulseDevice* pulse = (AudinPulseDevice*) userdata;
AudinPulseDevice* pulse = (AudinPulseDevice*)userdata;
state = pa_stream_get_state(stream);
WLog_Print(pulse->log, WLOG_DEBUG, "stream state %s", pulse_stream_state_string(state));
switch (state)
{
case PA_STREAM_READY:
WLog_Print(pulse->log, WLOG_DEBUG, "PA_STREAM_READY");
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state);
pa_threaded_mainloop_signal(pulse->mainloop, 0);
break;
default:
WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state);
break;
}
}
@ -303,17 +328,17 @@ static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata)
static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata)
{
const void* data;
AudinPulseDevice* pulse = (AudinPulseDevice*) userdata;
AudinPulseDevice* pulse = (AudinPulseDevice*)userdata;
UINT error = CHANNEL_RC_OK;
pa_stream_peek(stream, &data, &length);
error = IFCALLRESULT(CHANNEL_RC_OK, pulse->receive, &pulse->format, data, length, pulse->user_data);
error =
IFCALLRESULT(CHANNEL_RC_OK, pulse->receive, &pulse->format, data, length, pulse->user_data);
pa_stream_drop(stream);
if (error && pulse->rdpcontext)
setChannelError(pulse->rdpcontext, error, "audin_pulse_thread_func reported an error");
}
/**
* Function description
*
@ -321,7 +346,7 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
*/
static UINT audin_pulse_close(IAudinDevice* device)
{
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
AudinPulseDevice* pulse = (AudinPulseDevice*)device;
if (!pulse)
return ERROR_INVALID_PARAMETER;
@ -349,7 +374,7 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
{
pa_stream_state_t state;
pa_buffer_attr buffer_attr = { 0 };
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
AudinPulseDevice* pulse = (AudinPulseDevice*)device;
if (!pulse || !receive || !user_data)
return ERROR_INVALID_PARAMETER;
@ -363,8 +388,7 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
pulse->receive = receive;
pulse->user_data = user_data;
pa_threaded_mainloop_lock(pulse->mainloop);
pulse->stream = pa_stream_new(pulse->context, "freerdp_audin",
&pulse->sample_spec, NULL);
pulse->stream = pa_stream_new(pulse->context, "freerdp_audin", &pulse->sample_spec, NULL);
if (!pulse->stream)
{
@ -375,24 +399,21 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
}
pulse->bytes_per_frame = pa_frame_size(&pulse->sample_spec);
pa_stream_set_state_callback(pulse->stream,
audin_pulse_stream_state_callback, pulse);
pa_stream_set_read_callback(pulse->stream,
audin_pulse_stream_request_callback, pulse);
buffer_attr.maxlength = (UINT32) - 1;
buffer_attr.tlength = (UINT32) - 1;
buffer_attr.prebuf = (UINT32) - 1;
buffer_attr.minreq = (UINT32) - 1;
pa_stream_set_state_callback(pulse->stream, audin_pulse_stream_state_callback, pulse);
pa_stream_set_read_callback(pulse->stream, audin_pulse_stream_request_callback, pulse);
buffer_attr.maxlength = (UINT32)-1;
buffer_attr.tlength = (UINT32)-1;
buffer_attr.prebuf = (UINT32)-1;
buffer_attr.minreq = (UINT32)-1;
/* 500ms latency */
buffer_attr.fragsize = pulse->bytes_per_frame * pulse->frames_per_packet;
if (buffer_attr.fragsize % pulse->format.nBlockAlign)
buffer_attr.fragsize += pulse->format.nBlockAlign - buffer_attr.fragsize %
pulse->format.nBlockAlign;
buffer_attr.fragsize +=
pulse->format.nBlockAlign - buffer_attr.fragsize % pulse->format.nBlockAlign;
if (pa_stream_connect_record(pulse->stream,
pulse->device_name,
&buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0)
if (pa_stream_connect_record(pulse->stream, pulse->device_name, &buffer_attr,
PA_STREAM_ADJUST_LATENCY) < 0)
{
pa_threaded_mainloop_unlock(pulse->mainloop);
WLog_Print(pulse->log, WLOG_ERROR, "pa_stream_connect_playback failed (%d)",
@ -410,8 +431,8 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
if (!PA_STREAM_IS_GOOD(state))
{
audin_pulse_close(device);
WLog_Print(pulse->log, WLOG_ERROR, "bad stream state (%d)",
pa_context_errno(pulse->context));
WLog_Print(pulse->log, WLOG_ERROR, "bad stream state (%s: %d)",
pulse_stream_state_string(state), pa_context_errno(pulse->context));
pa_threaded_mainloop_unlock(pulse->mainloop);
return pa_context_errno(pulse->context);
}
@ -425,12 +446,6 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
return CHANNEL_RC_OK;
}
static COMMAND_LINE_ARGUMENT_A audin_pulse_args[] =
{
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
/**
* Function description
*
@ -441,10 +456,15 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv, audin_pulse_args, flags,
pulse, NULL, NULL);
AudinPulseDevice* pulse = (AudinPulseDevice*)device;
COMMAND_LINE_ARGUMENT_A audin_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv, audin_pulse_args, flags, pulse,
NULL, NULL);
if (status < 0)
return ERROR_INVALID_PARAMETER;
@ -456,8 +476,7 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "dev")
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev")
{
pulse->device_name = _strdup(arg->Value);
@ -468,16 +487,15 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a
}
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry
#else
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#endif
/**
@ -490,7 +508,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
ADDIN_ARGV* args;
AudinPulseDevice* pulse;
UINT error;
pulse = (AudinPulseDevice*) calloc(1, sizeof(AudinPulseDevice));
pulse = (AudinPulseDevice*)calloc(1, sizeof(AudinPulseDevice));
if (!pulse)
{
@ -509,8 +527,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
if ((error = audin_pulse_parse_addin_args(pulse, args)))
{
WLog_Print(pulse->log, WLOG_ERROR, "audin_pulse_parse_addin_args failed with error %"PRIu32"!",
error);
WLog_Print(pulse->log, WLOG_ERROR,
"audin_pulse_parse_addin_args failed with error %" PRIu32 "!", error);
goto error_out;
}
@ -534,21 +552,21 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
pa_context_set_state_callback(pulse->context, audin_pulse_context_state_callback, pulse);
if ((error = audin_pulse_connect((IAudinDevice*) pulse)))
if ((error = audin_pulse_connect(&pulse->iface)))
{
WLog_Print(pulse->log, WLOG_ERROR, "audin_pulse_connect failed");
goto error_out;
}
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) pulse)))
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, &pulse->iface)))
{
WLog_Print(pulse->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error);
WLog_Print(pulse->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!",
error);
goto error_out;
}
return CHANNEL_RC_OK;
error_out:
audin_pulse_free((IAudinDevice*)pulse);
audin_pulse_free(&pulse->iface);
return error;
}

View File

@ -59,7 +59,7 @@ typedef struct _AudinWinmmDevice
static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
AudinWinmmDevice* winmm = (AudinWinmmDevice*) dwInstance;
AudinWinmmDevice* winmm = (AudinWinmmDevice*)dwInstance;
PWAVEHDR pWaveHdr;
UINT error = CHANNEL_RC_OK;
MMRESULT mmResult;
@ -74,8 +74,8 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance
if (WHDR_DONE == (WHDR_DONE & pWaveHdr->dwFlags))
{
if (pWaveHdr->dwBytesRecorded
&& !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0))
if (pWaveHdr->dwBytesRecorded &&
!(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0))
{
AUDIO_FORMAT format;
format.cbSize = winmm->pwfx_cur->cbSize;
@ -86,8 +86,8 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance
format.wBitsPerSample = winmm->pwfx_cur->wBitsPerSample;
format.wFormatTag = winmm->pwfx_cur->wFormatTag;
if ((error = winmm->receive(&format, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded,
winmm->user_data)))
if ((error = winmm->receive(&format, pWaveHdr->lpData,
pWaveHdr->dwBytesRecorded, winmm->user_data)))
break;
mmResult = waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR));
@ -110,34 +110,84 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance
setChannelError(winmm->rdpcontext, error, "waveInProc reported an error");
}
static BOOL log_mmresult(AudinWinmmDevice* winmm, const char* what, MMRESULT result)
{
if (result != MMSYSERR_NOERROR)
{
CHAR buffer[8192] = { 0 };
CHAR msg[8192] = { 0 };
CHAR cmsg[8192] = { 0 };
waveInGetErrorTextA(result, buffer, sizeof(buffer));
_snprintf(msg, sizeof(msg) - 1, "%s failed. %" PRIu32 " [%s]", what, result, buffer);
_snprintf(cmsg, sizeof(cmsg) - 1, "audin_winmm_thread_func reported an error '%s'", msg);
WLog_Print(winmm->log, WLOG_DEBUG, "%s", msg);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, cmsg);
return FALSE;
}
return TRUE;
}
static BOOL test_format_supported(const PWAVEFORMATEX pwfx)
{
MMRESULT rc;
WAVEINCAPSA caps = { 0 };
rc = waveInGetDevCapsA(WAVE_MAPPER, &caps, sizeof(caps));
if (rc != MMSYSERR_NOERROR)
return FALSE;
switch (pwfx->nChannels)
{
case 1:
if ((caps.dwFormats &
(WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08 |
WAVE_FORMAT_1M16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_96M16)) == 0)
return FALSE;
break;
case 2:
if ((caps.dwFormats &
(WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08 |
WAVE_FORMAT_1S16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_96S16)) == 0)
return FALSE;
break;
default:
return FALSE;
}
rc = waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0,
WAVE_FORMAT_QUERY | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE);
return (rc == MMSYSERR_NOERROR);
}
static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
{
AudinWinmmDevice* winmm = (AudinWinmmDevice*) arg;
AudinWinmmDevice* winmm = (AudinWinmmDevice*)arg;
char* buffer;
int size, i;
WAVEHDR waveHdr[4];
WAVEHDR waveHdr[4] = { 0 };
DWORD status;
MMRESULT rc;
if (!winmm->hWaveIn)
{
if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur,
(DWORD_PTR)waveInProc, (DWORD_PTR)winmm, CALLBACK_FUNCTION))
{
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
MMRESULT rc;
rc = waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur, (DWORD_PTR)waveInProc,
(DWORD_PTR)winmm,
CALLBACK_FUNCTION | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE);
if (!log_mmresult(winmm, "waveInOpen", rc))
return ERROR_INTERNAL_ERROR;
}
}
size = (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet +
7) / 8;
size =
(winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet +
7) /
8;
for (i = 0; i < 4; i++)
{
buffer = (char*) malloc(size);
buffer = (char*)malloc(size);
if (!buffer)
return CHANNEL_RC_NO_MEMORY;
@ -147,36 +197,22 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
waveHdr[i].lpData = buffer;
rc = waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
if (MMSYSERR_NOERROR != rc)
if (!log_mmresult(winmm, "waveInPrepareHeader", rc))
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInPrepareHeader failed. %"PRIu32"", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
rc = waveInAddBuffer(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
if (MMSYSERR_NOERROR != rc)
if (!log_mmresult(winmm, "waveInAddBuffer", rc))
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInAddBuffer failed. %"PRIu32"", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
}
rc = waveInStart(winmm->hWaveIn);
if (MMSYSERR_NOERROR != rc)
if (!log_mmresult(winmm, "waveInStart", rc))
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInStart failed. %"PRIu32"", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
status = WaitForSingleObject(winmm->stopEvent, INFINITE);
@ -192,26 +228,17 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
rc = waveInReset(winmm->hWaveIn);
if (MMSYSERR_NOERROR != rc)
if (!log_mmresult(winmm, "waveInReset", rc))
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInReset failed. %"PRIu32"", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
for (i = 0; i < 4; i++)
{
rc = waveInUnprepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
if (MMSYSERR_NOERROR != rc)
if (!log_mmresult(winmm, "waveInUnprepareHeader", rc))
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInUnprepareHeader failed. %"PRIu32"", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
free(waveHdr[i].lpData);
@ -219,13 +246,8 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
rc = waveInClose(winmm->hWaveIn);
if (MMSYSERR_NOERROR != rc)
if (!log_mmresult(winmm, "waveInClose", rc))
{
WLog_Print(winmm->log, WLOG_DEBUG, "waveInClose failed. %"PRIu32"", rc);
if (winmm->rdpcontext)
setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR,
"audin_winmm_thread_func reported an error");
}
winmm->hWaveIn = NULL;
@ -240,7 +262,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
static UINT audin_winmm_free(IAudinDevice* device)
{
UINT32 i;
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
if (!winmm)
return ERROR_INVALID_PARAMETER;
@ -265,7 +287,7 @@ static UINT audin_winmm_close(IAudinDevice* device)
{
DWORD status;
UINT error = CHANNEL_RC_OK;
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
if (!winmm)
return ERROR_INVALID_PARAMETER;
@ -276,7 +298,8 @@ static UINT audin_winmm_close(IAudinDevice* device)
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_Print(winmm->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"!", error);
WLog_Print(winmm->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!",
error);
return error;
}
@ -298,7 +321,7 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for
UINT32 FramesPerPacket)
{
UINT32 i;
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
if (!winmm || !format)
return ERROR_INVALID_PARAMETER;
@ -307,27 +330,46 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for
for (i = 0; i < winmm->cFormats; i++)
{
if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag
&& winmm->ppwfx[i]->nChannels == format->nChannels
&& winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample)
const PWAVEFORMATEX ppwfx = winmm->ppwfx[i];
if ((ppwfx->wFormatTag == format->wFormatTag) && (ppwfx->nChannels == format->nChannels) &&
(ppwfx->wBitsPerSample == format->wBitsPerSample) &&
(ppwfx->nSamplesPerSec == format->nSamplesPerSec))
{
winmm->pwfx_cur = winmm->ppwfx[i];
break;
/* BUG: Many devices report to support stereo recording but fail here.
* Ensure we always use mono. */
if (ppwfx->nChannels > 1)
{
ppwfx->nChannels = 1;
}
if (ppwfx->nBlockAlign != 2)
{
ppwfx->nBlockAlign = 2;
ppwfx->nAvgBytesPerSec = ppwfx->nSamplesPerSec * ppwfx->nBlockAlign;
}
if (!test_format_supported(ppwfx))
return ERROR_INVALID_PARAMETER;
winmm->pwfx_cur = ppwfx;
return CHANNEL_RC_OK;
}
}
return CHANNEL_RC_OK;
return ERROR_INVALID_PARAMETER;
}
static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format)
{
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
PWAVEFORMATEX pwfx;
BYTE* data;
if (!winmm || !format)
return FALSE;
if (format->wFormatTag != WAVE_FORMAT_PCM)
return FALSE;
pwfx = (PWAVEFORMATEX)malloc(sizeof(WAVEFORMATEX) + format->cbSize);
if (!pwfx)
@ -342,29 +384,27 @@ static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMA
data = (BYTE*)pwfx + sizeof(WAVEFORMATEX);
memcpy(data, format->data, format->cbSize);
if (pwfx->wFormatTag == WAVE_FORMAT_PCM)
pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
if (!test_format_supported(pwfx))
goto fail;
if (winmm->cFormats >= winmm->ppwfx_size)
{
pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
PWAVEFORMATEX* tmp_ppwfx;
tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2);
if (MMSYSERR_NOERROR == waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0, WAVE_FORMAT_QUERY))
{
if (winmm->cFormats >= winmm->ppwfx_size)
{
PWAVEFORMATEX* tmp_ppwfx;
tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2);
if (!tmp_ppwfx)
goto fail;
if (!tmp_ppwfx)
return FALSE;
winmm->ppwfx_size *= 2;
winmm->ppwfx = tmp_ppwfx;
}
winmm->ppwfx[winmm->cFormats++] = pwfx;
return TRUE;
}
winmm->ppwfx_size *= 2;
winmm->ppwfx = tmp_ppwfx;
}
winmm->ppwfx[winmm->cFormats++] = pwfx;
return TRUE;
fail:
free(pwfx);
return FALSE;
}
@ -376,7 +416,7 @@ static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMA
*/
static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data)
{
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
if (!winmm || !receive || !user_data)
return ERROR_INVALID_PARAMETER;
@ -390,8 +430,7 @@ static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* u
return ERROR_INTERNAL_ERROR;
}
if (!(winmm->thread = CreateThread(NULL, 0,
audin_winmm_thread_func, winmm, 0, NULL)))
if (!(winmm->thread = CreateThread(NULL, 0, audin_winmm_thread_func, winmm, 0, NULL)))
{
WLog_Print(winmm->log, WLOG_ERROR, "CreateThread failed!");
CloseHandle(winmm->stopEvent);
@ -402,12 +441,6 @@ static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* u
return CHANNEL_RC_OK;
}
static COMMAND_LINE_ARGUMENT_A audin_winmm_args[] =
{
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
/**
* Function description
*
@ -418,10 +451,15 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv, audin_winmm_args, flags,
winmm, NULL, NULL);
AudinWinmmDevice* winmm = (AudinWinmmDevice*)device;
COMMAND_LINE_ARGUMENT_A audin_winmm_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>",
NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
flags =
COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
status = CommandLineParseArgumentsA(args->argc, args->argv, audin_winmm_args, flags, winmm,
NULL, NULL);
arg = audin_winmm_args;
do
@ -429,8 +467,7 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "dev")
CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev")
{
winmm->device_name = _strdup(arg->Value);
@ -441,16 +478,15 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a
}
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry
#else
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry
#endif
/**
@ -463,7 +499,14 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
ADDIN_ARGV* args;
AudinWinmmDevice* winmm;
UINT error;
winmm = (AudinWinmmDevice*) calloc(1, sizeof(AudinWinmmDevice));
if (waveInGetNumDevs() == 0)
{
WLog_Print(WLog_Get(TAG), WLOG_ERROR, "No microphone available!");
return ERROR_DEVICE_NOT_AVAILABLE;
}
winmm = (AudinWinmmDevice*)calloc(1, sizeof(AudinWinmmDevice));
if (!winmm)
{
@ -482,8 +525,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
if ((error = audin_winmm_parse_addin_args(winmm, args)))
{
WLog_Print(winmm->log, WLOG_ERROR, "audin_winmm_parse_addin_args failed with error %"PRIu32"!",
error);
WLog_Print(winmm->log, WLOG_ERROR,
"audin_winmm_parse_addin_args failed with error %" PRIu32 "!", error);
goto error_out;
}
@ -500,7 +543,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
}
winmm->ppwfx_size = 10;
winmm->ppwfx = malloc(sizeof(PWAVEFORMATEX) * winmm->ppwfx_size);
winmm->ppwfx = calloc(winmm->ppwfx_size, sizeof(PWAVEFORMATEX));
if (!winmm->ppwfx)
{
@ -509,9 +552,10 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn
goto error_out;
}
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) winmm)))
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, &winmm->iface)))
{
WLog_Print(winmm->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error);
WLog_Print(winmm->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!",
error);
goto error_out;
}

View File

@ -35,17 +35,18 @@
#include <freerdp/codec/dsp.h>
#include <freerdp/codec/audio.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/channels/audin.h>
#include <freerdp/server/audin.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("audin.server")
#define MSG_SNDIN_VERSION 0x01
#define MSG_SNDIN_FORMATS 0x02
#define MSG_SNDIN_OPEN 0x03
#define MSG_SNDIN_OPEN_REPLY 0x04
#define MSG_SNDIN_DATA_INCOMING 0x05
#define MSG_SNDIN_DATA 0x06
#define MSG_SNDIN_FORMATCHANGE 0x07
#define MSG_SNDIN_VERSION 0x01
#define MSG_SNDIN_FORMATS 0x02
#define MSG_SNDIN_OPEN 0x03
#define MSG_SNDIN_OPEN_REPLY 0x04
#define MSG_SNDIN_DATA_INCOMING 0x05
#define MSG_SNDIN_DATA 0x06
#define MSG_SNDIN_FORMATCHANGE 0x07
typedef struct _audin_server
{
@ -69,15 +70,13 @@ typedef struct _audin_server
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_server_select_format(audin_server_context* context,
size_t client_format_index)
static UINT audin_server_select_format(audin_server_context* context, size_t client_format_index)
{
audin_server* audin = (audin_server*) context;
audin_server* audin = (audin_server*)context;
if (client_format_index >= context->num_client_formats)
{
WLog_ERR(TAG,
"error in protocol: client_format_index >= context->num_client_formats!");
WLog_ERR(TAG, "error in protocol: client_format_index >= context->num_client_formats!");
return ERROR_INVALID_DATA;
}
@ -109,7 +108,7 @@ static UINT audin_server_send_version(audin_server* audin, wStream* s)
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
if (!WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s),
if (!WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
@ -124,14 +123,13 @@ static UINT audin_server_send_version(audin_server* audin, wStream* s)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_server_recv_version(audin_server* audin, wStream* s,
UINT32 length)
static UINT audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
{
UINT32 Version;
if (length < 4)
{
WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %"PRIu32"",
WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %" PRIu32 "",
length);
return ERROR_INVALID_DATA;
}
@ -140,7 +138,7 @@ static UINT audin_server_recv_version(audin_server* audin, wStream* s,
if (Version < 1)
{
WLog_ERR(TAG, "expected Version > 0 but got %"PRIu32"", Version);
WLog_ERR(TAG, "expected Version > 0 but got %" PRIu32 "", Version);
return ERROR_INVALID_DATA;
}
@ -158,16 +156,12 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s)
ULONG written;
Stream_SetPosition(s, 0);
Stream_Write_UINT8(s, MSG_SNDIN_FORMATS);
Stream_Write_UINT32(s,
audin->context.num_server_formats); /* NumFormats (4 bytes) */
Stream_Write_UINT32(s,
0); /* cbSizeFormatsPacket (4 bytes), client-to-server only */
Stream_Write_UINT32(s, audin->context.num_server_formats); /* NumFormats (4 bytes) */
Stream_Write_UINT32(s, 0); /* cbSizeFormatsPacket (4 bytes), client-to-server only */
for (i = 0; i < audin->context.num_server_formats; i++)
{
AUDIO_FORMAT format = audin->context.server_formats[i];
// TODO: Eliminate this
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8;
if (!audio_format_write(s, &format))
{
@ -176,8 +170,10 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s)
}
}
return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s),
Stream_GetPosition(s), &written) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written)
? CHANNEL_RC_OK
: ERROR_INTERNAL_ERROR;
}
/**
@ -185,22 +181,20 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_server_recv_formats(audin_server* audin, wStream* s,
UINT32 length)
static UINT audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
{
size_t i;
UINT success = CHANNEL_RC_OK;
if (length < 8)
{
WLog_ERR(TAG, "error parsing rec formats: expected at least 8 bytes, got %"PRIu32"",
WLog_ERR(TAG, "error parsing rec formats: expected at least 8 bytes, got %" PRIu32 "",
length);
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s,
audin->context.num_client_formats); /* NumFormats (4 bytes) */
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket (4 bytes) */
Stream_Read_UINT32(s, audin->context.num_client_formats); /* NumFormats (4 bytes) */
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket (4 bytes) */
length -= 8;
if (audin->context.num_client_formats <= 0)
@ -223,7 +217,7 @@ static UINT audin_server_recv_formats(audin_server* audin, wStream* s,
{
audio_formats_free(audin->context.client_formats, i);
audin->context.client_formats = NULL;
WLog_ERR(TAG, "expected length at least 18, but got %"PRIu32"", length);
WLog_ERR(TAG, "expected length at least 18, but got %" PRIu32 "", length);
return ERROR_INVALID_DATA;
}
@ -233,7 +227,7 @@ static UINT audin_server_recv_formats(audin_server* audin, wStream* s,
IFCALLRET(audin->context.Opening, success, &audin->context);
if (success)
WLog_ERR(TAG, "context.Opening failed with error %"PRIu32"", success);
WLog_ERR(TAG, "context.Opening failed with error %" PRIu32 "", success);
return success;
}
@ -257,24 +251,24 @@ static UINT audin_server_send_open(audin_server* audin, wStream* s)
audin->opened = TRUE;
Stream_SetPosition(s, 0);
Stream_Write_UINT8(s, MSG_SNDIN_OPEN);
Stream_Write_UINT32(s,
audin->context.frames_per_packet); /* FramesPerPacket (4 bytes) */
Stream_Write_UINT32(s,
audin->context.selected_client_format); /* initialFormat (4 bytes) */
Stream_Write_UINT32(s, audin->context.frames_per_packet); /* FramesPerPacket (4 bytes) */
Stream_Write_UINT32(s, audin->context.selected_client_format); /* initialFormat (4 bytes) */
/*
* [MS-RDPEAI] 3.2.5.1.6
* The second format specify the format that SHOULD be used to capture data from
* the actual audio input device.
*/
Stream_Write_UINT16(s, 1); /* wFormatTag = PCM */
Stream_Write_UINT16(s, 2); /* nChannels */
Stream_Write_UINT32(s, 44100); /* nSamplesPerSec */
Stream_Write_UINT16(s, 1); /* wFormatTag = PCM */
Stream_Write_UINT16(s, 2); /* nChannels */
Stream_Write_UINT32(s, 44100); /* nSamplesPerSec */
Stream_Write_UINT32(s, 44100 * 2 * 2); /* nAvgBytesPerSec */
Stream_Write_UINT16(s, 4); /* nBlockAlign */
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
Stream_Write_UINT16(s, 0); /* cbSize */
return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s),
Stream_GetPosition(s), &written) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
Stream_Write_UINT16(s, 4); /* nBlockAlign */
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
Stream_Write_UINT16(s, 0); /* cbSize */
return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written)
? CHANNEL_RC_OK
: ERROR_INTERNAL_ERROR;
}
/**
@ -282,15 +276,14 @@ static UINT audin_server_send_open(audin_server* audin, wStream* s)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s,
UINT32 length)
static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
{
UINT32 Result;
UINT success = CHANNEL_RC_OK;
if (length < 4)
{
WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %"PRIu32"",
WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %" PRIu32 "",
length);
return ERROR_INVALID_DATA;
}
@ -299,7 +292,7 @@ static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s,
IFCALLRET(audin->context.OpenResult, success, &audin->context, Result);
if (success)
WLog_ERR(TAG, "context.OpenResult failed with error %"PRIu32"", success);
WLog_ERR(TAG, "context.OpenResult failed with error %" PRIu32 "", success);
return success;
}
@ -309,8 +302,7 @@ static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT audin_server_recv_data(audin_server* audin, wStream* s,
UINT32 length)
static UINT audin_server_recv_data(audin_server* audin, wStream* s, UINT32 length)
{
AUDIO_FORMAT* format;
int sbytes_per_sample;
@ -346,7 +338,7 @@ static UINT audin_server_recv_data(audin_server* audin, wStream* s,
IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, &dformat, out, frames);
if (success)
WLog_ERR(TAG, "context.ReceiveSamples failed with error %"PRIu32"", success);
WLog_ERR(TAG, "context.ReceiveSamples failed with error %" PRIu32 "", success);
}
else
WLog_ERR(TAG, "freerdp_dsp_decode failed!");
@ -365,7 +357,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
BOOL ready = FALSE;
HANDLE ChannelEvent;
DWORD BytesReturned = 0;
audin_server* audin = (audin_server*) arg;
audin_server* audin = (audin_server*)arg;
UINT error = CHANNEL_RC_OK;
DWORD status;
buffer = NULL;
@ -395,26 +387,25 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
while (1)
{
if ((status = WaitForMultipleObjects(nCount, events, FALSE,
100)) == WAIT_OBJECT_0)
if ((status = WaitForMultipleObjects(nCount, events, FALSE, 100)) == WAIT_OBJECT_0)
goto out;
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
goto out;
}
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady,
&buffer, &BytesReturned) == FALSE)
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer,
&BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
error = ERROR_INTERNAL_ERROR;
goto out;
}
ready = *((BOOL*) buffer);
ready = *((BOOL*)buffer);
WTSFreeMemory(buffer);
if (ready)
@ -434,21 +425,20 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
{
if ((error = audin_server_send_version(audin, s)))
{
WLog_ERR(TAG, "audin_server_send_version failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!", error);
goto out_capacity;
}
}
while (ready)
{
if ((status = WaitForMultipleObjects(nCount, events, FALSE,
INFINITE)) == WAIT_OBJECT_0)
if ((status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE)) == WAIT_OBJECT_0)
break;
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
goto out;
}
@ -467,7 +457,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
break;
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR)Stream_Buffer(s),
Stream_Capacity(s), &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
@ -483,13 +473,15 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
case MSG_SNDIN_VERSION:
if ((error = audin_server_recv_version(audin, s, BytesReturned)))
{
WLog_ERR(TAG, "audin_server_recv_version failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "audin_server_recv_version failed with error %" PRIu32 "!",
error);
goto out_capacity;
}
if ((error = audin_server_send_formats(audin, s)))
{
WLog_ERR(TAG, "audin_server_send_formats failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "audin_server_send_formats failed with error %" PRIu32 "!",
error);
goto out_capacity;
}
@ -498,13 +490,14 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
case MSG_SNDIN_FORMATS:
if ((error = audin_server_recv_formats(audin, s, BytesReturned)))
{
WLog_ERR(TAG, "audin_server_recv_formats failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "audin_server_recv_formats failed with error %" PRIu32 "!",
error);
goto out_capacity;
}
if ((error = audin_server_send_open(audin, s)))
{
WLog_ERR(TAG, "audin_server_send_open failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "audin_server_send_open failed with error %" PRIu32 "!", error);
goto out_capacity;
}
@ -513,7 +506,8 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
case MSG_SNDIN_OPEN_REPLY:
if ((error = audin_server_recv_open_reply(audin, s, BytesReturned)))
{
WLog_ERR(TAG, "audin_server_recv_open_reply failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "audin_server_recv_open_reply failed with error %" PRIu32 "!",
error);
goto out_capacity;
}
@ -525,7 +519,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
case MSG_SNDIN_DATA:
if ((error = audin_server_recv_data(audin, s, BytesReturned)))
{
WLog_ERR(TAG, "audin_server_recv_data failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "audin_server_recv_data failed with error %" PRIu32 "!", error);
goto out_capacity;
};
@ -535,7 +529,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
break;
default:
WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %"PRIu8"", MessageId);
WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId);
break;
}
}
@ -556,23 +550,25 @@ out:
static BOOL audin_server_open(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
audin_server* audin = (audin_server*)context;
if (!audin->thread)
{
PULONG pSessionId = NULL;
DWORD BytesReturned = 0;
audin->SessionId = WTS_CURRENT_SESSION;
UINT32 channelId;
BOOL status = TRUE;
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION,
WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned))
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned))
{
audin->SessionId = (DWORD) * pSessionId;
audin->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
}
audin->audin_channel = WTSVirtualChannelOpenEx(audin->SessionId,
"AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
audin->audin_channel = WTSVirtualChannelOpenEx(audin->SessionId, AUDIN_DVC_CHANNEL_NAME,
WTS_CHANNEL_OPTION_DYNAMIC);
if (!audin->audin_channel)
{
@ -580,13 +576,23 @@ static BOOL audin_server_open(audin_server_context* context)
return FALSE;
}
channelId = WTSChannelGetIdByHandle(audin->audin_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
if (!(audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
{
WLog_ERR(TAG, "CreateEvent failed!");
return FALSE;
}
if (!(audin->thread = CreateThread(NULL, 0, audin_server_thread_func, (void*) audin, 0, NULL)))
if (!(audin->thread =
CreateThread(NULL, 0, audin_server_thread_func, (void*)audin, 0, NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(audin->stopEvent);
@ -603,7 +609,7 @@ static BOOL audin_server_open(audin_server_context* context)
static BOOL audin_server_is_open(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
audin_server* audin = (audin_server*)context;
if (!audin)
return FALSE;
@ -613,7 +619,7 @@ static BOOL audin_server_is_open(audin_server_context* context)
static BOOL audin_server_close(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
audin_server* audin = (audin_server*)context;
if (audin->thread)
{
@ -621,7 +627,7 @@ static BOOL audin_server_close(audin_server_context* context)
if (WaitForSingleObject(audin->thread, INFINITE) == WAIT_FAILED)
{
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", GetLastError());
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
return FALSE;
}
@ -668,12 +674,12 @@ audin_server_context* audin_server_context_new(HANDLE vcm)
return NULL;
}
return (audin_server_context*) audin;
return (audin_server_context*)audin;
}
void audin_server_context_free(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
audin_server* audin = (audin_server*)context;
if (!audin)
return;

View File

@ -33,22 +33,28 @@ set(CLIENT_STATIC_TYPEDEFS "${CLIENT_STATIC_TYPEDEFS}typedef UINT (*static_addin
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
if(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL ${STATIC_ENTRY})
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${STATIC_MODULE_NAME})
foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY})
if(${ENTRY} STREQUAL ${STATIC_ENTRY})
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${STATIC_MODULE_NAME})
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}")
if(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL "VirtualChannelEntry")
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS);")
elseif(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL "VirtualChannelEntryEx")
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS,PVOID);")
else()
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(void);")
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${ENTRY}")
if(${ENTRY} STREQUAL "VirtualChannelEntry")
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS);")
elseif(${ENTRY} STREQUAL "VirtualChannelEntryEx")
set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS,PVOID);")
elseif(${ENTRY} MATCHES "DVCPluginEntry$")
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(IDRDYNVC_ENTRY_POINTS* pEntryPoints);")
elseif(${ENTRY} MATCHES "DeviceServiceEntry$")
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints);")
else()
set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(void);")
endif()
set(${STATIC_ENTRY}_IMPORTS "${${STATIC_ENTRY}_IMPORTS}\n${ENTRY_POINT_IMPORT}")
set(${STATIC_ENTRY}_TABLE "${${STATIC_ENTRY}_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_entry_fkt)${ENTRY_POINT_NAME} },")
endif()
set(${STATIC_ENTRY}_IMPORTS "${${STATIC_ENTRY}_IMPORTS}\n${ENTRY_POINT_IMPORT}")
set(${STATIC_ENTRY}_TABLE "${${STATIC_ENTRY}_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_entry_fkt)${ENTRY_POINT_NAME} },")
endif()
endforeach()
endforeach()
endforeach()
@ -91,15 +97,17 @@ foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
set(STATIC_SUBSYSTEM_ENTRY "${STATIC_SUBSYSTEM_NAME}_freerdp_${STATIC_MODULE_CHANNEL}_client_subsystem_entry")
endif()
set(SUBSYSTEM_TABLE "${SUBSYSTEM_TABLE}\n\t{ \"${STATIC_SUBSYSTEM_NAME}\", \"${STATIC_SUBSYSTEM_TYPE}\", ${STATIC_SUBSYSTEM_ENTRY} },")
set(SUBSYSTEM_IMPORT "extern void ${STATIC_SUBSYSTEM_ENTRY}(void);")
set(SUBSYSTEM_IMPORT "extern UINT ${STATIC_SUBSYSTEM_ENTRY}(void*);")
set(CLIENT_STATIC_SUBSYSTEM_IMPORTS "${CLIENT_STATIC_SUBSYSTEM_IMPORTS}\n${SUBSYSTEM_IMPORT}")
endforeach()
set(SUBSYSTEM_TABLE "${SUBSYSTEM_TABLE}\n\t{ NULL, NULL, NULL }\n};")
set(CLIENT_STATIC_SUBSYSTEM_TABLES "${CLIENT_STATIC_SUBSYSTEM_TABLES}\n${SUBSYSTEM_TABLE}")
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}")
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_addin_fkt)${ENTRY_POINT_NAME}, ${SUBSYSTEM_TABLE_NAME} },")
foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY})
set (ENTRY_POINT_NAME ${STATIC_MODULE_CHANNEL}_${ENTRY})
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", \"${ENTRY}\", (static_addin_fkt)${ENTRY_POINT_NAME}, ${SUBSYSTEM_TABLE_NAME} },")
endforeach()
endforeach()
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL }\n};")
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL, NULL }\n};")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c)

View File

@ -43,21 +43,21 @@
extern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[];
void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table,
const char* identifier)
static void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table,
const char* identifier)
{
int index = 0;
size_t index = 0;
STATIC_ENTRY* pEntry;
pEntry = (STATIC_ENTRY*) &table->table[index++];
pEntry = (STATIC_ENTRY*)&table->table[index++];
while (pEntry->entry != NULL)
{
if (strcmp(pEntry->name, identifier) == 0)
{
return (void*) pEntry->entry;
return (void*)pEntry->entry;
}
pEntry = (STATIC_ENTRY*) &table->table[index++];
pEntry = (STATIC_ENTRY*)&table->table[index++];
}
return NULL;
@ -65,9 +65,9 @@ void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* tabl
void* freerdp_channels_client_find_static_entry(const char* name, const char* identifier)
{
int index = 0;
size_t index = 0;
STATIC_ENTRY_TABLE* pEntry;
pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++];
pEntry = (STATIC_ENTRY_TABLE*)&CLIENT_STATIC_ENTRY_TABLES[index++];
while (pEntry->table != NULL)
{
@ -76,7 +76,7 @@ void* freerdp_channels_client_find_static_entry(const char* name, const char* id
return freerdp_channels_find_static_entry_in_table(pEntry, identifier);
}
pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++];
pEntry = (STATIC_ENTRY_TABLE*)&CLIENT_STATIC_ENTRY_TABLES[index++];
}
return NULL;
@ -84,15 +84,16 @@ void* freerdp_channels_client_find_static_entry(const char* name, const char* id
extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[];
FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR pszSubsystem,
LPSTR pszType, DWORD dwFlags)
static FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPCSTR pszName,
LPCSTR pszSubsystem,
LPCSTR pszType, DWORD dwFlags)
{
size_t i, j;
DWORD nAddins;
FREERDP_ADDIN** ppAddins = NULL;
STATIC_SUBSYSTEM_ENTRY* subsystems;
nAddins = 0;
ppAddins = (FREERDP_ADDIN**) calloc(128, sizeof(FREERDP_ADDIN*));
ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*));
if (!ppAddins)
{
@ -104,7 +105,7 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR
for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++)
{
FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN));
FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
if (!pAddin)
{
@ -117,11 +118,11 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR
pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
ppAddins[nAddins++] = pAddin;
subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table;
subsystems = (STATIC_SUBSYSTEM_ENTRY*)CLIENT_STATIC_ADDIN_TABLE[i].table;
for (j = 0; subsystems[j].name != NULL; j++)
{
pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN));
pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
if (!pAddin)
{
@ -129,7 +130,8 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR
goto error_out;
}
sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", CLIENT_STATIC_ADDIN_TABLE[i].name);
sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s",
CLIENT_STATIC_ADDIN_TABLE[i].name);
sprintf_s(pAddin->cSubsystem, ARRAYSIZE(pAddin->cSubsystem), "%s", subsystems[j].name);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
@ -145,8 +147,8 @@ error_out:
return NULL;
}
FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSubsystem,
LPSTR pszType, DWORD dwFlags)
static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCSTR pszSubsystem,
LPCSTR pszType, DWORD dwFlags)
{
int index;
int nDashes;
@ -163,11 +165,11 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub
size_t cchInstallPrefix;
FREERDP_ADDIN** ppAddins;
WIN32_FIND_DATAA FindData;
cchAddinPath = strlen(pszAddinPath);
cchInstallPrefix = strlen(pszInstallPrefix);
cchAddinPath = strnlen(pszAddinPath, sizeof(FREERDP_ADDIN_PATH));
cchInstallPrefix = strnlen(pszInstallPrefix, sizeof(FREERDP_INSTALL_PREFIX));
pszExtension = PathGetSharedLibraryExtensionA(0);
cchPattern = 128 + strlen(pszExtension) + 2;
pszPattern = (LPSTR) malloc(cchPattern + 1);
cchPattern = 128 + strnlen(pszExtension, MAX_PATH) + 2;
pszPattern = (LPSTR)malloc(cchPattern + 1);
if (!pszPattern)
{
@ -177,28 +179,28 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub
if (pszName && pszSubsystem && pszType)
{
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-%s-%s.%s",
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-%s-%s.%s",
pszName, pszSubsystem, pszType, pszExtension);
}
else if (pszName && pszType)
{
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-?-%s.%s",
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-?-%s.%s",
pszName, pszType, pszExtension);
}
else if (pszName)
{
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client*.%s",
pszName, pszExtension);
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client*.%s", pszName,
pszExtension);
}
else
{
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"?-client*.%s",
sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "?-client*.%s",
pszExtension);
}
cchPattern = strlen(pszPattern);
cchPattern = strnlen(pszPattern, cchPattern);
cchSearchPath = cchInstallPrefix + cchAddinPath + cchPattern + 3;
pszSearchPath = (LPSTR) malloc(cchSearchPath + 1);
pszSearchPath = (LPSTR)malloc(cchSearchPath + 1);
if (!pszSearchPath)
{
@ -215,7 +217,7 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub
hFind = FindFirstFileA(pszSearchPath, &FindData);
free(pszSearchPath);
nAddins = 0;
ppAddins = (FREERDP_ADDIN**) calloc(128, sizeof(FREERDP_ADDIN*));
ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*));
if (!ppAddins)
{
@ -229,10 +231,8 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub
do
{
char* p[5];
FREERDP_ADDIN* pAddin;
nDashes = 0;
pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN));
BOOL used = FALSE;
FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN));
if (!pAddin)
{
@ -240,59 +240,117 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub
goto error_out;
}
nDashes = 0;
for (index = 0; FindData.cFileName[index]; index++)
nDashes += (FindData.cFileName[index] == '-') ? 1 : 0;
if (nDashes == 1)
{
size_t len;
char* p[2] = { 0 };
/* <name>-client.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
len = p[1] - p[0];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
ppAddins[nAddins++] = pAddin;
used = TRUE;
}
else if (nDashes == 2)
{
size_t len;
char* p[4] = { 0 };
/* <name>-client-<subsystem>.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
p[2] = strchr(p[1], '-') + 1;
p[3] = strchr(p[2], '.') + 1;
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
len = p[1] - p[0];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
len = p[3] - p[2];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
ppAddins[nAddins++] = pAddin;
used = TRUE;
}
else if (nDashes == 3)
{
size_t len;
char* p[5] = { 0 };
/* <name>-client-<subsystem>-<type>.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
p[2] = strchr(p[1], '-') + 1;
p[3] = strchr(p[2], '-') + 1;
p[4] = strchr(p[3], '.') + 1;
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
strncpy(pAddin->cType, p[3], (p[4] - p[3]) - 1);
len = p[1] - p[0];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1));
len = p[3] - p[2];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1));
len = p[4] - p[3];
if (len < 1)
{
WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName);
goto skip;
}
strncpy(pAddin->cType, p[3], MIN(ARRAYSIZE(pAddin->cType), len - 1));
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
pAddin->dwFlags |= FREERDP_ADDIN_TYPE;
ppAddins[nAddins++] = pAddin;
used = TRUE;
}
else
{
skip:
if (!used)
free(pAddin);
}
}
while (FindNextFileA(hFind, &FindData));
} while (FindNextFileA(hFind, &FindData));
FindClose(hFind);
ppAddins[nAddins] = NULL;
@ -303,8 +361,8 @@ error_out:
return NULL;
}
FREERDP_ADDIN** freerdp_channels_list_addins(LPSTR pszName, LPSTR pszSubsystem, LPSTR pszType,
DWORD dwFlags)
FREERDP_ADDIN** freerdp_channels_list_addins(LPCSTR pszName, LPCSTR pszSubsystem, LPCSTR pszType,
DWORD dwFlags)
{
if (dwFlags & FREERDP_ADDIN_STATIC)
return freerdp_channels_list_client_static_addins(pszName, pszSubsystem, pszType, dwFlags);
@ -316,7 +374,7 @@ FREERDP_ADDIN** freerdp_channels_list_addins(LPSTR pszName, LPSTR pszSubsystem,
void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins)
{
int index;
size_t index;
if (!ppAddins)
return;
@ -329,48 +387,68 @@ void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins)
extern const STATIC_ENTRY CLIENT_VirtualChannelEntryEx_TABLE[];
BOOL freerdp_channels_is_virtual_channel_entry_ex(LPCSTR pszName)
static BOOL freerdp_channels_is_virtual_channel_entry_ex(LPCSTR pszName)
{
int i;
STATIC_ENTRY* entry;
size_t i;
for (i = 0; CLIENT_VirtualChannelEntryEx_TABLE[i].name != NULL; i++)
{
entry = (STATIC_ENTRY*) &CLIENT_VirtualChannelEntryEx_TABLE[i];
const STATIC_ENTRY* entry = &CLIENT_VirtualChannelEntryEx_TABLE[i];
if (!strcmp(entry->name, pszName))
if (!strncmp(entry->name, pszName, MAX_PATH))
return TRUE;
}
return FALSE;
}
PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPSTR pszSubsystem,
LPSTR pszType, DWORD dwFlags)
PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem,
LPCSTR pszType, DWORD dwFlags)
{
int i, j;
STATIC_SUBSYSTEM_ENTRY* subsystems;
const STATIC_ADDIN_TABLE* table = CLIENT_STATIC_ADDIN_TABLE;
const char* type = NULL;
for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++)
if (!pszName)
return NULL;
if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC)
type = "DVCPluginEntry";
else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE)
type = "DeviceServiceEntry";
else if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC)
{
if (strcmp(CLIENT_STATIC_ADDIN_TABLE[i].name, pszName) == 0)
if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
type = "VirtualChannelEntryEx";
else
type = "VirtualChannelEntry";
}
for (; table->name != NULL; table++)
{
if (strncmp(table->name, pszName, MAX_PATH) == 0)
{
if (type && strncmp(table->type, type, MAX_PATH))
continue;
if (pszSubsystem != NULL)
{
subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table;
const STATIC_SUBSYSTEM_ENTRY* subsystems = table->table;
for (j = 0; subsystems[j].name != NULL; j++)
for (; subsystems->name != NULL; subsystems++)
{
if (strcmp(subsystems[j].name, pszSubsystem) == 0)
/* If the pszSubsystem is an empty string use the default backend. */
if ((strnlen(pszSubsystem, 1) ==
0) || /* we only want to know if strnlen is > 0 */
(strncmp(subsystems->name, pszSubsystem, MAX_PATH) == 0))
{
if (pszType)
{
if (strcmp(subsystems[j].type, pszType) == 0)
return (PVIRTUALCHANNELENTRY) subsystems[j].entry;
if (strncmp(subsystems->type, pszType, MAX_PATH) == 0)
return (PVIRTUALCHANNELENTRY)subsystems->entry;
}
else
{
return (PVIRTUALCHANNELENTRY) subsystems[j].entry;
return (PVIRTUALCHANNELENTRY)subsystems->entry;
}
}
}
@ -383,7 +461,7 @@ PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LP
return NULL;
}
return (PVIRTUALCHANNELENTRY) CLIENT_STATIC_ADDIN_TABLE[i].entry;
return (PVIRTUALCHANNELENTRY)table->entry;
}
}
}

View File

@ -16,5 +16,3 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

View File

@ -19,6 +19,7 @@
* limitations under the License.
*/
#include <freerdp/channels/rdpdr.h>
#include "tables.h"
${CLIENT_STATIC_TYPEDEFS}

View File

@ -22,7 +22,7 @@
struct _STATIC_ENTRY
{
const char* name;
UINT(*entry)();
UINT (*entry)();
};
typedef struct _STATIC_ENTRY STATIC_ENTRY;
@ -37,14 +37,15 @@ struct _STATIC_SUBSYSTEM_ENTRY
{
const char* name;
const char* type;
void (*entry)(void);
UINT (*entry)();
};
typedef struct _STATIC_SUBSYSTEM_ENTRY STATIC_SUBSYSTEM_ENTRY;
struct _STATIC_ADDIN_TABLE
{
const char* name;
UINT(*entry)();
const char* type;
UINT (*entry)();
const STATIC_SUBSYSTEM_ENTRY* table;
};
typedef struct _STATIC_ADDIN_TABLE STATIC_ADDIN_TABLE;

View File

@ -21,7 +21,10 @@ set(${MODULE_PREFIX}_SRCS
cliprdr_format.c
cliprdr_format.h
cliprdr_main.c
cliprdr_main.h)
cliprdr_main.h
../cliprdr_common.h
../cliprdr_common.c
)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx")

View File

@ -33,22 +33,17 @@
#include "cliprdr_main.h"
#include "cliprdr_format.h"
#include "../cliprdr_common.h"
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags)
{
UINT32 index;
size_t position;
BOOL asciiNames;
int formatNameLength;
char* szFormatName;
WCHAR* wszFormatName;
CLIPRDR_FORMAT* formats = NULL;
CLIPRDR_FORMAT_LIST formatList;
CLIPRDR_FORMAT_LIST formatList = { 0 };
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
UINT error = CHANNEL_RC_OK;
@ -58,185 +53,24 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
return ERROR_INTERNAL_ERROR;
}
asciiNames = (msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE;
formatList.msgType = CB_FORMAT_LIST;
formatList.msgFlags = msgFlags;
formatList.dataLen = dataLen;
index = 0;
formatList.numFormats = 0;
position = Stream_GetPosition(s);
if ((error = cliprdr_read_format_list(s, &formatList, cliprdr->useLongFormatNames)))
goto error_out;
if (!formatList.dataLen)
{
/* empty format list */
formatList.formats = NULL;
formatList.numFormats = 0;
}
else if (!cliprdr->useLongFormatNames)
{
formatList.numFormats = (dataLen / 36);
if ((formatList.numFormats * 36) != dataLen)
{
WLog_ERR(TAG, "Invalid short format list length: %"PRIu32"", dataLen);
return ERROR_INTERNAL_ERROR;
}
if (formatList.numFormats)
formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT));
if (!formats)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
formatList.formats = formats;
while (dataLen)
{
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
dataLen -= 4;
formats[index].formatName = NULL;
/* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing
* the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters
* or 16 Unicode characters)"
* However, both Windows RDSH and mstsc violate this specs as seen in the following
* example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.]
* These are 16 unicode charaters - *without* terminating null !
*/
if (asciiNames)
{
szFormatName = (char*) Stream_Pointer(s);
if (szFormatName[0])
{
/* ensure null termination */
formats[index].formatName = (char*) malloc(32 + 1);
if (!formats[index].formatName)
{
WLog_ERR(TAG, "malloc failed!");
error = CHANNEL_RC_NO_MEMORY;
goto error_out;
}
CopyMemory(formats[index].formatName, szFormatName, 32);
formats[index].formatName[32] = '\0';
}
}
else
{
wszFormatName = (WCHAR*) Stream_Pointer(s);
if (wszFormatName[0])
{
/* ConvertFromUnicode always returns a null-terminated
* string on success, even if the source string isn't.
*/
if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16,
&(formats[index].formatName), 0, NULL, NULL) < 1)
{
WLog_ERR(TAG, "failed to convert short clipboard format name");
error = ERROR_INTERNAL_ERROR;
goto error_out;
}
}
}
Stream_Seek(s, 32);
dataLen -= 32;
index++;
}
}
else
{
while (dataLen)
{
Stream_Seek(s, 4); /* formatId (4 bytes) */
dataLen -= 4;
wszFormatName = (WCHAR*) Stream_Pointer(s);
if (!wszFormatName[0])
formatNameLength = 0;
else
formatNameLength = _wcslen(wszFormatName);
Stream_Seek(s, (formatNameLength + 1) * 2);
dataLen -= ((formatNameLength + 1) * 2);
formatList.numFormats++;
}
dataLen = formatList.dataLen;
Stream_SetPosition(s, position);
if (formatList.numFormats)
formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT));
if (!formats)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
formatList.formats = formats;
while (dataLen)
{
Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */
dataLen -= 4;
formats[index].formatName = NULL;
wszFormatName = (WCHAR*) Stream_Pointer(s);
if (!wszFormatName[0])
formatNameLength = 0;
else
formatNameLength = _wcslen(wszFormatName);
if (formatNameLength)
{
if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1,
&(formats[index].formatName), 0, NULL, NULL) < 1)
{
WLog_ERR(TAG, "failed to convert long clipboard format name");
error = ERROR_INTERNAL_ERROR;
goto error_out;
}
}
Stream_Seek(s, (formatNameLength + 1) * 2);
dataLen -= ((formatNameLength + 1) * 2);
index++;
}
}
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %"PRIu32"",
formatList.numFormats);
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %" PRIu32 "",
formatList.numFormats);
if (context->ServerFormatList)
{
if ((error = context->ServerFormatList(context, &formatList)))
WLog_ERR(TAG, "ServerFormatList failed with error %"PRIu32"", error);
WLog_ERR(TAG, "ServerFormatList failed with error %" PRIu32 "", error);
}
error_out:
if (formats)
{
for (index = 0; index < formatList.numFormats; index++)
{
free(formats[index].formatName);
}
free(formats);
}
cliprdr_free_format_list(&formatList);
return error;
}
@ -245,9 +79,10 @@ error_out:
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags)
{
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = { 0 };
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
UINT error = CHANNEL_RC_OK;
@ -265,7 +100,7 @@ UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UI
IFCALLRET(context->ServerFormatListResponse, error, context, &formatListResponse);
if (error)
WLog_ERR(TAG, "ServerFormatListResponse failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "ServerFormatListResponse failed with error %" PRIu32 "!", error);
return error;
}
@ -275,7 +110,8 @@ UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UI
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags)
{
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
@ -293,12 +129,13 @@ UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN
formatDataRequest.msgFlags = msgFlags;
formatDataRequest.dataLen = dataLen;
Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */
if ((error = cliprdr_read_format_data_request(s, &formatDataRequest)))
return error;
context->lastRequestedFormatId = formatDataRequest.requestedFormatId;
IFCALLRET(context->ServerFormatDataRequest, error, context, &formatDataRequest);
if (error)
WLog_ERR(TAG, "ServerFormatDataRequest failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "ServerFormatDataRequest failed with error %" PRIu32 "!", error);
return error;
}
@ -308,7 +145,8 @@ UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags)
UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags)
{
CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse;
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
@ -325,192 +163,13 @@ UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI
formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE;
formatDataResponse.msgFlags = msgFlags;
formatDataResponse.dataLen = dataLen;
formatDataResponse.requestedFormatData = NULL;
if (dataLen)
formatDataResponse.requestedFormatData = (BYTE*) Stream_Pointer(s);
if ((error = cliprdr_read_format_data_response(s, &formatDataResponse)))
return error;
IFCALLRET(context->ServerFormatDataResponse, error, context, &formatDataResponse);
if (error)
WLog_ERR(TAG, "ServerFormatDataResponse failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "ServerFormatDataResponse failed with error %" PRIu32 "!", error);
return error;
}
static UINT64 filetime_to_uint64(FILETIME value)
{
UINT64 converted = 0;
converted |= (UINT32) value.dwHighDateTime;
converted <<= 32;
converted |= (UINT32) value.dwLowDateTime;
return converted;
}
static FILETIME uint64_to_filetime(UINT64 value)
{
FILETIME converted;
converted.dwLowDateTime = (UINT32) (value >> 0);
converted.dwHighDateTime = (UINT32) (value >> 32);
return converted;
}
#define CLIPRDR_FILEDESCRIPTOR_SIZE (4 + 32 + 4 + 16 + 8 + 8 + 520)
/**
* Parse a packed file list.
*
* The resulting array must be freed with the `free()` function.
*
* @param [in] format_data packed `CLIPRDR_FILELIST` to parse.
* @param [in] format_data_length length of `format_data` in bytes.
* @param [out] file_descriptor_array parsed array of `FILEDESCRIPTOR` structs.
* @param [out] file_descriptor_count number of elements in `file_descriptor_array`.
*
* @returns 0 on success, otherwise a Win32 error code.
*/
UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length,
FILEDESCRIPTOR** file_descriptor_array, UINT32* file_descriptor_count)
{
UINT result = NO_ERROR;
UINT32 i;
UINT32 count = 0;
wStream* s = NULL;
if (!format_data || !file_descriptor_array || !file_descriptor_count)
return ERROR_BAD_ARGUMENTS;
s = Stream_New((BYTE*) format_data, format_data_length);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "invalid packed file list");
result = ERROR_INCORRECT_SIZE;
goto out;
}
Stream_Read_UINT32(s, count); /* cItems (4 bytes) */
if (Stream_GetRemainingLength(s) / CLIPRDR_FILEDESCRIPTOR_SIZE < count)
{
WLog_ERR(TAG, "packed file list is too short: expected %"PRIuz", have %"PRIuz,
((size_t) count) * CLIPRDR_FILEDESCRIPTOR_SIZE,
Stream_GetRemainingLength(s));
result = ERROR_INCORRECT_SIZE;
goto out;
}
*file_descriptor_count = count;
*file_descriptor_array = calloc(count, sizeof(FILEDESCRIPTOR));
if (!*file_descriptor_array)
{
result = ERROR_NOT_ENOUGH_MEMORY;
goto out;
}
for (i = 0; i < count; i++)
{
int c;
UINT64 lastWriteTime;
FILEDESCRIPTOR* file = &((*file_descriptor_array)[i]);
Stream_Read_UINT32(s, file->dwFlags); /* flags (4 bytes) */
Stream_Seek(s, 32); /* reserved1 (32 bytes) */
Stream_Read_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */
Stream_Seek(s, 16); /* reserved2 (16 bytes) */
Stream_Read_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */
file->ftLastWriteTime = uint64_to_filetime(lastWriteTime);
Stream_Read_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */
Stream_Read_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */
for (c = 0; c < 260; c++) /* cFileName (520 bytes) */
Stream_Read_UINT16(s, file->cFileName[c]);
}
if (Stream_GetRemainingLength(s) > 0)
WLog_WARN(TAG, "packed file list has %"PRIuz" excess bytes",
Stream_GetRemainingLength(s));
out:
Stream_Free(s, FALSE);
return result;
}
#define CLIPRDR_MAX_FILE_SIZE (2U * 1024 * 1024 * 1024)
/**
* Serialize a packed file list.
*
* The resulting format data must be freed with the `free()` function.
*
* @param [in] file_descriptor_array array of `FILEDESCRIPTOR` structs to serialize.
* @param [in] file_descriptor_count number of elements in `file_descriptor_array`.
* @param [out] format_data serialized CLIPRDR_FILELIST.
* @param [out] format_data_length length of `format_data` in bytes.
*
* @returns 0 on success, otherwise a Win32 error code.
*/
UINT cliprdr_serialize_file_list(const FILEDESCRIPTOR* file_descriptor_array,
UINT32 file_descriptor_count, BYTE** format_data, UINT32* format_data_length)
{
UINT result = NO_ERROR;
UINT32 i;
wStream* s = NULL;
if (!file_descriptor_array || !format_data || !format_data_length)
return ERROR_BAD_ARGUMENTS;
s = Stream_New(NULL, 4 + file_descriptor_count * CLIPRDR_FILEDESCRIPTOR_SIZE);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT32(s, file_descriptor_count); /* cItems (4 bytes) */
for (i = 0; i < file_descriptor_count; i++)
{
int c;
UINT64 lastWriteTime;
const FILEDESCRIPTOR* file = &file_descriptor_array[i];
/*
* There is a known issue with Windows server getting stuck in
* an infinite loop when downloading files that are larger than
* 2 gigabytes. Do not allow clients to send such file lists.
*
* https://support.microsoft.com/en-us/help/2258090
*/
if ((file->nFileSizeHigh > 0) || (file->nFileSizeLow >= CLIPRDR_MAX_FILE_SIZE))
{
WLog_ERR(TAG, "cliprdr does not support files over 2 GB");
result = ERROR_FILE_TOO_LARGE;
goto error;
}
Stream_Write_UINT32(s, file->dwFlags); /* flags (4 bytes) */
Stream_Zero(s, 32); /* reserved1 (32 bytes) */
Stream_Write_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */
Stream_Zero(s, 16); /* reserved2 (16 bytes) */
lastWriteTime = filetime_to_uint64(file->ftLastWriteTime);
Stream_Write_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */
Stream_Write_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */
Stream_Write_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */
for (c = 0; c < 260; c++) /* cFileName (520 bytes) */
Stream_Write_UINT16(s, file->cFileName[c]);
}
Stream_SealLength(s);
Stream_GetBuffer(s, *format_data);
Stream_GetLength(s, *format_data_length);
Stream_Free(s, FALSE);
return result;
error:
Stream_Free(s, TRUE);
return result;
}

View File

@ -23,9 +23,13 @@
#ifndef FREERDP_CHANNEL_CLIPRDR_CLIENT_FORMAT_H
#define FREERDP_CHANNEL_CLIPRDR_CLIENT_FORMAT_H
UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags);
UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags);
UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags);
UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags);
UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen,
UINT16 msgFlags);
#endif /* FREERDP_CHANNEL_CLIPRDR_CLIENT_FORMAT_H */

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,7 @@ struct cliprdr_plugin
BOOL streamFileClipEnabled;
BOOL fileClipNoFilePaths;
BOOL canLockClipData;
BOOL hasHugeFileSupport;
};
typedef struct cliprdr_plugin cliprdrPlugin;
@ -57,7 +58,10 @@ CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr);
#ifdef WITH_DEBUG_CLIPRDR
#define DEBUG_CLIPRDR(...) WLog_DBG(TAG, __VA_ARGS__)
#else
#define DEBUG_CLIPRDR(...) do { } while (0)
#define DEBUG_CLIPRDR(...) \
do \
{ \
} while (0)
#endif
#endif /* FREERDP_CHANNEL_CLIPRDR_CLIENT_MAIN_H */

View File

@ -0,0 +1,588 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Cliprdr common
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("cliprdr.common")
#include "cliprdr_common.h"
static BOOL cliprdr_validate_file_contents_request(const CLIPRDR_FILE_CONTENTS_REQUEST* request)
{
/*
* [MS-RDPECLIP] 2.2.5.3 File Contents Request PDU (CLIPRDR_FILECONTENTS_REQUEST).
*
* A request for the size of the file identified by the lindex field. The size MUST be
* returned as a 64-bit, unsigned integer. The cbRequested field MUST be set to
* 0x00000008 and both the nPositionLow and nPositionHigh fields MUST be
* set to 0x00000000.
*/
if (request->dwFlags & FILECONTENTS_SIZE)
{
if (request->cbRequested != sizeof(UINT64))
{
WLog_ERR(TAG, "[%s]: cbRequested must be %" PRIu32 ", got %" PRIu32 "", __FUNCTION__,
sizeof(UINT64), request->cbRequested);
return FALSE;
}
if (request->nPositionHigh != 0 || request->nPositionLow != 0)
{
WLog_ERR(TAG, "[%s]: nPositionHigh and nPositionLow must be set to 0", __FUNCTION__);
return FALSE;
}
}
return TRUE;
}
wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen)
{
wStream* s;
s = Stream_New(NULL, dataLen + 8);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
return NULL;
}
Stream_Write_UINT16(s, msgType);
Stream_Write_UINT16(s, msgFlags);
/* Write actual length after the entire packet has been constructed. */
Stream_Seek(s, 4);
return s;
}
static void cliprdr_write_file_contents_request(wStream* s,
const CLIPRDR_FILE_CONTENTS_REQUEST* request)
{
Stream_Write_UINT32(s, request->streamId); /* streamId (4 bytes) */
Stream_Write_UINT32(s, request->listIndex); /* listIndex (4 bytes) */
Stream_Write_UINT32(s, request->dwFlags); /* dwFlags (4 bytes) */
Stream_Write_UINT32(s, request->nPositionLow); /* nPositionLow (4 bytes) */
Stream_Write_UINT32(s, request->nPositionHigh); /* nPositionHigh (4 bytes) */
Stream_Write_UINT32(s, request->cbRequested); /* cbRequested (4 bytes) */
if (request->haveClipDataId)
Stream_Write_UINT32(s, request->clipDataId); /* clipDataId (4 bytes) */
}
static INLINE void cliprdr_write_lock_unlock_clipdata(wStream* s, UINT32 clipDataId)
{
Stream_Write_UINT32(s, clipDataId);
}
static void cliprdr_write_lock_clipdata(wStream* s,
const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
{
cliprdr_write_lock_unlock_clipdata(s, lockClipboardData->clipDataId);
}
static void cliprdr_write_unlock_clipdata(wStream* s,
const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
{
cliprdr_write_lock_unlock_clipdata(s, unlockClipboardData->clipDataId);
}
static void cliprdr_write_file_contents_response(wStream* s,
const CLIPRDR_FILE_CONTENTS_RESPONSE* response)
{
Stream_Write_UINT32(s, response->streamId); /* streamId (4 bytes) */
Stream_Write(s, response->requestedData, response->cbRequested);
}
wStream* cliprdr_packet_lock_clipdata_new(const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
{
wStream* s;
if (!lockClipboardData)
return NULL;
s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4);
if (!s)
return NULL;
cliprdr_write_lock_clipdata(s, lockClipboardData);
return s;
}
wStream*
cliprdr_packet_unlock_clipdata_new(const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
{
wStream* s;
if (!unlockClipboardData)
return NULL;
s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4);
if (!s)
return NULL;
cliprdr_write_unlock_clipdata(s, unlockClipboardData);
return s;
}
wStream* cliprdr_packet_file_contents_request_new(const CLIPRDR_FILE_CONTENTS_REQUEST* request)
{
wStream* s;
if (!request)
return NULL;
s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 28);
if (!s)
return NULL;
cliprdr_write_file_contents_request(s, request);
return s;
}
wStream* cliprdr_packet_file_contents_response_new(const CLIPRDR_FILE_CONTENTS_RESPONSE* response)
{
wStream* s;
if (!response)
return NULL;
s = cliprdr_packet_new(CB_FILECONTENTS_RESPONSE, response->msgFlags, 4 + response->cbRequested);
if (!s)
return NULL;
cliprdr_write_file_contents_response(s, response);
return s;
}
wStream* cliprdr_packet_format_list_new(const CLIPRDR_FORMAT_LIST* formatList,
BOOL useLongFormatNames)
{
wStream* s;
UINT32 index;
int cchWideChar;
LPWSTR lpWideCharStr;
int formatNameSize;
char* szFormatName;
WCHAR* wszFormatName;
BOOL asciiNames = FALSE;
CLIPRDR_FORMAT* format;
UINT32 length;
if (formatList->msgType != CB_FORMAT_LIST)
WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__,
formatList->msgType);
if (!useLongFormatNames)
{
length = formatList->numFormats * 36;
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length);
if (!s)
{
WLog_ERR(TAG, "cliprdr_packet_new failed!");
return NULL;
}
for (index = 0; index < formatList->numFormats; index++)
{
size_t formatNameLength = 0;
format = (CLIPRDR_FORMAT*)&(formatList->formats[index]);
Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */
formatNameSize = 0;
szFormatName = format->formatName;
if (asciiNames)
{
if (szFormatName)
formatNameLength = strnlen(szFormatName, 32);
if (formatNameLength > 31)
formatNameLength = 31;
Stream_Write(s, szFormatName, formatNameLength);
Stream_Zero(s, 32 - formatNameLength);
}
else
{
wszFormatName = NULL;
if (szFormatName)
formatNameSize =
ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, 0);
if (formatNameSize < 0)
{
Stream_Free(s, TRUE);
return NULL;
}
if (formatNameSize > 15)
formatNameSize = 15;
/* size in bytes instead of wchar */
formatNameSize *= 2;
if (wszFormatName)
Stream_Write(s, wszFormatName, (size_t)formatNameSize);
Stream_Zero(s, (size_t)(32 - formatNameSize));
free(wszFormatName);
}
}
}
else
{
length = 0;
for (index = 0; index < formatList->numFormats; index++)
{
format = (CLIPRDR_FORMAT*)&(formatList->formats[index]);
length += 4;
formatNameSize = 2;
if (format->formatName)
formatNameSize =
MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0) * 2;
if (formatNameSize < 0)
return NULL;
length += (UINT32)formatNameSize;
}
s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length);
if (!s)
{
WLog_ERR(TAG, "cliprdr_packet_new failed!");
return NULL;
}
for (index = 0; index < formatList->numFormats; index++)
{
format = (CLIPRDR_FORMAT*)&(formatList->formats[index]);
Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */
if (format->formatName)
{
const size_t cap = Stream_Capacity(s);
const size_t pos = Stream_GetPosition(s);
const size_t rem = cap - pos;
if ((cap < pos) || ((rem / 2) > INT_MAX))
{
Stream_Free(s, TRUE);
return NULL;
}
lpWideCharStr = (LPWSTR)Stream_Pointer(s);
cchWideChar = (int)(rem / 2);
formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1,
lpWideCharStr, cchWideChar) *
2;
if (formatNameSize < 0)
{
Stream_Free(s, TRUE);
return NULL;
}
Stream_Seek(s, (size_t)formatNameSize);
}
else
{
Stream_Write_UINT16(s, 0);
}
}
}
return s;
}
UINT cliprdr_read_unlock_clipdata(wStream* s, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
{
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "not enough remaining data");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */
return CHANNEL_RC_OK;
}
UINT cliprdr_read_format_data_request(wStream* s, CLIPRDR_FORMAT_DATA_REQUEST* request)
{
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "not enough data in stream!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, request->requestedFormatId); /* requestedFormatId (4 bytes) */
return CHANNEL_RC_OK;
}
UINT cliprdr_read_format_data_response(wStream* s, CLIPRDR_FORMAT_DATA_RESPONSE* response)
{
response->requestedFormatData = NULL;
if (Stream_GetRemainingLength(s) < response->dataLen)
{
WLog_ERR(TAG, "not enough data in stream!");
return ERROR_INVALID_DATA;
}
if (response->dataLen)
response->requestedFormatData = Stream_Pointer(s);
return CHANNEL_RC_OK;
}
UINT cliprdr_read_file_contents_request(wStream* s, CLIPRDR_FILE_CONTENTS_REQUEST* request)
{
if (Stream_GetRemainingLength(s) < 24)
{
WLog_ERR(TAG, "not enough remaining data");
return ERROR_INVALID_DATA;
}
request->haveClipDataId = FALSE;
Stream_Read_UINT32(s, request->streamId); /* streamId (4 bytes) */
Stream_Read_UINT32(s, request->listIndex); /* listIndex (4 bytes) */
Stream_Read_UINT32(s, request->dwFlags); /* dwFlags (4 bytes) */
Stream_Read_UINT32(s, request->nPositionLow); /* nPositionLow (4 bytes) */
Stream_Read_UINT32(s, request->nPositionHigh); /* nPositionHigh (4 bytes) */
Stream_Read_UINT32(s, request->cbRequested); /* cbRequested (4 bytes) */
if (Stream_GetRemainingLength(s) >= 4)
{
Stream_Read_UINT32(s, request->clipDataId); /* clipDataId (4 bytes) */
request->haveClipDataId = TRUE;
}
if (!cliprdr_validate_file_contents_request(request))
return ERROR_BAD_ARGUMENTS;
return CHANNEL_RC_OK;
}
UINT cliprdr_read_file_contents_response(wStream* s, CLIPRDR_FILE_CONTENTS_RESPONSE* response)
{
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "not enough remaining data");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, response->streamId); /* streamId (4 bytes) */
response->requestedData = Stream_Pointer(s); /* requestedFileContentsData */
response->cbRequested = response->dataLen - 4;
return CHANNEL_RC_OK;
}
UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL useLongFormatNames)
{
UINT32 index;
BOOL asciiNames;
int formatNameLength;
char* szFormatName;
WCHAR* wszFormatName;
wStream sub1, sub2;
CLIPRDR_FORMAT* formats = NULL;
UINT error = ERROR_INTERNAL_ERROR;
asciiNames = (formatList->msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE;
index = 0;
/* empty format list */
formatList->formats = NULL;
formatList->numFormats = 0;
Stream_StaticInit(&sub1, Stream_Pointer(s), formatList->dataLen);
if (!Stream_SafeSeek(s, formatList->dataLen))
return ERROR_INVALID_DATA;
if (!formatList->dataLen)
{
}
else if (!useLongFormatNames)
{
const size_t cap = Stream_Capacity(&sub1);
formatList->numFormats = (cap / 36);
if ((formatList->numFormats * 36) != cap)
{
WLog_ERR(TAG, "Invalid short format list length: %" PRIuz "", cap);
return ERROR_INTERNAL_ERROR;
}
if (formatList->numFormats)
formats = (CLIPRDR_FORMAT*)calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT));
if (!formats)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
formatList->formats = formats;
while (Stream_GetRemainingLength(&sub1) >= 4)
{
Stream_Read_UINT32(&sub1, formats[index].formatId); /* formatId (4 bytes) */
formats[index].formatName = NULL;
/* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing
* the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters
* or 16 Unicode characters)"
* However, both Windows RDSH and mstsc violate this specs as seen in the following
* example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.]
* These are 16 unicode charaters - *without* terminating null !
*/
szFormatName = (char*)Stream_Pointer(&sub1);
wszFormatName = (WCHAR*)Stream_Pointer(&sub1);
if (!Stream_SafeSeek(&sub1, 32))
goto error_out;
if (asciiNames)
{
if (szFormatName[0])
{
/* ensure null termination */
formats[index].formatName = (char*)malloc(32 + 1);
if (!formats[index].formatName)
{
WLog_ERR(TAG, "malloc failed!");
error = CHANNEL_RC_NO_MEMORY;
goto error_out;
}
CopyMemory(formats[index].formatName, szFormatName, 32);
formats[index].formatName[32] = '\0';
}
}
else
{
if (wszFormatName[0])
{
/* ConvertFromUnicode always returns a null-terminated
* string on success, even if the source string isn't.
*/
if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16,
&(formats[index].formatName), 0, NULL, NULL) < 1)
{
WLog_ERR(TAG, "failed to convert short clipboard format name");
error = ERROR_INTERNAL_ERROR;
goto error_out;
}
}
}
index++;
}
}
else
{
sub2 = sub1;
while (Stream_GetRemainingLength(&sub1) > 0)
{
size_t rest;
if (!Stream_SafeSeek(&sub1, 4)) /* formatId (4 bytes) */
goto error_out;
wszFormatName = (WCHAR*)Stream_Pointer(&sub1);
rest = Stream_GetRemainingLength(&sub1);
formatNameLength = _wcsnlen(wszFormatName, rest / sizeof(WCHAR));
if (!Stream_SafeSeek(&sub1, (formatNameLength + 1) * sizeof(WCHAR)))
goto error_out;
formatList->numFormats++;
}
if (formatList->numFormats)
formats = (CLIPRDR_FORMAT*)calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT));
if (!formats)
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
formatList->formats = formats;
while (Stream_GetRemainingLength(&sub2) >= 4)
{
size_t rest;
Stream_Read_UINT32(&sub2, formats[index].formatId); /* formatId (4 bytes) */
formats[index].formatName = NULL;
wszFormatName = (WCHAR*)Stream_Pointer(&sub2);
rest = Stream_GetRemainingLength(&sub2);
formatNameLength = _wcsnlen(wszFormatName, rest / sizeof(WCHAR));
if (!Stream_SafeSeek(&sub2, (formatNameLength + 1) * sizeof(WCHAR)))
goto error_out;
if (formatNameLength)
{
if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, formatNameLength,
&(formats[index].formatName), 0, NULL, NULL) < 1)
{
WLog_ERR(TAG, "failed to convert long clipboard format name");
error = ERROR_INTERNAL_ERROR;
goto error_out;
}
}
index++;
}
}
return CHANNEL_RC_OK;
error_out:
cliprdr_free_format_list(formatList);
return error;
}
void cliprdr_free_format_list(CLIPRDR_FORMAT_LIST* formatList)
{
UINT index = 0;
if (formatList == NULL)
return;
if (formatList->formats)
{
for (index = 0; index < formatList->numFormats; index++)
{
free(formatList->formats[index].formatName);
}
free(formatList->formats);
formatList->formats = NULL;
formatList->numFormats = 0;
}
}

View File

@ -0,0 +1,61 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Cliprdr common
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_RDPECLIP_COMMON_H
#define FREERDP_CHANNEL_RDPECLIP_COMMON_H
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <freerdp/channels/cliprdr.h>
#include <freerdp/api.h>
FREERDP_LOCAL wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen);
FREERDP_LOCAL wStream*
cliprdr_packet_lock_clipdata_new(const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData);
FREERDP_LOCAL wStream*
cliprdr_packet_unlock_clipdata_new(const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData);
FREERDP_LOCAL wStream*
cliprdr_packet_file_contents_request_new(const CLIPRDR_FILE_CONTENTS_REQUEST* request);
FREERDP_LOCAL wStream*
cliprdr_packet_file_contents_response_new(const CLIPRDR_FILE_CONTENTS_RESPONSE* response);
FREERDP_LOCAL wStream* cliprdr_packet_format_list_new(const CLIPRDR_FORMAT_LIST* formatList,
BOOL useLongFormatNames);
FREERDP_LOCAL UINT cliprdr_read_lock_clipdata(wStream* s,
CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData);
FREERDP_LOCAL UINT cliprdr_read_unlock_clipdata(wStream* s,
CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData);
FREERDP_LOCAL UINT cliprdr_read_format_data_request(wStream* s,
CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
FREERDP_LOCAL UINT cliprdr_read_format_data_response(wStream* s,
CLIPRDR_FORMAT_DATA_RESPONSE* response);
FREERDP_LOCAL UINT
cliprdr_read_file_contents_request(wStream* s, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest);
FREERDP_LOCAL UINT cliprdr_read_file_contents_response(wStream* s,
CLIPRDR_FILE_CONTENTS_RESPONSE* response);
FREERDP_LOCAL UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList,
BOOL useLongFormatNames);
FREERDP_LOCAL void cliprdr_free_format_list(CLIPRDR_FORMAT_LIST* formatList);
#endif /* FREERDP_CHANNEL_RDPECLIP_COMMON_H */

View File

@ -19,7 +19,10 @@ define_channel_server("cliprdr")
set(${MODULE_PREFIX}_SRCS
cliprdr_main.c
cliprdr_main.h)
cliprdr_main.h
../cliprdr_common.h
../cliprdr_common.c
)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
#define TAG CHANNELS_TAG("cliprdr.server")
#define CLIPRDR_HEADER_LENGTH 8
#define CLIPRDR_HEADER_LENGTH 8
struct _cliprdr_server_private
{

View File

@ -20,3 +20,7 @@ define_channel("disp")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -19,7 +19,9 @@ define_channel_client("disp")
set(${MODULE_PREFIX}_SRCS
disp_main.c
disp_main.h)
disp_main.h
../disp_common.c
../disp_common.h)
include_directories(..)

182
channels/disp/client/disp_main.c Executable file → Normal file
View File

@ -40,6 +40,7 @@
#include <freerdp/addin.h>
#include "disp_main.h"
#include "../disp_common.h"
struct _DISP_CHANNEL_CALLBACK
{
@ -71,6 +72,7 @@ struct _DISP_PLUGIN
UINT32 MaxNumMonitors;
UINT32 MaxMonitorAreaFactorA;
UINT32 MaxMonitorAreaFactorB;
BOOL initialized;
};
typedef struct _DISP_PLUGIN DISP_PLUGIN;
@ -79,41 +81,42 @@ typedef struct _DISP_PLUGIN DISP_PLUGIN;
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors)
static UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback,
UINT32 NumMonitors,
DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors)
{
UINT status;
wStream* s;
UINT32 type;
UINT32 index;
UINT32 length;
DISP_PLUGIN* disp;
UINT32 MonitorLayoutSize;
DISPLAY_CONTROL_HEADER header;
disp = (DISP_PLUGIN*)callback->plugin;
MonitorLayoutSize = DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE;
header.length = 8 + 8 + (NumMonitors * MonitorLayoutSize);
header.type = DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT;
disp = (DISP_PLUGIN*) callback->plugin;
s = Stream_New(NULL, header.length);
MonitorLayoutSize = 40;
length = 8 + 8 + (NumMonitors * MonitorLayoutSize);
type = DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT;
s = Stream_New(NULL, length);
if(!s)
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write_UINT32(s, type); /* Type (4 bytes) */
Stream_Write_UINT32(s, length); /* Length (4 bytes) */
if ((status = disp_write_header(s, &header)))
{
WLog_ERR(TAG, "Failed to write header with error %" PRIu32 "!", status);
goto out;
}
if (NumMonitors > disp->MaxNumMonitors)
NumMonitors = disp->MaxNumMonitors;
Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
WLog_DBG(TAG, "disp_send_display_control_monitor_layout_pdu: NumMonitors=%"PRIu32"", NumMonitors);
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
WLog_DBG(TAG, "disp_send_display_control_monitor_layout_pdu: NumMonitors=%" PRIu32 "",
NumMonitors);
for (index = 0; index < NumMonitors; index++)
{
@ -134,30 +137,34 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac
if (Monitors[index].Height > 8192)
Monitors[index].Height = 8192;
Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Top); /* Top (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Width); /* Width (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Height); /* Height (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Top); /* Top (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Width); /* Width (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Height); /* Height (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */
Stream_Write_UINT32(s,
Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */
WLog_DBG(TAG, "\t%d : Flags: 0x%08"PRIX32" Left/Top: (%"PRId32",%"PRId32") W/H=%"PRIu32"x%"PRIu32")", index,
Monitors[index].Flags, Monitors[index].Left, Monitors[index].Top, Monitors[index].Width,
Monitors[index].Height);
WLog_DBG(TAG, "\t PhysicalWidth: %"PRIu32" PhysicalHeight: %"PRIu32" Orientation: %"PRIu32"",
Monitors[index].PhysicalWidth, Monitors[index].PhysicalHeight, Monitors[index].Orientation);
WLog_DBG(TAG,
"\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32
"x%" PRIu32 ")",
index, Monitors[index].Flags, Monitors[index].Left, Monitors[index].Top,
Monitors[index].Width, Monitors[index].Height);
WLog_DBG(TAG,
"\t PhysicalWidth: %" PRIu32 " PhysicalHeight: %" PRIu32 " Orientation: %" PRIu32
"",
Monitors[index].PhysicalWidth, Monitors[index].PhysicalHeight,
Monitors[index].Orientation);
}
out:
Stream_SealLength(s);
status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL);
status = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
NULL);
Stream_Free(s, TRUE);
return status;
}
@ -166,14 +173,13 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
static UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
{
DISP_PLUGIN* disp;
DispClientContext *context;
DispClientContext* context;
UINT ret = CHANNEL_RC_OK;
disp = (DISP_PLUGIN*) callback->plugin;
context = (DispClientContext *)disp->iface.pInterface;
disp = (DISP_PLUGIN*)callback->plugin;
context = (DispClientContext*)disp->iface.pInterface;
if (Stream_GetRemainingLength(s) < 12)
{
@ -181,12 +187,13 @@ UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */
Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */
Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorA); /* MaxMonitorAreaFactorA (4 bytes) */
Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorB); /* MaxMonitorAreaFactorB (4 bytes) */
if (context->DisplayControlCaps)
ret = context->DisplayControlCaps(context, disp->MaxNumMonitors, disp->MaxMonitorAreaFactorA, disp->MaxMonitorAreaFactorB);
ret = context->DisplayControlCaps(context, disp->MaxNumMonitors,
disp->MaxMonitorAreaFactorA, disp->MaxMonitorAreaFactorB);
return ret;
}
@ -196,10 +203,10 @@ UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
static UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
{
UINT32 type;
UINT32 length;
UINT32 error;
DISPLAY_CONTROL_HEADER header;
if (Stream_GetRemainingLength(s) < 8)
{
@ -207,18 +214,25 @@ UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, type); /* Type (4 bytes) */
Stream_Read_UINT32(s, length); /* Length (4 bytes) */
if ((error = disp_read_header(s, &header)))
{
WLog_ERR(TAG, "disp_read_header failed with error %" PRIu32 "!", error);
return error;
}
//WLog_ERR(TAG, "Type: %"PRIu32" Length: %"PRIu32"", type, length);
if (!Stream_EnsureRemainingCapacity(s, header.length))
{
WLog_ERR(TAG, "not enough remaining data");
return ERROR_INVALID_DATA;
}
switch (type)
switch (header.type)
{
case DISPLAY_CONTROL_PDU_TYPE_CAPS:
return disp_recv_display_control_caps_pdu(callback, s);
default:
WLog_ERR(TAG, "Type %"PRIu32" not recognized!", type);
WLog_ERR(TAG, "Type %" PRIu32 " not recognized!", header.type);
return ERROR_INTERNAL_ERROR;
}
}
@ -228,10 +242,9 @@ UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
static UINT disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
{
DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback;
DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*)pChannelCallback;
return disp_recv_pdu(callback, data);
}
@ -252,13 +265,12 @@ static UINT disp_on_close(IWTSVirtualChannelCallback* pChannelCallback)
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
DISP_CHANNEL_CALLBACK* callback;
DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*) pListenerCallback;
callback = (DISP_CHANNEL_CALLBACK*) calloc(1, sizeof(DISP_CHANNEL_CALLBACK));
DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*)pListenerCallback;
callback = (DISP_CHANNEL_CALLBACK*)calloc(1, sizeof(DISP_CHANNEL_CALLBACK));
if (!callback)
{
@ -272,9 +284,7 @@ static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallba
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = (IWTSVirtualChannelCallback*) callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
@ -286,9 +296,13 @@ static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallba
static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT status;
DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin;
disp->listener_callback = (DISP_LISTENER_CALLBACK*) calloc(1, sizeof(DISP_LISTENER_CALLBACK));
DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin;
if (disp->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", DISP_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
disp->listener_callback = (DISP_LISTENER_CALLBACK*)calloc(1, sizeof(DISP_LISTENER_CALLBACK));
if (!disp->listener_callback)
{
@ -299,12 +313,11 @@ static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage
disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection;
disp->listener_callback->plugin = pPlugin;
disp->listener_callback->channel_mgr = pChannelMgr;
status = pChannelMgr->CreateListener(pChannelMgr, DISP_DVC_CHANNEL_NAME, 0,
(IWTSListenerCallback*) disp->listener_callback, &(disp->listener));
&disp->listener_callback->iface, &(disp->listener));
disp->listener->pInterface = disp->iface.pInterface;
disp->initialized = status == CHANNEL_RC_OK;
return status;
}
@ -315,7 +328,15 @@ static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage
*/
static UINT disp_plugin_terminated(IWTSPlugin* pPlugin)
{
DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin;
DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin;
if (disp && disp->listener_callback)
{
IWTSVirtualChannelManager* mgr = disp->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, disp->listener);
}
free(disp->listener_callback);
free(disp->iface.pInterface);
free(pPlugin);
@ -331,18 +352,18 @@ static UINT disp_plugin_terminated(IWTSPlugin* pPlugin)
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors)
static UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors,
DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors)
{
DISP_PLUGIN* disp = (DISP_PLUGIN*) context->handle;
DISP_PLUGIN* disp = (DISP_PLUGIN*)context->handle;
DISP_CHANNEL_CALLBACK* callback = disp->listener_callback->channel_callback;
return disp_send_display_control_monitor_layout_pdu(callback, NumMonitors, Monitors);
}
#ifdef BUILTIN_CHANNELS
#define DVCPluginEntry disp_DVCPluginEntry
#define DVCPluginEntry disp_DVCPluginEntry
#else
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#endif
/**
@ -355,11 +376,12 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
UINT error = CHANNEL_RC_OK;
DISP_PLUGIN* disp;
DispClientContext* context;
disp = (DISP_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "disp");
disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp");
if (!disp)
{
disp = (DISP_PLUGIN*) calloc(1, sizeof(DISP_PLUGIN));
disp = (DISP_PLUGIN*)calloc(1, sizeof(DISP_PLUGIN));
if (!disp)
{
WLog_ERR(TAG, "calloc failed!");
@ -373,8 +395,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
disp->MaxNumMonitors = 16;
disp->MaxMonitorAreaFactorA = 8192;
disp->MaxMonitorAreaFactorB = 8192;
context = (DispClientContext*)calloc(1, sizeof(DispClientContext));
context = (DispClientContext*) calloc(1, sizeof(DispClientContext));
if (!context)
{
WLog_ERR(TAG, "calloc failed!");
@ -382,12 +404,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
return CHANNEL_RC_NO_MEMORY;
}
context->handle = (void*) disp;
context->handle = (void*)disp;
context->SendMonitorLayout = disp_send_monitor_layout;
disp->iface.pInterface = (void*) context;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
disp->iface.pInterface = (void*)context;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*)disp);
}
else
{

View File

@ -33,10 +33,6 @@
#include <freerdp/client/disp.h>
#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000005
#define DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002
#define TAG CHANNELS_TAG("disp.client")
#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */

View File

@ -0,0 +1,60 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDPEDISP Virtual Channel Extension
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <freerdp/channels/log.h>
#define TAG CHANNELS_TAG("disp.common")
#include "disp_common.h"
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT disp_read_header(wStream* s, DISPLAY_CONTROL_HEADER* header)
{
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "header parsing failed: not enough data!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, header->type);
Stream_Read_UINT32(s, header->length);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT disp_write_header(wStream* s, const DISPLAY_CONTROL_HEADER* header)
{
Stream_Write_UINT32(s, header->type);
Stream_Write_UINT32(s, header->length);
return CHANNEL_RC_OK;
}

View File

@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDPEDISP Virtual Channel Extension
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_DISP_COMMON_H
#define FREERDP_CHANNEL_DISP_COMMON_H
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <freerdp/channels/disp.h>
#include <freerdp/api.h>
FREERDP_LOCAL UINT disp_read_header(wStream* s, DISPLAY_CONTROL_HEADER* header);
FREERDP_LOCAL UINT disp_write_header(wStream* s, const DISPLAY_CONTROL_HEADER* header);
#endif /* FREERDP_CHANNEL_DISP_COMMON_H */

View File

@ -0,0 +1,32 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_server("disp")
set(${MODULE_PREFIX}_SRCS
disp_main.c
disp_main.h
../disp_common.c
../disp_common.h
)
include_directories(..)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View File

@ -0,0 +1,597 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDPEDISP Virtual Channel Extension
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "disp_main.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/channels/log.h>
#include <freerdp/server/disp.h>
#include "../disp_common.h"
#define TAG CHANNELS_TAG("rdpedisp.server")
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static wStream* disp_server_single_packet_new(UINT32 type, UINT32 length)
{
UINT error;
DISPLAY_CONTROL_HEADER header;
wStream* s = Stream_New(NULL, DISPLAY_CONTROL_HEADER_LENGTH + length);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
goto error;
}
header.type = type;
header.length = DISPLAY_CONTROL_HEADER_LENGTH + length;
if ((error = disp_write_header(s, &header)))
{
WLog_ERR(TAG, "Failed to write header with error %" PRIu32 "!", error);
goto error;
}
return s;
error:
Stream_Free(s, TRUE);
return NULL;
}
static void disp_server_sanitize_monitor_layout(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor)
{
if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH ||
monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH ||
monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT ||
monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT)
{
if (monitor->PhysicalWidth != 0 || monitor->PhysicalHeight != 0)
WLog_DBG(
TAG,
"Sanitizing invalid physical monitor size. Old physical monitor size: [%" PRIu32
", %" PRIu32 "]",
monitor->PhysicalWidth, monitor->PhysicalHeight);
monitor->PhysicalWidth = monitor->PhysicalHeight = 0;
}
}
static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor)
{
if (monitor->Width < DISPLAY_CONTROL_MIN_MONITOR_WIDTH ||
monitor->Width > DISPLAY_CONTROL_MAX_MONITOR_WIDTH)
{
WLog_WARN(TAG, "Received invalid value for monitor->Width: %" PRIu32 "", monitor->Width);
return FALSE;
}
if (monitor->Height < DISPLAY_CONTROL_MIN_MONITOR_HEIGHT ||
monitor->Height > DISPLAY_CONTROL_MAX_MONITOR_HEIGHT)
{
WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "", monitor->Width);
return FALSE;
}
switch (monitor->Orientation)
{
case ORIENTATION_LANDSCAPE:
case ORIENTATION_PORTRAIT:
case ORIENTATION_LANDSCAPE_FLIPPED:
case ORIENTATION_PORTRAIT_FLIPPED:
break;
default:
WLog_WARN(TAG, "Received incorrect value for monitor->Orientation: %" PRIu32 "",
monitor->Orientation);
return FALSE;
}
return TRUE;
}
static UINT disp_recv_display_control_monitor_layout_pdu(wStream* s, DispServerContext* context)
{
UINT32 error = CHANNEL_RC_OK;
UINT32 index;
DISPLAY_CONTROL_MONITOR_LAYOUT_PDU pdu;
DISPLAY_CONTROL_MONITOR_LAYOUT* monitor;
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "not enough data!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, pdu.MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */
if (pdu.MonitorLayoutSize != DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE)
{
WLog_ERR(TAG, "MonitorLayoutSize is set to %" PRIu32 ". expected %" PRIu32 "",
pdu.MonitorLayoutSize, DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE);
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, pdu.NumMonitors); /* NumMonitors (4 bytes) */
if (pdu.NumMonitors > context->MaxNumMonitors)
{
WLog_ERR(TAG, "NumMonitors (%" PRIu32 ")> server MaxNumMonitors (%" PRIu32 ")",
pdu.NumMonitors, context->MaxNumMonitors);
return ERROR_INVALID_DATA;
}
if (Stream_GetRemainingLength(s) < DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE * pdu.NumMonitors)
{
WLog_ERR(TAG, "not enough data!");
return ERROR_INVALID_DATA;
}
pdu.Monitors = (DISPLAY_CONTROL_MONITOR_LAYOUT*)calloc(pdu.NumMonitors,
sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
if (!pdu.Monitors)
{
WLog_ERR(TAG, "disp_recv_display_control_monitor_layout_pdu(): calloc failed!");
return CHANNEL_RC_NO_MEMORY;
}
WLog_DBG(TAG, "disp_recv_display_control_monitor_layout_pdu: NumMonitors=%" PRIu32 "",
pdu.NumMonitors);
for (index = 0; index < pdu.NumMonitors; index++)
{
monitor = &(pdu.Monitors[index]);
Stream_Read_UINT32(s, monitor->Flags); /* Flags (4 bytes) */
Stream_Read_UINT32(s, monitor->Left); /* Left (4 bytes) */
Stream_Read_UINT32(s, monitor->Top); /* Top (4 bytes) */
Stream_Read_UINT32(s, monitor->Width); /* Width (4 bytes) */
Stream_Read_UINT32(s, monitor->Height); /* Height (4 bytes) */
Stream_Read_UINT32(s, monitor->PhysicalWidth); /* PhysicalWidth (4 bytes) */
Stream_Read_UINT32(s, monitor->PhysicalHeight); /* PhysicalHeight (4 bytes) */
Stream_Read_UINT32(s, monitor->Orientation); /* Orientation (4 bytes) */
Stream_Read_UINT32(s, monitor->DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
Stream_Read_UINT32(s, monitor->DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */
disp_server_sanitize_monitor_layout(monitor);
WLog_DBG(TAG,
"\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32
"x%" PRIu32 ")",
index, monitor->Flags, monitor->Left, monitor->Top, monitor->Width,
monitor->Height);
WLog_DBG(TAG,
"\t PhysicalWidth: %" PRIu32 " PhysicalHeight: %" PRIu32 " Orientation: %" PRIu32
"",
monitor->PhysicalWidth, monitor->PhysicalHeight, monitor->Orientation);
if (!disp_server_is_monitor_layout_valid(monitor))
{
error = ERROR_INVALID_DATA;
goto out;
}
}
if (context)
IFCALLRET(context->DispMonitorLayout, error, context, &pdu);
out:
free(pdu.Monitors);
return error;
}
static UINT disp_server_receive_pdu(DispServerContext* context, wStream* s)
{
UINT error = CHANNEL_RC_OK;
size_t beg, end;
DISPLAY_CONTROL_HEADER header;
beg = Stream_GetPosition(s);
if ((error = disp_read_header(s, &header)))
{
WLog_ERR(TAG, "disp_read_header failed with error %" PRIu32 "!", error);
return error;
}
switch (header.type)
{
case DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT:
if ((error = disp_recv_display_control_monitor_layout_pdu(s, context)))
WLog_ERR(TAG,
"disp_recv_display_control_monitor_layout_pdu "
"failed with error %" PRIu32 "!",
error);
break;
default:
error = CHANNEL_RC_BAD_PROC;
WLog_WARN(TAG, "Received unknown PDU type: %" PRIu32 "", header.type);
break;
}
end = Stream_GetPosition(s);
if (end != (beg + header.length))
{
WLog_ERR(TAG, "Unexpected DISP pdu end: Actual: %d, Expected: %" PRIu32 "", end,
(beg + header.length));
Stream_SetPosition(s, (beg + header.length));
}
return error;
}
static UINT disp_server_handle_messages(DispServerContext* context)
{
DWORD BytesReturned;
void* buffer;
UINT ret = CHANNEL_RC_OK;
DispServerPrivate* priv = context->priv;
wStream* s = priv->input_stream;
/* Check whether the dynamic channel is ready */
if (!priv->isReady)
{
if (WTSVirtualChannelQuery(priv->disp_channel, WTSVirtualChannelReady, &buffer,
&BytesReturned) == FALSE)
{
if (GetLastError() == ERROR_NO_DATA)
return ERROR_NO_DATA;
WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
return ERROR_INTERNAL_ERROR;
}
priv->isReady = *((BOOL*)buffer);
WTSFreeMemory(buffer);
}
/* Consume channel event only after the disp dynamic channel is ready */
Stream_SetPosition(s, 0);
if (!WTSVirtualChannelRead(priv->disp_channel, 0, NULL, 0, &BytesReturned))
{
if (GetLastError() == ERROR_NO_DATA)
return ERROR_NO_DATA;
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
return ERROR_INTERNAL_ERROR;
}
if (BytesReturned < 1)
return CHANNEL_RC_OK;
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
if (WTSVirtualChannelRead(priv->disp_channel, 0, (PCHAR)Stream_Buffer(s), Stream_Capacity(s),
&BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
return ERROR_INTERNAL_ERROR;
}
Stream_SetLength(s, BytesReturned);
Stream_SetPosition(s, 0);
while (Stream_GetPosition(s) < Stream_Length(s))
{
if ((ret = disp_server_receive_pdu(context, s)))
{
WLog_ERR(TAG,
"disp_server_receive_pdu "
"failed with error %" PRIu32 "!",
ret);
return ret;
}
}
return ret;
}
static DWORD WINAPI disp_server_thread_func(LPVOID arg)
{
DispServerContext* context = (DispServerContext*)arg;
DispServerPrivate* priv = context->priv;
DWORD status;
DWORD nCount;
HANDLE events[8];
UINT error = CHANNEL_RC_OK;
nCount = 0;
events[nCount++] = priv->stopEvent;
events[nCount++] = priv->channelEvent;
/* Main virtual channel loop. RDPEDISP do not need version negotiation */
while (TRUE)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
break;
}
/* Stop Event */
if (status == WAIT_OBJECT_0)
break;
if ((error = disp_server_handle_messages(context)))
{
WLog_ERR(TAG, "disp_server_handle_messages failed with error %" PRIu32 "", error);
break;
}
}
ExitThread(error);
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_server_open(DispServerContext* context)
{
UINT rc = ERROR_INTERNAL_ERROR;
DispServerPrivate* priv = context->priv;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
void* buffer;
buffer = NULL;
priv->SessionId = WTS_CURRENT_SESSION;
UINT32 channelId;
BOOL status = TRUE;
if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
rc = ERROR_INTERNAL_ERROR;
goto out_close;
}
priv->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
priv->disp_channel = (HANDLE)WTSVirtualChannelOpenEx(priv->SessionId, DISP_DVC_CHANNEL_NAME,
WTS_CHANNEL_OPTION_DYNAMIC);
if (!priv->disp_channel)
{
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!");
rc = GetLastError();
goto out_close;
}
channelId = WTSChannelGetIdByHandle(priv->disp_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
rc = ERROR_INTERNAL_ERROR;
goto out_close;
}
/* Query for channel event handle */
if (!WTSVirtualChannelQuery(priv->disp_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) ||
(BytesReturned != sizeof(HANDLE)))
{
WLog_ERR(TAG,
"WTSVirtualChannelQuery failed "
"or invalid returned size(%" PRIu32 ")",
BytesReturned);
if (buffer)
WTSFreeMemory(buffer);
rc = ERROR_INTERNAL_ERROR;
goto out_close;
}
CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
if (priv->thread == NULL)
{
if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
{
WLog_ERR(TAG, "CreateEvent failed!");
rc = ERROR_INTERNAL_ERROR;
}
if (!(priv->thread =
CreateThread(NULL, 0, disp_server_thread_func, (void*)context, 0, NULL)))
{
WLog_ERR(TAG, "CreateEvent failed!");
CloseHandle(priv->stopEvent);
priv->stopEvent = NULL;
rc = ERROR_INTERNAL_ERROR;
}
}
return CHANNEL_RC_OK;
out_close:
WTSVirtualChannelClose(priv->disp_channel);
priv->disp_channel = NULL;
priv->channelEvent = NULL;
return rc;
}
static UINT disp_server_packet_send(DispServerContext* context, wStream* s)
{
UINT ret;
ULONG written;
if (!WTSVirtualChannelWrite(context->priv->disp_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
ret = ERROR_INTERNAL_ERROR;
goto out;
}
if (written < Stream_GetPosition(s))
{
WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
Stream_GetPosition(s));
}
ret = CHANNEL_RC_OK;
out:
Stream_Free(s, TRUE);
return ret;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_server_send_caps_pdu(DispServerContext* context)
{
wStream* s = disp_server_single_packet_new(DISPLAY_CONTROL_PDU_TYPE_CAPS, 12);
if (!s)
{
WLog_ERR(TAG, "disp_server_single_packet_new failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write_UINT32(s, context->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */
Stream_Write_UINT32(s, context->MaxMonitorAreaFactorA); /* MaxMonitorAreaFactorA (4 bytes) */
Stream_Write_UINT32(s, context->MaxMonitorAreaFactorB); /* MaxMonitorAreaFactorB (4 bytes) */
return disp_server_packet_send(context, s);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT disp_server_close(DispServerContext* context)
{
UINT error = CHANNEL_RC_OK;
DispServerPrivate* priv = context->priv;
if (priv->thread)
{
SetEvent(priv->stopEvent);
if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
CloseHandle(priv->thread);
CloseHandle(priv->stopEvent);
priv->thread = NULL;
priv->stopEvent = NULL;
}
if (priv->disp_channel)
{
WTSVirtualChannelClose(priv->disp_channel);
priv->disp_channel = NULL;
}
return error;
}
DispServerContext* disp_server_context_new(HANDLE vcm)
{
DispServerContext* context;
DispServerPrivate* priv;
context = (DispServerContext*)calloc(1, sizeof(DispServerContext));
if (!context)
{
WLog_ERR(TAG, "disp_server_context_new(): calloc DispServerContext failed!");
goto out_free;
}
priv = context->priv = (DispServerPrivate*)calloc(1, sizeof(DispServerPrivate));
if (!context->priv)
{
WLog_ERR(TAG, "disp_server_context_new(): calloc DispServerPrivate failed!");
goto out_free;
}
priv->input_stream = Stream_New(NULL, 4);
if (!priv->input_stream)
{
WLog_ERR(TAG, "Stream_New failed!");
goto out_free_priv;
}
context->vcm = vcm;
context->Open = disp_server_open;
context->Close = disp_server_close;
context->DisplayControlCaps = disp_server_send_caps_pdu;
priv->isReady = FALSE;
return context;
out_free_priv:
free(context->priv);
out_free:
free(context);
return NULL;
}
void disp_server_context_free(DispServerContext* context)
{
if (!context)
return;
disp_server_close(context);
if (context->priv)
{
Stream_Free(context->priv->input_stream, TRUE);
free(context->priv);
}
free(context);
}

View File

@ -0,0 +1,37 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDPEDISP Virtual Channel Extension
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_DISP_SERVER_MAIN_H
#define FREERDP_CHANNEL_DISP_SERVER_MAIN_H
#include <freerdp/server/disp.h>
struct _disp_server_private
{
BOOL isReady;
wStream* input_stream;
HANDLE channelEvent;
HANDLE thread;
HANDLE stopEvent;
DWORD SessionId;
void* disp_channel;
};
#endif /* FREERDP_CHANNEL_DISP_SERVER_MAIN_H */

File diff suppressed because it is too large Load Diff

View File

@ -37,21 +37,16 @@
typedef struct drdynvc_plugin drdynvcPlugin;
#define MAX_PLUGINS 32
struct _DVCMAN
{
IWTSVirtualChannelManager iface;
drdynvcPlugin* drdynvc;
int num_plugins;
const char* plugin_names[MAX_PLUGINS];
IWTSPlugin* plugins[MAX_PLUGINS];
int num_listeners;
IWTSListener* listeners[MAX_PLUGINS];
wArrayList* plugin_names;
wArrayList* plugins;
wArrayList* listeners;
wArrayList* channels;
wStreamPool* pool;
};
@ -106,11 +101,11 @@ enum _DRDYNVC_STATE
};
typedef enum _DRDYNVC_STATE DRDYNVC_STATE;
#define CREATE_REQUEST_PDU 0x01
#define DATA_FIRST_PDU 0x02
#define DATA_PDU 0x03
#define CLOSE_REQUEST_PDU 0x04
#define CAPABILITY_REQUEST_PDU 0x05
#define CREATE_REQUEST_PDU 0x01
#define DATA_FIRST_PDU 0x02
#define DATA_PDU 0x03
#define CLOSE_REQUEST_PDU 0x04
#define CAPABILITY_REQUEST_PDU 0x05
struct drdynvc_plugin
{
@ -127,7 +122,7 @@ struct drdynvc_plugin
DRDYNVC_STATE state;
DrdynvcClientContext* context;
int version;
UINT16 version;
int PriorityCharge0;
int PriorityCharge1;
int PriorityCharge2;

View File

@ -32,7 +32,6 @@
#define TAG CHANNELS_TAG("drdynvc.server")
static DWORD WINAPI drdynvc_server_thread(LPVOID arg)
{
#if 0
@ -121,8 +120,8 @@ static DWORD WINAPI drdynvc_server_thread(LPVOID arg)
*/
static UINT drdynvc_server_start(DrdynvcServerContext* context)
{
context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm,
WTS_CURRENT_SESSION, "drdynvc");
context->priv->ChannelHandle =
WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "drdynvc");
if (!context->priv->ChannelHandle)
{
@ -136,7 +135,8 @@ static UINT drdynvc_server_start(DrdynvcServerContext* context)
return ERROR_INTERNAL_ERROR;
}
if (!(context->priv->Thread = CreateThread(NULL, 0, drdynvc_server_thread, (void*) context, 0, NULL)))
if (!(context->priv->Thread =
CreateThread(NULL, 0, drdynvc_server_thread, (void*)context, 0, NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(context->priv->StopEvent);
@ -160,7 +160,7 @@ static UINT drdynvc_server_stop(DrdynvcServerContext* context)
if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
return error;
}
@ -171,14 +171,14 @@ static UINT drdynvc_server_stop(DrdynvcServerContext* context)
DrdynvcServerContext* drdynvc_server_context_new(HANDLE vcm)
{
DrdynvcServerContext* context;
context = (DrdynvcServerContext*) calloc(1, sizeof(DrdynvcServerContext));
context = (DrdynvcServerContext*)calloc(1, sizeof(DrdynvcServerContext));
if (context)
{
context->vcm = vcm;
context->Start = drdynvc_server_start;
context->Stop = drdynvc_server_stop;
context->priv = (DrdynvcServerPrivate*) calloc(1, sizeof(DrdynvcServerPrivate));
context->priv = (DrdynvcServerPrivate*)calloc(1, sizeof(DrdynvcServerPrivate));
if (!context->priv)
{

View File

@ -46,15 +46,29 @@
#include "drive_file.h"
#ifdef WITH_DEBUG_RDPDR
#define DEBUG_WSTR(msg, wstr) do { LPSTR lpstr; ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &lpstr, 0, NULL, NULL); WLog_DBG(TAG, msg, lpstr); free(lpstr); } while (0)
#define DEBUG_WSTR(msg, wstr) \
do \
{ \
LPSTR lpstr; \
ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &lpstr, 0, NULL, NULL); \
WLog_DBG(TAG, msg, lpstr); \
free(lpstr); \
} while (0)
#else
#define DEBUG_WSTR(msg, wstr) do { } while (0)
#define DEBUG_WSTR(msg, wstr) \
do \
{ \
} while (0)
#endif
static void drive_file_fix_path(WCHAR* path)
static BOOL drive_file_fix_path(WCHAR* path, size_t length)
{
size_t i;
size_t length = _wcslen(path);
if ((length == 0) || (length > UINT32_MAX))
return FALSE;
WINPR_ASSERT(path);
for (i = 0; i < length; i++)
{
@ -65,57 +79,82 @@ static void drive_file_fix_path(WCHAR* path)
#ifdef WIN32
if ((length == 3) && (path[1] == L':') && (path[2] == L'/'))
return;
return FALSE;
#else
if ((length == 1) && (path[0] == L'/'))
return;
return FALSE;
#endif
if ((length > 0) && (path[length - 1] == L'/'))
path[length - 1] = L'\0';
return TRUE;
}
static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path,
size_t PathLength)
size_t PathWCharLength)
{
WCHAR* fullpath;
size_t base_path_length;
BOOL ok = FALSE;
WCHAR* fullpath = NULL;
size_t length;
if (!base_path || !path)
return NULL;
if (!base_path || (!path && (PathWCharLength > 0)))
goto fail;
base_path_length = _wcslen(base_path) * 2;
fullpath = (WCHAR*)calloc(1, base_path_length + PathLength + sizeof(WCHAR));
const size_t base_path_length = _wcsnlen(base_path, MAX_PATH);
length = base_path_length + PathWCharLength + 1;
fullpath = (WCHAR*)calloc(length, sizeof(WCHAR));
if (!fullpath)
goto fail;
CopyMemory(fullpath, base_path, base_path_length * sizeof(WCHAR));
if (path)
CopyMemory(&fullpath[base_path_length], path, PathWCharLength * sizeof(WCHAR));
if (!drive_file_fix_path(fullpath, length))
goto fail;
/* Ensure the path does not contain sequences like '..' */
const WCHAR dotdot[] = { '.', '.', '\0' };
if (_wcsstr(&fullpath[base_path_length], dotdot))
{
WLog_ERR(TAG, "malloc failed!");
return NULL;
char abuffer[MAX_PATH] = { 0 };
ConvertFromUnicode(CP_UTF8, 0, &fullpath[base_path_length], -1, (char**)&abuffer,
ARRAYSIZE(abuffer) - 1, NULL, NULL);
WLog_WARN(TAG, "[rdpdr] received invalid file path '%s' from server, aborting!",
&abuffer[base_path_length]);
goto fail;
}
CopyMemory(fullpath, base_path, base_path_length);
CopyMemory((char*)fullpath + base_path_length, path, PathLength);
drive_file_fix_path(fullpath);
ok = TRUE;
fail:
if (!ok)
{
free(fullpath);
fullpath = NULL;
}
return fullpath;
}
static BOOL drive_file_remove_dir(const WCHAR* path)
{
WIN32_FIND_DATAW findFileData;
WIN32_FIND_DATAW findFileData = { 0 };
BOOL ret = TRUE;
HANDLE dir;
WCHAR* fullpath;
WCHAR* path_slash;
size_t base_path_length;
HANDLE dir = INVALID_HANDLE_VALUE;
WCHAR* fullpath = NULL;
WCHAR* path_slash = NULL;
size_t base_path_length = 0;
if (!path)
return FALSE;
base_path_length = _wcslen(path) * 2;
path_slash = (WCHAR*)calloc(1, base_path_length + sizeof(WCHAR) * 3);
base_path_length = _wcslen(path);
path_slash = (WCHAR*)calloc(base_path_length + 3, sizeof(WCHAR));
if (!path_slash)
{
@ -123,12 +162,11 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
return FALSE;
}
CopyMemory(path_slash, path, base_path_length);
path_slash[base_path_length / 2] = L'/';
path_slash[base_path_length / 2 + 1] = L'*';
CopyMemory(path_slash, path, base_path_length * sizeof(WCHAR));
path_slash[base_path_length] = L'/';
path_slash[base_path_length + 1] = L'*';
DEBUG_WSTR("Search in %s", path_slash);
dir = FindFirstFileW(path_slash, &findFileData);
path_slash[base_path_length / 2 + 1] = 0;
if (dir == INVALID_HANDLE_VALUE)
{
@ -138,15 +176,15 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
do
{
size_t len = _wcslen(findFileData.cFileName);
const size_t len = _wcsnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
if ((len == 1 && findFileData.cFileName[0] == L'.') || (len == 2 &&
findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.'))
if ((len == 1 && findFileData.cFileName[0] == L'.') ||
(len == 2 && findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.'))
{
continue;
}
fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2);
fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len);
DEBUG_WSTR("Delete %s", fullpath);
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@ -162,8 +200,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
if (!ret)
break;
}
while (ret && FindNextFileW(dir, &findFileData) != 0);
} while (ret && FindNextFileW(dir, &findFileData) != 0);
FindClose(dir);
@ -238,7 +275,8 @@ static BOOL drive_file_init(DRIVE_FILE* file)
if (file->is_dir)
{
/* Should only create the directory if the disposition allows for it */
if ((file->CreateDisposition == FILE_OPEN_IF) || (file->CreateDisposition == FILE_CREATE))
if ((file->CreateDisposition == FILE_OPEN_IF) ||
(file->CreateDisposition == FILE_CREATE))
{
if (CreateDirectoryW(file->fullpath, NULL) != 0)
{
@ -255,27 +293,33 @@ static BOOL drive_file_init(DRIVE_FILE* file)
{
switch (file->CreateDisposition)
{
case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If it does not, create the given file. */
case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If
it does not, create the given file. */
CreateDisposition = CREATE_ALWAYS;
break;
case FILE_OPEN: /* If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file. */
case FILE_OPEN: /* If the file already exists, open it instead of creating a new file.
If it does not, fail the request and do not create a new file. */
CreateDisposition = OPEN_EXISTING;
break;
case FILE_CREATE: /* If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file. */
case FILE_CREATE: /* If the file already exists, fail the request and do not create or
open the given file. If it does not, create the given file. */
CreateDisposition = CREATE_NEW;
break;
case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the given file. */
case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the
given file. */
CreateDisposition = OPEN_ALWAYS;
break;
case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does not, fail the request. */
case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does
not, fail the request. */
CreateDisposition = TRUNCATE_EXISTING;
break;
case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it does not, create the given file. */
case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it
does not, create the given file. */
CreateDisposition = CREATE_ALWAYS;
break;
@ -286,11 +330,11 @@ static BOOL drive_file_init(DRIVE_FILE* file)
#ifndef WIN32
file->SharedAccess = 0;
#endif
file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess,
file->SharedAccess, NULL, CreateDisposition,
file->FileAttributes, NULL);
file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess,
NULL, CreateDisposition, file->FileAttributes, NULL);
}
#ifdef WIN32
if (file->file_handle == INVALID_HANDLE_VALUE)
{
/* Get the error message, if any. */
@ -298,31 +342,34 @@ static BOOL drive_file_init(DRIVE_FILE* file)
if (errorMessageID != 0)
{
#ifdef WIN32
LPSTR messageBuffer = NULL;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
size_t size =
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&messageBuffer, 0, NULL);
WLog_ERR(TAG, "Error in drive_file_init: %s %s", messageBuffer, file->fullpath);
/* Free the buffer. */
LocalFree(messageBuffer);
#endif
/* restore original error code */
SetLastError(errorMessageID);
}
}
#endif
return file->file_handle != INVALID_HANDLE_VALUE;
}
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id,
UINT32 DesiredAccess, UINT32 CreateDisposition,
DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength,
UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition,
UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess)
{
DRIVE_FILE* file;
if (!base_path || !path)
if (!base_path || (!path && (PathWCharLength > 0)))
return NULL;
file = (DRIVE_FILE*) calloc(1, sizeof(DRIVE_FILE));
file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE));
if (!file)
{
@ -339,11 +386,13 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat
file->CreateDisposition = CreateDisposition;
file->CreateOptions = CreateOptions;
file->SharedAccess = SharedAccess;
drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathLength));
drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathWCharLength));
if (!drive_file_init(file))
{
DWORD lastError = GetLastError();
drive_file_free(file);
SetLastError(lastError);
return NULL;
}
@ -461,15 +510,23 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w
goto out_fail;
Stream_Write_UINT32(output, 36); /* Length */
Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */
Stream_Write_UINT32(output,
fileAttributes.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output,
fileAttributes.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(output,
fileAttributes.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(
output, fileAttributes.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output,
fileAttributes.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
fileAttributes.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
fileAttributes.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output,
fileAttributes.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */
/* Reserved(4), MUST NOT be added! */
break;
@ -479,15 +536,16 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w
if (!Stream_EnsureRemainingCapacity(output, 4 + 22))
goto out_fail;
Stream_Write_UINT32(output, 22); /* Length */
Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, 22); /* Length */
Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* AllocationSize */
Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* EndOfFile */
Stream_Write_UINT32(output, 0); /* NumberOfLinks */
Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */
Stream_Write_UINT8(output, fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? TRUE :
FALSE); /* Directory */
Stream_Write_UINT32(output, 0); /* NumberOfLinks */
Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */
Stream_Write_UINT8(output, fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
? TRUE
: FALSE); /* Directory */
/* Reserved(2), MUST NOT be added! */
break;
@ -497,9 +555,9 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w
if (!Stream_EnsureRemainingCapacity(output, 4 + 8))
goto out_fail;
Stream_Write_UINT32(output, 8); /* Length */
Stream_Write_UINT32(output, 8); /* Length */
Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */
Stream_Write_UINT32(output, 0); /* ReparseTag */
Stream_Write_UINT32(output, 0); /* ReparseTag */
break;
default:
@ -556,47 +614,49 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
if (file->file_handle == INVALID_HANDLE_VALUE)
{
WLog_ERR(TAG, "Unable to set file time %s (%"PRId32")", file->fullpath, GetLastError());
WLog_ERR(TAG, "Unable to set file time %s (%" PRId32 ")", file->fullpath,
GetLastError());
return FALSE;
}
if (liCreationTime.QuadPart != 0)
{
ftCreationTime.dwHighDateTime = liCreationTime.HighPart;
ftCreationTime.dwLowDateTime = liCreationTime.LowPart;
ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart;
ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart;
pftCreationTime = &ftCreationTime;
}
if (liLastAccessTime.QuadPart != 0)
{
ftLastAccessTime.dwHighDateTime = liLastAccessTime.HighPart;
ftLastAccessTime.dwLowDateTime = liLastAccessTime.LowPart;
ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart;
ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart;
pftLastAccessTime = &ftLastAccessTime;
}
if (liLastWriteTime.QuadPart != 0)
{
ftLastWriteTime.dwHighDateTime = liLastWriteTime.HighPart;
ftLastWriteTime.dwLowDateTime = liLastWriteTime.LowPart;
ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart;
ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart;
pftLastWriteTime = &ftLastWriteTime;
}
if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
{
ftLastWriteTime.dwHighDateTime = liChangeTime.HighPart;
ftLastWriteTime.dwLowDateTime = liChangeTime.LowPart;
ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart;
ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart;
pftLastWriteTime = &ftLastWriteTime;
}
DEBUG_WSTR("SetFileTime %s", file->fullpath);
if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime))
SetFileAttributesW(file->fullpath, FileAttributes);
if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime,
pftLastWriteTime))
{
WLog_ERR(TAG, "Unable to set file time to %s", file->fullpath);
return FALSE;
}
SetFileAttributesW(file->fullpath, FileAttributes);
break;
case FileEndOfFileInformation:
@ -611,8 +671,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
if (file->file_handle == INVALID_HANDLE_VALUE)
{
WLog_ERR(TAG, "Unable to truncate %s to %"PRId64" (%"PRId32")", file->fullpath, size,
GetLastError());
WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", file->fullpath,
size, GetLastError());
return FALSE;
}
@ -620,7 +680,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN))
{
WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError());
WLog_ERR(TAG, "Unable to truncate %s to %d (%" PRId32 ")", file->fullpath, size,
GetLastError());
return FALSE;
}
@ -628,7 +689,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
if (SetEndOfFile(file->file_handle) == 0)
{
WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError());
WLog_ERR(TAG, "Unable to truncate %s to %d (%" PRId32 ")", file->fullpath, size,
GetLastError());
return FALSE;
}
@ -679,13 +741,10 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
return FALSE;
fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input),
FileNameLength);
FileNameLength / sizeof(WCHAR));
if (!fullpath)
{
WLog_ERR(TAG, "drive_file_combine_fullpath failed!");
return FALSE;
}
#ifdef _WIN32
@ -699,7 +758,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
DEBUG_WSTR("MoveFileExW %s", file->fullpath);
if (MoveFileExW(file->fullpath, fullpath,
MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
MOVEFILE_COPY_ALLOWED |
(ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0)))
{
if (!drive_file_set_fullpath(file, fullpath))
return FALSE;
@ -723,7 +783,7 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
}
BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery,
const WCHAR* path, UINT32 PathLength, wStream* output)
const WCHAR* path, UINT32 PathWCharLength, wStream* output)
{
size_t length;
WCHAR* ent_path;
@ -737,7 +797,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
if (file->find_handle != INVALID_HANDLE_VALUE)
FindClose(file->find_handle);
ent_path = drive_file_combine_fullpath(file->basepath, path, PathLength);
ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength);
/* open new search handle and retrieve the first entry */
file->find_handle = FindFirstFileW(ent_path, &file->find_data);
free(ent_path);
@ -762,22 +822,30 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
goto out_fail;
Stream_Write_UINT32(output, (UINT32)(64 + length)); /* Length */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output,
file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output,
file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(
output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(
output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write(output, file->find_data.cFileName, length);
break;
@ -791,23 +859,31 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
goto out_fail;
Stream_Write_UINT32(output, (UINT32)(68 + length)); /* Length */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output,
file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output,
file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(
output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(
output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write_UINT32(output, 0); /* EaSize */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write_UINT32(output, 0); /* EaSize */
Stream_Write(output, file->find_data.cFileName, length);
break;
@ -821,24 +897,32 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
goto out_fail;
Stream_Write_UINT32(output, (UINT32)(93 + length)); /* Length */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output,
file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
Stream_Write_UINT32(output,
file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
Stream_Write_UINT32(
output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
Stream_Write_UINT32(
output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
Stream_Write_UINT32(output,
file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write_UINT32(output, 0); /* EaSize */
Stream_Write_UINT8(output, 0); /* ShortNameLength */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write_UINT32(output, 0); /* EaSize */
Stream_Write_UINT8(output, 0); /* ShortNameLength */
/* Reserved(1), MUST NOT be added! */
Stream_Zero(output, 24); /* ShortName */
Stream_Write(output, file->find_data.cFileName, length);
@ -854,14 +938,14 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
goto out_fail;
Stream_Write_UINT32(output, (UINT32)(12 + length)); /* Length */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
Stream_Write_UINT32(output, 0); /* FileIndex */
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
Stream_Write(output, file->find_data.cFileName, length);
break;
default:
WLog_ERR(TAG, "unhandled FsInformationClass %"PRIu32, FsInformationClass);
WLog_ERR(TAG, "unhandled FsInformationClass %" PRIu32, FsInformationClass);
/* Unhandled FsInformationClass */
goto out_fail;
}
@ -869,6 +953,6 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
return TRUE;
out_fail:
Stream_Write_UINT32(output, 0); /* Length */
Stream_Write_UINT8(output, 0); /* Padding */
Stream_Write_UINT8(output, 0); /* Padding */
return FALSE;
}

View File

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

View File

@ -102,7 +102,7 @@ static DWORD drive_map_windows_err(DWORD fs_errno)
case ERROR_FILE_EXISTS:
case ERROR_ALREADY_EXISTS:
rc = STATUS_OBJECT_NAME_COLLISION;
rc = STATUS_OBJECT_NAME_COLLISION;
break;
case ERROR_INVALID_NAME:
@ -127,7 +127,7 @@ static DWORD drive_map_windows_err(DWORD fs_errno)
default:
rc = STATUS_UNSUCCESSFUL;
WLog_ERR(TAG, "Error code not found: %"PRIu32"", fs_errno);
WLog_ERR(TAG, "Error code not found: %" PRIu32 "", fs_errno);
break;
}
@ -137,12 +137,12 @@ static DWORD drive_map_windows_err(DWORD fs_errno)
static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id)
{
DRIVE_FILE* file = NULL;
void* key = (void*)(size_t) id;
void* key = (void*)(size_t)id;
if (!drive)
return NULL;
file = (DRIVE_FILE*) ListDictionary_GetItemValue(drive->files, key);
file = (DRIVE_FILE*)ListDictionary_GetItemValue(drive->files, key);
return file;
}
@ -182,10 +182,10 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
if (Stream_GetRemainingLength(irp->input) < PathLength)
return ERROR_INVALID_DATA;
path = (WCHAR*) Stream_Pointer(irp->input);
path = (const WCHAR*)Stream_Pointer(irp->input);
FileId = irp->devman->id_sequence++;
file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition,
CreateOptions, FileAttributes, SharedAccess);
file = drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess,
CreateDisposition, CreateOptions, FileAttributes, SharedAccess);
if (!file)
{
@ -195,7 +195,7 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
}
else
{
void* key = (void*)(size_t) file->id;
void* key = (void*)(size_t)file->id;
if (!ListDictionary_Add(drive->files, key, file))
{
@ -245,7 +245,7 @@ static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
return ERROR_INVALID_PARAMETER;
file = drive_get_file_by_id(drive, irp->FileId);
key = (void*)(size_t) irp->FileId;
key = (void*)(size_t)irp->FileId;
if (!file)
irp->IoStatus = STATUS_UNSUCCESSFUL;
@ -331,6 +331,7 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
DRIVE_FILE* file;
UINT32 Length;
UINT64 Offset;
void* ptr;
if (!drive || !irp || !irp->input || !irp->output || !irp->Complete)
return ERROR_INVALID_PARAMETER;
@ -341,6 +342,9 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
Stream_Read_UINT32(irp->input, Length);
Stream_Read_UINT64(irp->input, Offset);
Stream_Seek(irp->input, 20); /* Padding */
ptr = Stream_Pointer(irp->input);
if (!Stream_SafeSeek(irp->input, Length))
return ERROR_INVALID_DATA;
file = drive_get_file_by_id(drive, irp->FileId);
if (!file)
@ -353,7 +357,7 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
irp->IoStatus = drive_map_windows_err(GetLastError());
Length = 0;
}
else if (!drive_file_write(file, Stream_Pointer(irp->input), Length))
else if (!drive_file_write(file, ptr, Length))
{
irp->IoStatus = drive_map_windows_err(GetLastError());
Length = 0;
@ -421,8 +425,7 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
}
else if (!drive_file_set_information(file, FsInformationClass, Length,
irp->input))
else if (!drive_file_set_information(file, FsInformationClass, Length, irp->input))
{
irp->IoStatus = drive_map_windows_err(GetLastError());
}
@ -434,19 +437,17 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
return irp->Complete(irp);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
IRP* irp)
static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP* irp)
{
UINT32 FsInformationClass;
wStream* output = NULL;
char* volumeLabel = {"FREERDP"};
char* diskType = {"FAT32"};
char* volumeLabel = { "FREERDP" };
char* diskType = { "FAT32" };
WCHAR* outStr = NULL;
int length;
DWORD lpSectorsPerCluster;
@ -489,10 +490,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad);
Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime); /* VolumeCreationTime */
Stream_Write_UINT32(output, wfad.ftCreationTime.dwHighDateTime); /* VolumeCreationTime */
Stream_Write_UINT32(output,
wfad.ftCreationTime.dwHighDateTime); /* VolumeCreationTime */
Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff); /* VolumeSerialNumber */
Stream_Write_UINT32(output, length); /* VolumeLabelLength */
Stream_Write_UINT8(output, 0); /* SupportsObjects */
Stream_Write_UINT32(output, length); /* VolumeLabelLength */
Stream_Write_UINT8(output, 0); /* SupportsObjects */
/* Reserved(1), MUST NOT be added! */
Stream_Write(output, outStr, length); /* VolumeLabel (Unicode) */
free(outStr);
@ -509,9 +511,9 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
}
Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
break;
case FileFsAttributeInformation:
@ -532,13 +534,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write_UINT32(output,
FILE_CASE_SENSITIVE_SEARCH |
FILE_CASE_PRESERVED_NAMES |
FILE_UNICODE_ON_DISK); /* FileSystemAttributes */
Stream_Write_UINT32(output, MAX_PATH); /* MaximumComponentNameLength */
Stream_Write_UINT32(output, length); /* FileSystemNameLength */
Stream_Write(output, outStr, length); /* FileSystemName (Unicode) */
Stream_Write_UINT32(output, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
FILE_UNICODE_ON_DISK); /* FileSystemAttributes */
Stream_Write_UINT32(output, MAX_PATH); /* MaximumComponentNameLength */
Stream_Write_UINT32(output, length); /* FileSystemNameLength */
Stream_Write(output, outStr, length); /* FileSystemName (Unicode) */
free(outStr);
break;
@ -553,10 +553,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
}
Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */
Stream_Write_UINT64(output,
lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */
Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */
Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */
break;
case FileFsDeviceInformation:
@ -570,7 +571,7 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive,
}
Stream_Write_UINT32(output, FILE_DEVICE_DISK); /* DeviceType */
Stream_Write_UINT32(output, 0); /* Characteristics */
Stream_Write_UINT32(output, 0); /* Characteristics */
break;
default:
@ -627,7 +628,10 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
Stream_Read_UINT8(irp->input, InitialQuery);
Stream_Read_UINT32(irp->input, PathLength);
Stream_Seek(irp->input, 23); /* Padding */
path = (WCHAR*) Stream_Pointer(irp->input);
path = (WCHAR*)Stream_Pointer(irp->input);
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength))
return ERROR_INVALID_DATA;
file = drive_get_file_by_id(drive, irp->FileId);
if (file == NULL)
@ -635,8 +639,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
irp->IoStatus = STATUS_UNSUCCESSFUL;
Stream_Write_UINT32(irp->output, 0); /* Length */
}
else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength,
irp->output))
else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path,
PathLength / sizeof(WCHAR), irp->output))
{
irp->IoStatus = drive_map_windows_err(GetLastError());
}
@ -754,7 +758,7 @@ static DWORD WINAPI drive_thread_func(LPVOID arg)
{
IRP* irp;
wMessage message;
DRIVE_DEVICE* drive = (DRIVE_DEVICE*) arg;
DRIVE_DEVICE* drive = (DRIVE_DEVICE*)arg;
UINT error = CHANNEL_RC_OK;
if (!drive)
@ -782,13 +786,13 @@ static DWORD WINAPI drive_thread_func(LPVOID arg)
if (message.id == WMQ_QUIT)
break;
irp = (IRP*) message.wParam;
irp = (IRP*)message.wParam;
if (irp)
{
if ((error = drive_process_irp(drive, irp)))
{
WLog_ERR(TAG, "drive_process_irp failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "drive_process_irp failed with error %" PRIu32 "!", error);
break;
}
}
@ -810,12 +814,12 @@ fail:
*/
static UINT drive_irp_request(DEVICE* device, IRP* irp)
{
DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device;
DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
if (!drive)
return ERROR_INVALID_PARAMETER;
if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*) irp, NULL))
if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*)irp, NULL))
{
WLog_ERR(TAG, "MessageQueue_Post failed!");
return ERROR_INTERNAL_ERROR;
@ -847,17 +851,17 @@ static UINT drive_free_int(DRIVE_DEVICE* drive)
*/
static UINT drive_free(DEVICE* device)
{
DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device;
DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
UINT error = CHANNEL_RC_OK;
if (!drive)
return ERROR_INVALID_PARAMETER;
if (MessageQueue_PostQuit(drive->IrpQueue, 0)
&& (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
if (MessageQueue_PostQuit(drive->IrpQueue, 0) &&
(WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
@ -869,7 +873,7 @@ static UINT drive_free(DEVICE* device)
*/
static void drive_file_objfree(void* obj)
{
drive_file_free((DRIVE_FILE*) obj);
drive_file_free((DRIVE_FILE*)obj);
}
/**
@ -877,17 +881,24 @@ static void drive_file_objfree(void* obj)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
const char* name, const char* path, BOOL automount)
static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, const char* name,
const char* path, BOOL automount)
{
size_t i, length;
DRIVE_DEVICE* drive;
UINT error;
UINT error = ERROR_INTERNAL_ERROR;
if (!pEntryPoints || !name || !path)
{
WLog_ERR(TAG, "[%s] Invalid parameters: pEntryPoints=%p, name=%p, path=%p", pEntryPoints,
name, path);
return ERROR_INVALID_PARAMETER;
}
if (name[0] && path[0])
{
size_t pathLength = strnlen(path, MAX_PATH);
drive = (DRIVE_DEVICE*) calloc(1, sizeof(DRIVE_DEVICE));
drive = (DRIVE_DEVICE*)calloc(1, sizeof(DRIVE_DEVICE));
if (!drive)
{
@ -896,7 +907,6 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
}
drive->device.type = RDPDR_DTYP_FILESYSTEM;
drive->device.name = name;
drive->device.IRPRequest = drive_irp_request;
drive->device.Free = drive_free;
drive->rdpcontext = pEntryPoints->rdpcontext;
@ -911,11 +921,34 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
goto out_error;
}
for (i = 0; i <= length; i++)
Stream_Write_UINT8(drive->device.data, name[i] < 0 ? '_' : name[i]);
for (i = 0; i < length; i++)
{
/* Filter 2.2.1.3 Device Announce Header (DEVICE_ANNOUNCE) forbidden symbols */
switch (name[i])
{
case ':':
case '<':
case '>':
case '\"':
case '/':
case '\\':
case '|':
case ' ':
Stream_Write_UINT8(drive->device.data, '_');
break;
default:
Stream_Write_UINT8(drive->device.data, (BYTE)name[i]);
break;
}
}
Stream_Write_UINT8(drive->device.data, '\0');
drive->device.name = (const char*)Stream_Buffer(drive->device.data);
if (!drive->device.name)
goto out_error;
if ((pathLength > 1) && (path[pathLength - 1] == '/'))
pathLength --;
pathLength--;
if (ConvertToUnicode(sys_code_page, 0, path, pathLength, &drive->path, 0) <= 0)
{
@ -943,15 +976,14 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
goto out_error;
}
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman,
(DEVICE*) drive)))
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)drive)))
{
WLog_ERR(TAG, "RegisterDevice failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
goto out_error;
}
if (!(drive->thread = CreateThread(NULL, 0, drive_thread_func, drive,
CREATE_SUSPENDED, NULL)))
if (!(drive->thread =
CreateThread(NULL, 0, drive_thread_func, drive, CREATE_SUSPENDED, NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
goto out_error;
@ -967,9 +999,9 @@ out_error:
}
#ifdef BUILTIN_CHANNELS
#define DeviceServiceEntry drive_DeviceServiceEntry
#define DeviceServiceEntry drive_DeviceServiceEntry
#else
#define DeviceServiceEntry FREERDP_API DeviceServiceEntry
#define DeviceServiceEntry FREERDP_API DeviceServiceEntry
#endif
/**
@ -988,7 +1020,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
char* bufdup;
char* devdup;
#endif
drive = (RDPDR_DRIVE*) pEntryPoints->device;
drive = (RDPDR_DRIVE*)pEntryPoints->device;
#ifndef WIN32
sys_code_page = CP_UTF8;

View File

@ -31,6 +31,7 @@
#include "echo_main.h"
#include <freerdp/channels/log.h>
#include <freerdp/channels/echo.h>
#define TAG CHANNELS_TAG("echo.client")
@ -59,6 +60,8 @@ struct _ECHO_PLUGIN
IWTSPlugin iface;
ECHO_LISTENER_CALLBACK* listener_callback;
IWTSListener* listener;
BOOL initialized;
};
/**
@ -66,9 +69,9 @@ struct _ECHO_PLUGIN
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
{
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*)pChannelCallback;
BYTE* pBuffer = Stream_Pointer(data);
UINT32 cbSize = Stream_GetRemainingLength(data);
@ -83,7 +86,7 @@ static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
*/
static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*)pChannelCallback;
free(callback);
@ -96,13 +99,13 @@ static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback)
* @return 0 on success, otherwise a Win32 error code
*/
static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
ECHO_CHANNEL_CALLBACK* callback;
ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*) pListenerCallback;
ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*)pListenerCallback;
callback = (ECHO_CHANNEL_CALLBACK*) calloc(1, sizeof(ECHO_CHANNEL_CALLBACK));
callback = (ECHO_CHANNEL_CALLBACK*)calloc(1, sizeof(ECHO_CHANNEL_CALLBACK));
if (!callback)
{
@ -116,7 +119,7 @@ static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallba
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
*ppCallback = (IWTSVirtualChannelCallback*) callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
@ -128,9 +131,14 @@ static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallba
*/
static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin;
echo->listener_callback = (ECHO_LISTENER_CALLBACK*) calloc(1, sizeof(ECHO_LISTENER_CALLBACK));
UINT status;
ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin;
if (echo->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", ECHO_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
echo->listener_callback = (ECHO_LISTENER_CALLBACK*)calloc(1, sizeof(ECHO_LISTENER_CALLBACK));
if (!echo->listener_callback)
{
@ -142,8 +150,11 @@ static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage
echo->listener_callback->plugin = pPlugin;
echo->listener_callback->channel_mgr = pChannelMgr;
return pChannelMgr->CreateListener(pChannelMgr, "ECHO", 0,
(IWTSListenerCallback*) echo->listener_callback, NULL);
status = pChannelMgr->CreateListener(pChannelMgr, ECHO_DVC_CHANNEL_NAME, 0,
&echo->listener_callback->iface, &echo->listener);
echo->initialized = status == CHANNEL_RC_OK;
return status;
}
/**
@ -153,17 +164,22 @@ static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage
*/
static UINT echo_plugin_terminated(IWTSPlugin* pPlugin)
{
ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin;
ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin;
if (echo && echo->listener_callback)
{
IWTSVirtualChannelManager* mgr = echo->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, echo->listener);
}
free(echo);
return CHANNEL_RC_OK;
}
#ifdef BUILTIN_CHANNELS
#define DVCPluginEntry echo_DVCPluginEntry
#define DVCPluginEntry echo_DVCPluginEntry
#else
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#endif
/**
@ -176,11 +192,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
UINT status = CHANNEL_RC_OK;
ECHO_PLUGIN* echo;
echo = (ECHO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "echo");
echo = (ECHO_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "echo");
if (!echo)
{
echo = (ECHO_PLUGIN*) calloc(1, sizeof(ECHO_PLUGIN));
echo = (ECHO_PLUGIN*)calloc(1, sizeof(ECHO_PLUGIN));
if (!echo)
{
@ -193,7 +209,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
echo->iface.Disconnected = NULL;
echo->iface.Terminated = echo_plugin_terminated;
status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo);
status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*)echo);
}
return status;

View File

@ -33,8 +33,10 @@
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__)
#else
#define DEBUG_DVC(...) do { } while (0)
#define DEBUG_DVC(...) \
do \
{ \
} while (0)
#endif
#endif /* FREERDP_CHANNEL_ECHO_CLIENT_MAIN_H */

View File

@ -66,14 +66,14 @@ static UINT echo_server_open_channel(echo_server* echo)
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION,
WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned) == FALSE)
if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
echo->SessionId = (DWORD) * pSessionId;
echo->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(echo->context.vcm);
StartTick = GetTickCount();
@ -83,15 +83,29 @@ static UINT echo_server_open_channel(echo_server* echo)
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
{
Error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", Error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
return Error;
}
echo->echo_channel = WTSVirtualChannelOpenEx(echo->SessionId,
"ECHO", WTS_CHANNEL_OPTION_DYNAMIC);
echo->echo_channel =
WTSVirtualChannelOpenEx(echo->SessionId, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC);
if (echo->echo_channel)
{
UINT32 channelId;
BOOL status = TRUE;
channelId = WTSChannelGetIdByHandle(echo->echo_channel);
IFCALLRET(echo->context.ChannelIdAssigned, status, &echo->context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
break;
}
Error = GetLastError();
@ -114,19 +128,19 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg)
BOOL ready = FALSE;
HANDLE ChannelEvent;
DWORD BytesReturned = 0;
echo_server* echo = (echo_server*) arg;
echo_server* echo = (echo_server*)arg;
UINT error;
DWORD status;
if ((error = echo_server_open_channel(echo)))
{
UINT error2 = 0;
WLog_ERR(TAG, "echo_server_open_channel failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "echo_server_open_channel failed with error %" PRIu32 "!", error);
IFCALLRET(echo->context.OpenResult, error2, &echo->context,
ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED);
if (error2)
WLog_ERR(TAG, "echo server's OpenResult callback failed with error %"PRIu32"",
WLog_ERR(TAG, "echo server's OpenResult callback failed with error %" PRIu32 "",
error2);
goto out;
@ -158,7 +172,7 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg)
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
break;
}
@ -168,7 +182,7 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg)
ECHO_SERVER_OPEN_RESULT_CLOSED);
if (error)
WLog_ERR(TAG, "OpenResult failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error);
break;
}
@ -180,21 +194,20 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg)
ECHO_SERVER_OPEN_RESULT_ERROR);
if (error)
WLog_ERR(TAG, "OpenResult failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error);
break;
}
ready = *((BOOL*) buffer);
ready = *((BOOL*)buffer);
WTSFreeMemory(buffer);
if (ready)
{
IFCALLRET(echo->context.OpenResult, error, &echo->context,
ECHO_SERVER_OPEN_RESULT_OK);
IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_OK);
if (error)
WLog_ERR(TAG, "OpenResult failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error);
break;
}
@ -217,7 +230,7 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg)
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
break;
}
@ -237,20 +250,20 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg)
break;
}
if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR) Stream_Buffer(s),
(ULONG) Stream_Capacity(s), &BytesReturned) == FALSE)
if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
error = ERROR_INTERNAL_ERROR;
break;
}
IFCALLRET(echo->context.Response, error, &echo->context,
(BYTE*) Stream_Buffer(s), BytesReturned);
IFCALLRET(echo->context.Response, error, &echo->context, (BYTE*)Stream_Buffer(s),
BytesReturned);
if (error)
{
WLog_ERR(TAG, "Response failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
break;
}
}
@ -275,7 +288,7 @@ out:
*/
static UINT echo_server_open(echo_server_context* context)
{
echo_server* echo = (echo_server*) context;
echo_server* echo = (echo_server*)context;
if (echo->thread == NULL)
{
@ -285,7 +298,7 @@ static UINT echo_server_open(echo_server_context* context)
return ERROR_INTERNAL_ERROR;
}
if (!(echo->thread = CreateThread(NULL, 0, echo_server_thread_func, (void*) echo, 0, NULL)))
if (!(echo->thread = CreateThread(NULL, 0, echo_server_thread_func, (void*)echo, 0, NULL)))
{
WLog_ERR(TAG, "CreateEvent failed!");
CloseHandle(echo->stopEvent);
@ -305,7 +318,7 @@ static UINT echo_server_open(echo_server_context* context)
static UINT echo_server_close(echo_server_context* context)
{
UINT error = CHANNEL_RC_OK;
echo_server* echo = (echo_server*) context;
echo_server* echo = (echo_server*)context;
if (echo->thread)
{
@ -314,7 +327,7 @@ static UINT echo_server_close(echo_server_context* context)
if (WaitForSingleObject(echo->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
@ -327,17 +340,16 @@ static UINT echo_server_close(echo_server_context* context)
return error;
}
static BOOL echo_server_request(echo_server_context* context,
const BYTE* buffer, UINT32 length)
static BOOL echo_server_request(echo_server_context* context, const BYTE* buffer, UINT32 length)
{
echo_server* echo = (echo_server*) context;
return WTSVirtualChannelWrite(echo->echo_channel, (PCHAR) buffer, length, NULL);
echo_server* echo = (echo_server*)context;
return WTSVirtualChannelWrite(echo->echo_channel, (PCHAR)buffer, length, NULL);
}
echo_server_context* echo_server_context_new(HANDLE vcm)
{
echo_server* echo;
echo = (echo_server*) calloc(1, sizeof(echo_server));
echo = (echo_server*)calloc(1, sizeof(echo_server));
if (echo)
{
@ -349,12 +361,12 @@ echo_server_context* echo_server_context_new(HANDLE vcm)
else
WLog_ERR(TAG, "calloc failed!");
return (echo_server_context*) echo;
return (echo_server_context*)echo;
}
void echo_server_context_free(echo_server_context* context)
{
echo_server* echo = (echo_server*) context;
echo_server* echo = (echo_server*)context;
echo_server_close(context);
free(echo);
}

File diff suppressed because it is too large Load Diff

View File

@ -37,20 +37,6 @@
#define TAG CHANNELS_TAG("encomsp.client")
struct encomsp_plugin
{
CHANNEL_DEF channelDef;
CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints;
EncomspClientContext* context;
HANDLE thread;
wStream* data_in;
void* InitHandle;
DWORD OpenHandle;
wMessageQueue* queue;
rdpContext* rdpcontext;
};
typedef struct encomsp_plugin encomspPlugin;
#endif /* FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H */

View File

@ -43,7 +43,7 @@ static UINT encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header)
if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE)
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */
Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */
return CHANNEL_RC_OK;
}
@ -83,13 +83,14 @@ static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT encomsp_recv_change_participant_control_level_pdu(
EncomspServerContext* context, wStream* s, ENCOMSP_ORDER_HEADER* header)
static UINT encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context,
wStream* s,
ENCOMSP_ORDER_HEADER* header)
{
int beg, end;
ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu;
UINT error = CHANNEL_RC_OK;
beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
beg = ((int)Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE;
CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER));
if (Stream_GetRemainingLength(s) < 6)
@ -98,9 +99,9 @@ static UINT encomsp_recv_change_participant_control_level_pdu(
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */
Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */
end = (int) Stream_GetPosition(s);
end = (int)Stream_GetPosition(s);
if ((beg + header->Length) < end)
{
@ -110,7 +111,7 @@ static UINT encomsp_recv_change_participant_control_level_pdu(
if ((beg + header->Length) > end)
{
if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end))
if (Stream_GetRemainingLength(s) < (size_t)((beg + header->Length) - end))
{
WLog_ERR(TAG, "Not enough data!");
return ERROR_INVALID_DATA;
@ -122,7 +123,7 @@ static UINT encomsp_recv_change_participant_control_level_pdu(
IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %"PRIu32"",
WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "",
error);
return error;
@ -133,8 +134,7 @@ static UINT encomsp_recv_change_participant_control_level_pdu(
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT encomsp_server_receive_pdu(EncomspServerContext* context,
wStream* s)
static UINT encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s)
{
UINT error = CHANNEL_RC_OK;
ENCOMSP_ORDER_HEADER header;
@ -143,21 +143,22 @@ static UINT encomsp_server_receive_pdu(EncomspServerContext* context,
{
if ((error = encomsp_read_header(s, &header)))
{
WLog_ERR(TAG, "encomsp_read_header failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error);
return error;
}
WLog_INFO(TAG, "EncomspReceive: Type: %"PRIu16" Length: %"PRIu16"", header.Type,
WLog_INFO(TAG, "EncomspReceive: Type: %" PRIu16 " Length: %" PRIu16 "", header.Type,
header.Length);
switch (header.Type)
{
case ODTYPE_PARTICIPANT_CTRL_CHANGED:
if ((error = encomsp_recv_change_participant_control_level_pdu(context, s,
&header)))
if ((error =
encomsp_recv_change_participant_control_level_pdu(context, s, &header)))
{
WLog_ERR(TAG,
"encomsp_recv_change_participant_control_level_pdu failed with error %"PRIu32"!",
"encomsp_recv_change_participant_control_level_pdu failed with error "
"%" PRIu32 "!",
error);
return error;
}
@ -165,7 +166,7 @@ static UINT encomsp_server_receive_pdu(EncomspServerContext* context,
break;
default:
WLog_ERR(TAG, "header.Type unknown %"PRIu16"!", header.Type);
WLog_ERR(TAG, "header.Type unknown %" PRIu16 "!", header.Type);
return ERROR_INVALID_DATA;
break;
}
@ -186,7 +187,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
EncomspServerContext* context;
UINT error = CHANNEL_RC_OK;
DWORD status;
context = (EncomspServerContext*) arg;
context = (EncomspServerContext*)arg;
buffer = NULL;
BytesReturned = 0;
@ -200,8 +201,8 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
goto out;
}
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle,
&buffer, &BytesReturned) == TRUE)
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
&BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
@ -220,7 +221,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
break;
}
@ -229,7 +230,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
if (status == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
break;
}
@ -250,8 +251,8 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
break;
}
if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0,
(PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned))
if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s),
Stream_Capacity(s), &BytesReturned))
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
error = ERROR_INTERNAL_ERROR;
@ -260,7 +261,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE)
{
header = (ENCOMSP_ORDER_HEADER*) Stream_Buffer(s);
header = (ENCOMSP_ORDER_HEADER*)Stream_Buffer(s);
if (header->Length >= Stream_GetPosition(s))
{
@ -269,7 +270,8 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
if ((error = encomsp_server_receive_pdu(context, s)))
{
WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %" PRIu32 "!",
error);
break;
}
@ -282,8 +284,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg)
out:
if (error && context->rdpcontext)
setChannelError(context->rdpcontext, error,
"encomsp_server_thread reported an error");
setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error");
ExitThread(error);
return error;
@ -296,8 +297,8 @@ out:
*/
static UINT encomsp_server_start(EncomspServerContext* context)
{
context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm,
WTS_CURRENT_SESSION, "encomsp");
context->priv->ChannelHandle =
WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "encomsp");
if (!context->priv->ChannelHandle)
return CHANNEL_RC_BAD_CHANNEL;
@ -308,8 +309,8 @@ static UINT encomsp_server_start(EncomspServerContext* context)
return ERROR_INTERNAL_ERROR;
}
if (!(context->priv->Thread = CreateThread(NULL, 0,
encomsp_server_thread, (void*) context, 0, NULL)))
if (!(context->priv->Thread =
CreateThread(NULL, 0, encomsp_server_thread, (void*)context, 0, NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(context->priv->StopEvent);
@ -333,7 +334,7 @@ static UINT encomsp_server_stop(EncomspServerContext* context)
if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
@ -345,14 +346,14 @@ static UINT encomsp_server_stop(EncomspServerContext* context)
EncomspServerContext* encomsp_server_context_new(HANDLE vcm)
{
EncomspServerContext* context;
context = (EncomspServerContext*) calloc(1, sizeof(EncomspServerContext));
context = (EncomspServerContext*)calloc(1, sizeof(EncomspServerContext));
if (context)
{
context->vcm = vcm;
context->Start = encomsp_server_start;
context->Stop = encomsp_server_stop;
context->priv = (EncomspServerPrivate*) calloc(1, sizeof(EncomspServerPrivate));
context->priv = (EncomspServerPrivate*)calloc(1, sizeof(EncomspServerPrivate));
if (!context->priv)
{
@ -371,7 +372,7 @@ void encomsp_server_context_free(EncomspServerContext* context)
{
if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE)
WTSVirtualChannelClose(context->priv->ChannelHandle);
free(context->priv);
free(context);
}

View File

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

View File

@ -27,7 +27,6 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/interlocked.h>
#include <winpr/print.h>
#include <winpr/stream.h>
#include <winpr/cmdline.h>
@ -69,47 +68,30 @@ struct _GEOMETRY_PLUGIN
GEOMETRY_LISTENER_CALLBACK* listener_callback;
GeometryClientContext* context;
BOOL initialized;
};
typedef struct _GEOMETRY_PLUGIN GEOMETRY_PLUGIN;
static UINT32 mappedGeometryHash(UINT64 *g)
static UINT32 mappedGeometryHash(UINT64* g)
{
return (UINT32)((*g >> 32) + (*g & 0xffffffff));
}
static BOOL mappedGeometryKeyCompare(UINT64 *g1, UINT64 *g2)
static BOOL mappedGeometryKeyCompare(UINT64* g1, UINT64* g2)
{
return *g1 == *g2;
}
void mappedGeometryRef(MAPPED_GEOMETRY *g)
{
InterlockedIncrement(&g->refCounter);
}
void mappedGeometryUnref(MAPPED_GEOMETRY *g)
{
if (InterlockedDecrement(&g->refCounter))
return;
g->MappedGeometryUpdate = NULL;
g->MappedGeometryClear = NULL;
g->custom = NULL;
free(g->geometry.rects);
free(g);
}
void freerdp_rgndata_reset(FREERDP_RGNDATA *data)
static void freerdp_rgndata_reset(FREERDP_RGNDATA* data)
{
data->nRectCount = 0;
}
static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgndata)
static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgndata)
{
UINT32 dwSize, iType;
INT32 right, bottom;
INT32 x, y, w, h;
if (len < 32)
{
@ -129,18 +111,26 @@ static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgn
if (iType != RDH_RECTANGLE)
{
WLog_ERR(TAG, "iType %"PRIu32" for RGNDATA is not supported", iType);
WLog_ERR(TAG, "iType %" PRIu32 " for RGNDATA is not supported", iType);
return ERROR_UNSUPPORTED_TYPE;
}
Stream_Read_UINT32(s, rgndata->nRectCount);
Stream_Seek_UINT32(s); /* nRgnSize IGNORED */
Stream_Read_INT32(s, rgndata->boundingRect.x);
Stream_Read_INT32(s, rgndata->boundingRect.y);
Stream_Read_INT32(s, x);
Stream_Read_INT32(s, y);
Stream_Read_INT32(s, right);
Stream_Read_INT32(s, bottom);
rgndata->boundingRect.width = right - rgndata->boundingRect.x;
rgndata->boundingRect.height = bottom - rgndata->boundingRect.y;
if ((abs(x) > INT16_MAX) || (abs(y) > INT16_MAX))
return ERROR_INVALID_DATA;
w = right - x;
h = bottom - y;
if ((abs(w) > INT16_MAX) || (abs(h) > INT16_MAX))
return ERROR_INVALID_DATA;
rgndata->boundingRect.x = (INT16)x;
rgndata->boundingRect.y = (INT16)y;
rgndata->boundingRect.width = (INT16)w;
rgndata->boundingRect.height = (INT16)h;
len -= 32;
if (len / (4 * 4) < rgndata->nRectCount)
@ -150,24 +140,32 @@ static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgn
if (rgndata->nRectCount)
{
int i;
RDP_RECT *tmp = realloc(rgndata->rects, rgndata->nRectCount * sizeof(RDP_RECT));
UINT32 i;
RDP_RECT* tmp = realloc(rgndata->rects, rgndata->nRectCount * sizeof(RDP_RECT));
if (!tmp)
{
WLog_ERR(TAG, "unable to allocate memory for %"PRIu32" RECTs", rgndata->nRectCount);
WLog_ERR(TAG, "unable to allocate memory for %" PRIu32 " RECTs", rgndata->nRectCount);
return CHANNEL_RC_NO_MEMORY;
}
rgndata->rects = tmp;
for (i = 0; i < rgndata->nRectCount; i++)
{
Stream_Read_INT32(s, rgndata->rects[i].x);
Stream_Read_INT32(s, rgndata->rects[i].y);
Stream_Read_INT32(s, x);
Stream_Read_INT32(s, y);
Stream_Read_INT32(s, right);
Stream_Read_INT32(s, bottom);
rgndata->rects[i].width = right - rgndata->rects[i].x;
rgndata->rects[i].height = bottom - rgndata->rects[i].y;
if ((abs(x) > INT16_MAX) || (abs(y) > INT16_MAX))
return ERROR_INVALID_DATA;
w = right - x;
h = bottom - y;
if ((abs(w) > INT16_MAX) || (abs(h) > INT16_MAX))
return ERROR_INVALID_DATA;
rgndata->rects[i].x = (INT16)x;
rgndata->rects[i].y = (INT16)y;
rgndata->rects[i].width = (INT16)w;
rgndata->rects[i].height = (INT16)h;
}
}
@ -182,14 +180,14 @@ static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgn
static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
{
UINT32 length, cbGeometryBuffer;
MAPPED_GEOMETRY *mappedGeometry;
MAPPED_GEOMETRY* mappedGeometry;
GEOMETRY_PLUGIN* geometry;
GeometryClientContext *context;
GeometryClientContext* context;
UINT ret = CHANNEL_RC_OK;
UINT32 version, updateType, geometryType;
UINT64 id;
geometry = (GEOMETRY_PLUGIN*) callback->plugin;
geometry = (GEOMETRY_PLUGIN*)callback->plugin;
context = (GeometryClientContext*)geometry->iface.pInterface;
if (Stream_GetRemainingLength(s) < 4)
@ -213,17 +211,18 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
mappedGeometry = HashTable_GetItemValue(context->geometries, &id);
if (updateType == GEOMETRY_CLEAR )
if (updateType == GEOMETRY_CLEAR)
{
if (!mappedGeometry)
{
WLog_ERR(TAG, "geometry 0x%"PRIx64" not found here, ignoring clear command", id);
WLog_ERR(TAG, "geometry 0x%" PRIx64 " not found here, ignoring clear command", id);
return CHANNEL_RC_OK;
}
WLog_DBG(TAG, "clearing geometry 0x%"PRIx64"", id);
WLog_DBG(TAG, "clearing geometry 0x%" PRIx64 "", id);
if (mappedGeometry->MappedGeometryClear && !mappedGeometry->MappedGeometryClear(mappedGeometry))
if (mappedGeometry->MappedGeometryClear &&
!mappedGeometry->MappedGeometryClear(mappedGeometry))
return ERROR_INTERNAL_ERROR;
if (!HashTable_Remove(context->geometries, &id))
@ -236,7 +235,7 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
if (!mappedGeometry)
{
newOne = TRUE;
WLog_DBG(TAG, "creating geometry 0x%"PRIx64"", id);
WLog_DBG(TAG, "creating geometry 0x%" PRIx64 "", id);
mappedGeometry = calloc(1, sizeof(MAPPED_GEOMETRY));
if (!mappedGeometry)
return CHANNEL_RC_NO_MEMORY;
@ -244,16 +243,17 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
mappedGeometry->refCounter = 1;
mappedGeometry->mappingId = id;
if (HashTable_Add(context->geometries, &(mappedGeometry->mappingId), mappedGeometry) < 0)
if (HashTable_Add(context->geometries, &(mappedGeometry->mappingId), mappedGeometry) <
0)
{
WLog_ERR(TAG, "unable to register geometry 0x%"PRIx64" in the table", id);
WLog_ERR(TAG, "unable to register geometry 0x%" PRIx64 " in the table", id);
free(mappedGeometry);
return CHANNEL_RC_NO_MEMORY;
}
}
else
{
WLog_DBG(TAG, "updating geometry 0x%"PRIx64"", id);
WLog_DBG(TAG, "updating geometry 0x%" PRIx64 "", id);
}
Stream_Read_UINT64(s, mappedGeometry->topLevelId);
@ -290,7 +290,8 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
if (newOne)
{
if (context->MappedGeometryAdded && !context->MappedGeometryAdded(context, mappedGeometry))
if (context->MappedGeometryAdded &&
!context->MappedGeometryAdded(context, mappedGeometry))
{
WLog_ERR(TAG, "geometry added callback failed");
ret = ERROR_INTERNAL_ERROR;
@ -298,7 +299,8 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
}
else
{
if (mappedGeometry->MappedGeometryUpdate && !mappedGeometry->MappedGeometryUpdate(mappedGeometry))
if (mappedGeometry->MappedGeometryUpdate &&
!mappedGeometry->MappedGeometryUpdate(mappedGeometry))
{
WLog_ERR(TAG, "geometry update callback failed");
ret = ERROR_INTERNAL_ERROR;
@ -307,11 +309,10 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
}
else
{
WLog_ERR(TAG, "unknown updateType=%"PRIu32"", updateType);
WLog_ERR(TAG, "unknown updateType=%" PRIu32 "", updateType);
ret = CHANNEL_RC_OK;
}
return ret;
}
@ -322,7 +323,7 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s)
*/
static UINT geometry_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
{
GEOMETRY_CHANNEL_CALLBACK* callback = (GEOMETRY_CHANNEL_CALLBACK*) pChannelCallback;
GEOMETRY_CHANNEL_CALLBACK* callback = (GEOMETRY_CHANNEL_CALLBACK*)pChannelCallback;
return geometry_recv_pdu(callback, data);
}
@ -343,12 +344,17 @@ static UINT geometry_on_close(IWTSVirtualChannelCallback* pChannelCallback)
* @return 0 on success, otherwise a Win32 error code
*/
static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
IWTSVirtualChannel* pChannel, BYTE* Data,
BOOL* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
GEOMETRY_CHANNEL_CALLBACK* callback;
GEOMETRY_LISTENER_CALLBACK* listener_callback = (GEOMETRY_LISTENER_CALLBACK*) pListenerCallback;
callback = (GEOMETRY_CHANNEL_CALLBACK*) calloc(1, sizeof(GEOMETRY_CHANNEL_CALLBACK));
GEOMETRY_LISTENER_CALLBACK* listener_callback = (GEOMETRY_LISTENER_CALLBACK*)pListenerCallback;
WINPR_UNUSED(Data);
WINPR_UNUSED(pbAccept);
callback = (GEOMETRY_CHANNEL_CALLBACK*)calloc(1, sizeof(GEOMETRY_CHANNEL_CALLBACK));
if (!callback)
{
@ -362,7 +368,7 @@ static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCa
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
listener_callback->channel_callback = callback;
*ppCallback = (IWTSVirtualChannelCallback*) callback;
*ppCallback = (IWTSVirtualChannelCallback*)callback;
return CHANNEL_RC_OK;
}
@ -374,9 +380,14 @@ static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCa
static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
UINT status;
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*) pPlugin;
geometry->listener_callback = (GEOMETRY_LISTENER_CALLBACK*) calloc(1,
sizeof(GEOMETRY_LISTENER_CALLBACK));
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin;
if (geometry->initialized)
{
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", GEOMETRY_DVC_CHANNEL_NAME);
return ERROR_INVALID_DATA;
}
geometry->listener_callback =
(GEOMETRY_LISTENER_CALLBACK*)calloc(1, sizeof(GEOMETRY_LISTENER_CALLBACK));
if (!geometry->listener_callback)
{
@ -387,9 +398,12 @@ static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMa
geometry->listener_callback->iface.OnNewChannelConnection = geometry_on_new_channel_connection;
geometry->listener_callback->plugin = pPlugin;
geometry->listener_callback->channel_mgr = pChannelMgr;
status = pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0,
(IWTSListenerCallback*) geometry->listener_callback, &(geometry->listener));
status =
pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0,
&geometry->listener_callback->iface, &(geometry->listener));
geometry->listener->pInterface = geometry->iface.pInterface;
geometry->initialized = status == CHANNEL_RC_OK;
return status;
}
@ -400,8 +414,15 @@ static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMa
*/
static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin)
{
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*) pPlugin;
GeometryClientContext* context = (GeometryClientContext *)geometry->iface.pInterface;
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin;
GeometryClientContext* context = (GeometryClientContext*)geometry->iface.pInterface;
if (geometry && geometry->listener_callback)
{
IWTSVirtualChannelManager* mgr = geometry->listener_callback->channel_mgr;
if (mgr)
IFCALL(mgr->DestroyListener, mgr, geometry->listener);
}
if (context)
HashTable_Free(context->geometries);
@ -417,9 +438,9 @@ static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin)
*/
#ifdef BUILTIN_CHANNELS
#define DVCPluginEntry geometry_DVCPluginEntry
#define DVCPluginEntry geometry_DVCPluginEntry
#else
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#define DVCPluginEntry FREERDP_API DVCPluginEntry
#endif
/**
@ -432,11 +453,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
UINT error = CHANNEL_RC_OK;
GEOMETRY_PLUGIN* geometry;
GeometryClientContext* context;
geometry = (GEOMETRY_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "geometry");
geometry = (GEOMETRY_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "geometry");
if (!geometry)
{
geometry = (GEOMETRY_PLUGIN*) calloc(1, sizeof(GEOMETRY_PLUGIN));
geometry = (GEOMETRY_PLUGIN*)calloc(1, sizeof(GEOMETRY_PLUGIN));
if (!geometry)
{
@ -448,7 +469,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
geometry->iface.Connected = NULL;
geometry->iface.Disconnected = NULL;
geometry->iface.Terminated = geometry_plugin_terminated;
context = (GeometryClientContext*) calloc(1, sizeof(GeometryClientContext));
context = (GeometryClientContext*)calloc(1, sizeof(GeometryClientContext));
if (!context)
{
@ -461,10 +482,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
context->geometries->keyCompare = (HASH_TABLE_KEY_COMPARE_FN)mappedGeometryKeyCompare;
context->geometries->valueFree = (HASH_TABLE_VALUE_FREE_FN)mappedGeometryUnref;
context->handle = (void*) geometry;
geometry->iface.pInterface = (void*) context;
context->handle = (void*)geometry;
geometry->iface.pInterface = (void*)context;
geometry->context = context;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "geometry", (IWTSPlugin*) geometry);
error = pEntryPoints->RegisterPlugin(pEntryPoints, "geometry", (IWTSPlugin*)geometry);
}
else
{
@ -477,5 +498,4 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
error_context:
free(geometry);
return CHANNEL_RC_NO_MEMORY;
}

View File

@ -29,6 +29,4 @@
#include <freerdp/addin.h>
#include <freerdp/client/geometry.h>
#endif /* FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H */

View File

@ -83,16 +83,22 @@ static UINT parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
{
char* path = NULL;
int status;
WCHAR* ptr;
UINT32 PathLength;
Stream_Seek(irp->input, 28);
if (!Stream_SafeSeek(irp->input, 28))
return ERROR_INVALID_DATA;
/* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */
/* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */
if (Stream_GetRemainingLength(irp->input) < 4)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, PathLength);
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input),
PathLength / 2, &path, 0, NULL, NULL);
ptr = (WCHAR*)Stream_Pointer(irp->input);
if (!Stream_SafeSeek(irp->input, PathLength))
return ERROR_INVALID_DATA;
status = ConvertFromUnicode(CP_UTF8, 0, ptr, PathLength / 2, &path, 0, NULL, NULL);
if (status < 1)
if (!(path = (char*) calloc(1, 1)))
if (!(path = (char*)calloc(1, 1)))
{
WLog_ERR(TAG, "calloc failed!");
return CHANNEL_RC_NO_MEMORY;
@ -149,9 +155,11 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
UINT64 Offset;
ssize_t status;
BYTE* buffer = NULL;
if (Stream_GetRemainingLength(irp->input) < 12)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, Length);
Stream_Read_UINT64(irp->input, Offset);
buffer = (BYTE*) malloc(Length);
buffer = (BYTE*)calloc(Length, sizeof(BYTE));
if (!buffer)
{
@ -170,6 +178,7 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
}
else
{
Length = status;
}
Stream_Write_UINT32(irp->output, Length);
@ -201,14 +210,22 @@ static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
UINT32 Length;
UINT64 Offset;
ssize_t status;
void* ptr;
if (Stream_GetRemainingLength(irp->input) > 12)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, Length);
Stream_Read_UINT64(irp->input, Offset);
Stream_Seek(irp->input, 20); /* Padding */
if (!Stream_SafeSeek(irp->input, 20)) /* Padding */
return ERROR_INVALID_DATA;
ptr = Stream_Pointer(irp->input);
if (!Stream_SafeSeek(irp->input, Length))
return ERROR_INVALID_DATA;
len = Length;
while (len > 0)
{
status = write(parallel->file, Stream_Pointer(irp->input), len);
status = write(parallel->file, ptr, len);
if (status < 0)
{
@ -231,8 +248,7 @@ static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT parallel_process_irp_device_control(PARALLEL_DEVICE* parallel,
IRP* irp)
static UINT parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp)
{
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
return irp->Complete(irp);
@ -252,7 +268,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
case IRP_MJ_CREATE:
if ((error = parallel_process_irp_create(parallel, irp)))
{
WLog_ERR(TAG, "parallel_process_irp_create failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "parallel_process_irp_create failed with error %" PRIu32 "!", error);
return error;
}
@ -261,7 +277,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
case IRP_MJ_CLOSE:
if ((error = parallel_process_irp_close(parallel, irp)))
{
WLog_ERR(TAG, "parallel_process_irp_close failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "parallel_process_irp_close failed with error %" PRIu32 "!", error);
return error;
}
@ -270,7 +286,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
case IRP_MJ_READ:
if ((error = parallel_process_irp_read(parallel, irp)))
{
WLog_ERR(TAG, "parallel_process_irp_read failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "parallel_process_irp_read failed with error %" PRIu32 "!", error);
return error;
}
@ -279,7 +295,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
case IRP_MJ_WRITE:
if ((error = parallel_process_irp_write(parallel, irp)))
{
WLog_ERR(TAG, "parallel_process_irp_write failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "parallel_process_irp_write failed with error %" PRIu32 "!", error);
return error;
}
@ -288,7 +304,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
case IRP_MJ_DEVICE_CONTROL:
if ((error = parallel_process_irp_device_control(parallel, irp)))
{
WLog_ERR(TAG, "parallel_process_irp_device_control failed with error %"PRIu32"!",
WLog_ERR(TAG, "parallel_process_irp_device_control failed with error %" PRIu32 "!",
error);
return error;
}
@ -308,7 +324,7 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg)
{
IRP* irp;
wMessage message;
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) arg;
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)arg;
UINT error = CHANNEL_RC_OK;
while (1)
@ -330,18 +346,17 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg)
if (message.id == WMQ_QUIT)
break;
irp = (IRP*) message.wParam;
irp = (IRP*)message.wParam;
if ((error = parallel_process_irp(parallel, irp)))
{
WLog_ERR(TAG, "parallel_process_irp failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "parallel_process_irp failed with error %" PRIu32 "!", error);
break;
}
}
if (error && parallel->rdpcontext)
setChannelError(parallel->rdpcontext, error,
"parallel_thread_func reported an error");
setChannelError(parallel->rdpcontext, error, "parallel_thread_func reported an error");
ExitThread(error);
return error;
@ -354,9 +369,9 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg)
*/
static UINT parallel_irp_request(DEVICE* device, IRP* irp)
{
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
if (!MessageQueue_Post(parallel->queue, NULL, 0, (void*) irp, NULL))
if (!MessageQueue_Post(parallel->queue, NULL, 0, (void*)irp, NULL))
{
WLog_ERR(TAG, "MessageQueue_Post failed!");
return ERROR_INTERNAL_ERROR;
@ -373,13 +388,13 @@ static UINT parallel_irp_request(DEVICE* device, IRP* irp)
static UINT parallel_free(DEVICE* device)
{
UINT error;
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
if (!MessageQueue_PostQuit(parallel->queue, 0)
|| (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
if (!MessageQueue_PostQuit(parallel->queue, 0) ||
(WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
return error;
}
@ -391,9 +406,9 @@ static UINT parallel_free(DEVICE* device)
}
#ifdef BUILTIN_CHANNELS
#define DeviceServiceEntry parallel_DeviceServiceEntry
#define DeviceServiceEntry parallel_DeviceServiceEntry
#else
#define DeviceServiceEntry FREERDP_API DeviceServiceEntry
#define DeviceServiceEntry FREERDP_API DeviceServiceEntry
#endif
/**
@ -410,7 +425,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
RDPDR_PARALLEL* device;
PARALLEL_DEVICE* parallel;
UINT error;
device = (RDPDR_PARALLEL*) pEntryPoints->device;
device = (RDPDR_PARALLEL*)pEntryPoints->device;
name = device->Name;
path = device->Path;
@ -422,7 +437,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
if (name[0] && path[0])
{
parallel = (PARALLEL_DEVICE*) calloc(1, sizeof(PARALLEL_DEVICE));
parallel = (PARALLEL_DEVICE*)calloc(1, sizeof(PARALLEL_DEVICE));
if (!parallel)
{
@ -458,15 +473,14 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
goto error_out;
}
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman,
(DEVICE*) parallel)))
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)parallel)))
{
WLog_ERR(TAG, "RegisterDevice failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
goto error_out;
}
if (!(parallel->thread = CreateThread(NULL, 0,
parallel_thread_func, (void*) parallel, 0, NULL)))
if (!(parallel->thread =
CreateThread(NULL, 0, parallel_thread_func, (void*)parallel, 0, NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
error = ERROR_INTERNAL_ERROR;

View File

@ -18,39 +18,23 @@
define_channel_client("printer")
set(${MODULE_PREFIX}_SRCS
printer_main.c
printer_main.h)
if(WITH_CUPS)
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}
printer_cups.c
printer_cups.h)
include_directories(${CUPS_INCLUDE_DIR})
add_definitions(-DWITH_CUPS)
endif()
if(WIN32 AND NOT UWP)
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}
printer_win.c
printer_win.h)
endif()
printer_main.c)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
if(WITH_CUPS)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES})
endif()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS)
install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
if(WITH_CUPS)
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "cups" "")
endif()
if(WIN32 AND NOT UWP)
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "win" "")
endif()

View File

@ -0,0 +1,31 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2019 Armin Novak <armin.novak@thincast.com>
# Copyright 2019 Thincast Technologies GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_client_subsystem("printer" "cups" "")
set(${MODULE_PREFIX}_SRCS
printer_cups.c)
include_directories(..)
include_directories(${CUPS_INCLUDE_DIR})
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES})
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -0,0 +1,410 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Print Virtual Channel - CUPS driver
*
* Copyright 2010-2011 Vic Lee
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <cups/cups.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/string.h>
#include <freerdp/channels/rdpdr.h>
#include <freerdp/client/printer.h>
typedef struct rdp_cups_printer_driver rdpCupsPrinterDriver;
typedef struct rdp_cups_printer rdpCupsPrinter;
typedef struct rdp_cups_print_job rdpCupsPrintJob;
struct rdp_cups_printer_driver
{
rdpPrinterDriver driver;
int id_sequence;
size_t references;
};
struct rdp_cups_printer
{
rdpPrinter printer;
rdpCupsPrintJob* printjob;
};
struct rdp_cups_print_job
{
rdpPrintJob printjob;
void* printjob_object;
int printjob_id;
};
static void printer_cups_get_printjob_name(char* buf, size_t size, size_t id)
{
time_t tt;
struct tm tres;
struct tm* t;
tt = time(NULL);
t = localtime_r(&tt, &tres);
sprintf_s(buf, size - 1, "FreeRDP Print %04d-%02d-%02d %02d-%02d-%02d - Job %" PRIdz,
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, id);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT printer_cups_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size)
{
rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob;
#ifndef _CUPS_API_1_4
{
FILE* fp;
fp = winpr_fopen((const char*)cups_printjob->printjob_object, "a+b");
if (!fp)
return ERROR_INTERNAL_ERROR;
if (fwrite(data, 1, size, fp) < size)
{
fclose(fp);
return ERROR_INTERNAL_ERROR;
// FIXME once this function doesn't return void anymore!
}
fclose(fp);
}
#else
cupsWriteRequestData((http_t*)cups_printjob->printjob_object, (const char*)data, size);
#endif
return CHANNEL_RC_OK;
}
static void printer_cups_close_printjob(rdpPrintJob* printjob)
{
rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob;
#ifndef _CUPS_API_1_4
{
char buf[100];
printer_cups_get_printjob_name(buf, sizeof(buf), printjob->id);
if (cupsPrintFile(printjob->printer->name, (const char*)cups_printjob->printjob_object, buf,
0, NULL) == 0)
{
}
unlink(cups_printjob->printjob_object);
free(cups_printjob->printjob_object);
}
#else
cupsFinishDocument((http_t*)cups_printjob->printjob_object, printjob->printer->name);
cups_printjob->printjob_id = 0;
httpClose((http_t*)cups_printjob->printjob_object);
#endif
((rdpCupsPrinter*)printjob->printer)->printjob = NULL;
free(cups_printjob);
}
static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, UINT32 id)
{
rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer;
rdpCupsPrintJob* cups_printjob;
if (cups_printer->printjob != NULL)
return NULL;
cups_printjob = (rdpCupsPrintJob*)calloc(1, sizeof(rdpCupsPrintJob));
if (!cups_printjob)
return NULL;
cups_printjob->printjob.id = id;
cups_printjob->printjob.printer = printer;
cups_printjob->printjob.Write = printer_cups_write_printjob;
cups_printjob->printjob.Close = printer_cups_close_printjob;
#ifndef _CUPS_API_1_4
cups_printjob->printjob_object = _strdup(tmpnam(NULL));
if (!cups_printjob->printjob_object)
{
free(cups_printjob);
return NULL;
}
#else
{
char buf[100];
#if !defined(_CUPS_API_1_7)
cups_printjob->printjob_object =
httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED);
#else
cups_printjob->printjob_object = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC,
HTTP_ENCRYPT_IF_REQUESTED, 1, 10000, NULL);
#endif
if (!cups_printjob->printjob_object)
{
free(cups_printjob);
return NULL;
}
printer_cups_get_printjob_name(buf, sizeof(buf), cups_printjob->printjob.id);
cups_printjob->printjob_id =
cupsCreateJob((http_t*)cups_printjob->printjob_object, printer->name, buf, 0, NULL);
if (!cups_printjob->printjob_id)
{
httpClose((http_t*)cups_printjob->printjob_object);
free(cups_printjob);
return NULL;
}
cupsStartDocument((http_t*)cups_printjob->printjob_object, printer->name,
cups_printjob->printjob_id, buf, CUPS_FORMAT_AUTO, 1);
}
#endif
cups_printer->printjob = cups_printjob;
return (rdpPrintJob*)cups_printjob;
}
static rdpPrintJob* printer_cups_find_printjob(rdpPrinter* printer, UINT32 id)
{
rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer;
if (cups_printer->printjob == NULL)
return NULL;
if (cups_printer->printjob->printjob.id != id)
return NULL;
return (rdpPrintJob*)cups_printer->printjob;
}
static void printer_cups_free_printer(rdpPrinter* printer)
{
rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer;
if (cups_printer->printjob)
cups_printer->printjob->printjob.Close((rdpPrintJob*)cups_printer->printjob);
if (printer->backend)
printer->backend->ReleaseRef(printer->backend);
free(printer->name);
free(printer->driver);
free(printer);
}
static void printer_cups_add_ref_printer(rdpPrinter* printer)
{
if (printer)
printer->references++;
}
static void printer_cups_release_ref_printer(rdpPrinter* printer)
{
if (!printer)
return;
if (printer->references <= 1)
printer_cups_free_printer(printer);
else
printer->references--;
}
static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, const char* name,
const char* driverName, BOOL is_default)
{
rdpCupsPrinter* cups_printer;
cups_printer = (rdpCupsPrinter*)calloc(1, sizeof(rdpCupsPrinter));
if (!cups_printer)
return NULL;
cups_printer->printer.backend = &cups_driver->driver;
cups_printer->printer.id = cups_driver->id_sequence++;
cups_printer->printer.name = _strdup(name);
if (!cups_printer->printer.name)
{
free(cups_printer);
return NULL;
}
if (driverName)
cups_printer->printer.driver = _strdup(driverName);
else
cups_printer->printer.driver = _strdup("MS Publisher Imagesetter");
if (!cups_printer->printer.driver)
{
free(cups_printer->printer.name);
free(cups_printer);
return NULL;
}
cups_printer->printer.is_default = is_default;
cups_printer->printer.CreatePrintJob = printer_cups_create_printjob;
cups_printer->printer.FindPrintJob = printer_cups_find_printjob;
cups_printer->printer.AddRef = printer_cups_add_ref_printer;
cups_printer->printer.ReleaseRef = printer_cups_release_ref_printer;
cups_printer->printer.AddRef(&cups_printer->printer);
cups_printer->printer.backend->AddRef(cups_printer->printer.backend);
return &cups_printer->printer;
}
static void printer_cups_release_enum_printers(rdpPrinter** printers)
{
rdpPrinter** cur = printers;
while ((cur != NULL) && ((*cur) != NULL))
{
if ((*cur)->ReleaseRef)
(*cur)->ReleaseRef(*cur);
cur++;
}
free(printers);
}
static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver)
{
rdpPrinter** printers;
int num_printers;
cups_dest_t* dests;
cups_dest_t* dest;
int num_dests;
int i;
num_dests = cupsGetDests(&dests);
printers = (rdpPrinter**)calloc(num_dests + 1, sizeof(rdpPrinter*));
if (!printers)
return NULL;
num_printers = 0;
for (i = 0, dest = dests; i < num_dests; i++, dest++)
{
if (dest->instance == NULL)
{
rdpPrinter* current = printer_cups_new_printer((rdpCupsPrinterDriver*)driver,
dest->name, NULL, dest->is_default);
if (!current)
{
printer_cups_release_enum_printers(printers);
printers = NULL;
break;
}
printers[num_printers++] = current;
}
}
cupsFreeDests(num_dests, dests);
return printers;
}
static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver, const char* name,
const char* driverName)
{
rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver;
return printer_cups_new_printer(cups_driver, name, driverName,
cups_driver->id_sequence == 1 ? TRUE : FALSE);
}
static void printer_cups_add_ref_driver(rdpPrinterDriver* driver)
{
rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver;
if (cups_driver)
cups_driver->references++;
}
/* Singleton */
static rdpCupsPrinterDriver* uniq_cups_driver = NULL;
static void printer_cups_release_ref_driver(rdpPrinterDriver* driver)
{
rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver;
if (cups_driver->references <= 1)
{
if (uniq_cups_driver == cups_driver)
uniq_cups_driver = NULL;
free(cups_driver);
cups_driver = NULL;
}
else
cups_driver->references--;
}
#ifdef BUILTIN_CHANNELS
rdpPrinterDriver* cups_freerdp_printer_client_subsystem_entry(void)
#else
FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void)
#endif
{
if (!uniq_cups_driver)
{
uniq_cups_driver = (rdpCupsPrinterDriver*)calloc(1, sizeof(rdpCupsPrinterDriver));
if (!uniq_cups_driver)
return NULL;
uniq_cups_driver->driver.EnumPrinters = printer_cups_enum_printers;
uniq_cups_driver->driver.ReleaseEnumPrinters = printer_cups_release_enum_printers;
uniq_cups_driver->driver.GetPrinter = printer_cups_get_printer;
uniq_cups_driver->driver.AddRef = printer_cups_add_ref_driver;
uniq_cups_driver->driver.ReleaseRef = printer_cups_release_ref_driver;
uniq_cups_driver->id_sequence = 1;
}
uniq_cups_driver->driver.AddRef(&uniq_cups_driver->driver);
return &uniq_cups_driver->driver;
}

View File

@ -1,331 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Print Virtual Channel - CUPS driver
*
* Copyright 2010-2011 Vic Lee
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <cups/cups.h>
#include <winpr/crt.h>
#include <winpr/string.h>
#include <freerdp/channels/rdpdr.h>
#include "printer_main.h"
#include "printer_cups.h"
typedef struct rdp_cups_printer_driver rdpCupsPrinterDriver;
typedef struct rdp_cups_printer rdpCupsPrinter;
typedef struct rdp_cups_print_job rdpCupsPrintJob;
struct rdp_cups_printer_driver
{
rdpPrinterDriver driver;
int id_sequence;
};
struct rdp_cups_printer
{
rdpPrinter printer;
rdpCupsPrintJob* printjob;
};
struct rdp_cups_print_job
{
rdpPrintJob printjob;
void* printjob_object;
int printjob_id;
};
static void printer_cups_get_printjob_name(char* buf, int size)
{
time_t tt;
struct tm* t;
tt = time(NULL);
t = localtime(&tt);
sprintf_s(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT printer_cups_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size)
{
rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*) printjob;
#ifndef _CUPS_API_1_4
{
FILE* fp;
fp = fopen((const char*) cups_printjob->printjob_object, "a+b");
if (!fp)
return ERROR_INTERNAL_ERROR;
if (fwrite(data, 1, size, fp) < size)
{
fclose(fp);
return ERROR_INTERNAL_ERROR;
// FIXME once this function doesn't return void anymore!
}
fclose(fp);
}
#else
cupsWriteRequestData((http_t*) cups_printjob->printjob_object, (const char*) data, size);
#endif
return CHANNEL_RC_OK;
}
static void printer_cups_close_printjob(rdpPrintJob* printjob)
{
rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*) printjob;
#ifndef _CUPS_API_1_4
{
char buf[100];
printer_cups_get_printjob_name(buf, sizeof(buf));
if (cupsPrintFile(printjob->printer->name, (const char*) cups_printjob->printjob_object, buf, 0, NULL) == 0)
{
}
unlink(cups_printjob->printjob_object);
free(cups_printjob->printjob_object);
}
#else
cupsFinishDocument((http_t*) cups_printjob->printjob_object, printjob->printer->name);
cups_printjob->printjob_id = 0;
httpClose((http_t*) cups_printjob->printjob_object);
#endif
((rdpCupsPrinter*) printjob->printer)->printjob = NULL;
free(cups_printjob) ;
}
static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, UINT32 id)
{
rdpCupsPrinter* cups_printer = (rdpCupsPrinter*) printer;
rdpCupsPrintJob* cups_printjob;
if (cups_printer->printjob != NULL)
return NULL;
cups_printjob = (rdpCupsPrintJob*) calloc(1, sizeof(rdpCupsPrintJob));
if (!cups_printjob)
return NULL;
cups_printjob->printjob.id = id;
cups_printjob->printjob.printer = printer;
cups_printjob->printjob.Write = printer_cups_write_printjob;
cups_printjob->printjob.Close = printer_cups_close_printjob;
#ifndef _CUPS_API_1_4
cups_printjob->printjob_object = _strdup(tmpnam(NULL));
if (!cups_printjob->printjob_object)
{
free(cups_printjob);
return NULL;
}
#else
{
char buf[100];
cups_printjob->printjob_object = httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED);
if (!cups_printjob->printjob_object)
{
free(cups_printjob);
return NULL;
}
printer_cups_get_printjob_name(buf, sizeof(buf));
cups_printjob->printjob_id = cupsCreateJob((http_t*) cups_printjob->printjob_object,
printer->name, buf, 0, NULL);
if (!cups_printjob->printjob_id)
{
httpClose((http_t*) cups_printjob->printjob_object);
free(cups_printjob);
return NULL;
}
cupsStartDocument((http_t*) cups_printjob->printjob_object,
printer->name, cups_printjob->printjob_id, buf, CUPS_FORMAT_AUTO, 1);
}
#endif
cups_printer->printjob = cups_printjob;
return (rdpPrintJob*)cups_printjob;
}
static rdpPrintJob* printer_cups_find_printjob(rdpPrinter* printer, UINT32 id)
{
rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer;
if (cups_printer->printjob == NULL)
return NULL;
if (cups_printer->printjob->printjob.id != id)
return NULL;
return (rdpPrintJob*)cups_printer->printjob;
}
static void printer_cups_free_printer(rdpPrinter* printer)
{
rdpCupsPrinter* cups_printer = (rdpCupsPrinter*) printer;
if (cups_printer->printjob)
cups_printer->printjob->printjob.Close((rdpPrintJob*) cups_printer->printjob);
free(printer->name);
free(printer->driver);
free(printer);
}
static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver,
const char* name, const char* driverName, BOOL is_default)
{
rdpCupsPrinter* cups_printer;
cups_printer = (rdpCupsPrinter*) calloc(1, sizeof(rdpCupsPrinter));
if (!cups_printer)
return NULL;
cups_printer->printer.id = cups_driver->id_sequence++;
cups_printer->printer.name = _strdup(name);
if (!cups_printer->printer.name)
{
free(cups_printer);
return NULL;
}
if (driverName)
cups_printer->printer.driver = _strdup(driverName);
else
cups_printer->printer.driver = _strdup("MS Publisher Imagesetter");
if (!cups_printer->printer.driver)
{
free(cups_printer->printer.name);
free(cups_printer);
return NULL;
}
cups_printer->printer.is_default = is_default;
cups_printer->printer.CreatePrintJob = printer_cups_create_printjob;
cups_printer->printer.FindPrintJob = printer_cups_find_printjob;
cups_printer->printer.Free = printer_cups_free_printer;
return (rdpPrinter*) cups_printer;
}
static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver)
{
rdpPrinter** printers;
int num_printers;
cups_dest_t *dests;
cups_dest_t *dest;
int num_dests;
int i;
num_dests = cupsGetDests(&dests);
printers = (rdpPrinter**) calloc(num_dests + 1, sizeof(rdpPrinter*));
if (!printers)
return NULL;
num_printers = 0;
for (i = 0, dest = dests; i < num_dests; i++, dest++)
{
if (dest->instance == NULL)
{
printers[num_printers++] = printer_cups_new_printer((rdpCupsPrinterDriver*) driver,
dest->name, NULL, dest->is_default);
}
}
cupsFreeDests(num_dests, dests);
return printers;
}
static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver,
const char* name, const char* driverName)
{
rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*) driver;
return printer_cups_new_printer(cups_driver, name, driverName,
cups_driver->id_sequence == 1 ? TRUE : FALSE);
}
static rdpCupsPrinterDriver* cups_driver = NULL;
rdpPrinterDriver* printer_cups_get_driver(void)
{
if (cups_driver == NULL)
{
cups_driver = (rdpCupsPrinterDriver*) calloc(1, sizeof(rdpCupsPrinterDriver));
if (!cups_driver)
return NULL;
cups_driver->driver.EnumPrinters = printer_cups_enum_printers;
cups_driver->driver.GetPrinter = printer_cups_get_printer;
cups_driver->id_sequence = 1;
}
return (rdpPrinterDriver*) cups_driver;
}

View File

@ -42,15 +42,7 @@
#include "../printer.h"
#ifdef WITH_CUPS
#include "printer_cups.h"
#endif
#include "printer_main.h"
#if defined(_WIN32) && !defined(_UWP)
#include "printer_win.h"
#endif
#include <freerdp/client/printer.h>
#include <freerdp/channels/log.h>
@ -79,26 +71,20 @@ typedef enum
PRN_CONF_PNP = 1,
PRN_CONF_DRIVER = 2,
PRN_CONF_DATA = 3
}
prn_conf_t;
} prn_conf_t;
static const char* filemap[] =
{
"PortDosName",
"PnPName",
"DriverName",
"CachedPrinterConfigData"
};
static const char* filemap[] = { "PortDosName", "PnPName", "DriverName",
"CachedPrinterConfigData" };
static char* get_printer_config_path(const rdpSettings* settings, const WCHAR* name, size_t length)
{
char* dir = GetCombinedPath(settings->ConfigPath, "printers");
char* bname = crypto_base64_encode((const BYTE*) name, (int)length);
char* bname = crypto_base64_encode((const BYTE*)name, (int)length);
char* config = GetCombinedPath(dir, bname);
if (config && !PathFileExistsA(config))
if (config && !winpr_PathFileExists(config))
{
if (!PathMakePathA(config, NULL))
if (!winpr_PathMakePath(config, NULL))
{
free(config);
config = NULL;
@ -121,11 +107,10 @@ static BOOL printer_write_setting(const char* path, prn_conf_t type, const void*
const char* name = filemap[type];
char* abs = GetCombinedPath(path, name);
if (!abs)
if (!abs || (length > INT32_MAX))
return FALSE;
file = CreateFileA(abs, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
file = CreateFileA(abs, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
free(abs);
if (file == INVALID_HANDLE_VALUE)
@ -138,7 +123,9 @@ static BOOL printer_write_setting(const char* path, prn_conf_t type, const void*
if (!base64)
goto fail;
b64len = strlen(base64);
/* base64 char represents 6bit -> 4*(n/3) is the length which is
* always smaller than 2*n */
b64len = strnlen(base64, 2 * length);
rc = WriteFile(file, base64, b64len, &written, NULL);
if (b64len != written)
@ -158,27 +145,26 @@ static BOOL printer_config_valid(const char* path)
if (!path)
return FALSE;
if (!PathFileExistsA(path))
if (!winpr_PathFileExists(path))
return FALSE;
return TRUE;
}
static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data, size_t* length)
static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data, UINT32* length)
{
DWORD lowSize, highSize;
DWORD read = 0;
BOOL rc = FALSE;
HANDLE file;
BYTE* fdata = NULL;
char* fdata = NULL;
const char* name = filemap[type];
char* abs = GetCombinedPath(path, name);
if (!abs)
return FALSE;
file = CreateFileA(abs, GENERIC_READ, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
file = CreateFileA(abs, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
free(abs);
if (file == INVALID_HANDLE_VALUE)
@ -205,13 +191,13 @@ static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data,
fail:
CloseHandle(file);
if (rc)
if (rc && (lowSize <= INT_MAX))
{
int blen = 0;
crypto_base64_decode(fdata, lowSize, data, &blen);
crypto_base64_decode(fdata, (int)lowSize, (BYTE**)data, &blen);
if (*data)
*length = blen;
if (*data && (blen > 0))
*length = (UINT32)blen;
else
{
rc = FALSE;
@ -228,9 +214,8 @@ fail:
return rc;
}
static BOOL printer_save_to_config(const rdpSettings* settings,
const char* PortDosName, size_t PortDosNameLen,
const WCHAR* PnPName, size_t PnPNameLen,
static BOOL printer_save_to_config(const rdpSettings* settings, const char* PortDosName,
size_t PortDosNameLen, const WCHAR* PnPName, size_t PnPNameLen,
const WCHAR* DriverName, size_t DriverNameLen,
const WCHAR* PrinterName, size_t PrintNameLen,
const BYTE* CachedPrinterConfigData, size_t CacheFieldsLen)
@ -276,7 +261,7 @@ static BOOL printer_remove_config(const rdpSettings* settings, const WCHAR* name
if (!printer_config_valid(path))
goto fail;
rc = RemoveDirectoryA(path);
rc = winpr_RemoveDirectory(path);
fail:
free(path);
return rc;
@ -290,7 +275,7 @@ static BOOL printer_move_config(const rdpSettings* settings, const WCHAR* oldNam
char* newPath = get_printer_config_path(settings, newName, newLength);
if (printer_config_valid(oldPath))
rc = MoveFileA(oldPath, newPath);
rc = winpr_MoveFile(oldPath, newPath);
free(oldPath);
free(newPath);
@ -306,13 +291,13 @@ static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* pr
char* path = NULL;
int rc;
UINT32 flags = 0;
WCHAR* DriverName = NULL;
size_t DriverNameLen = 0;
WCHAR* PnPName = NULL;
size_t PnPNameLen = 0;
BYTE* CachedPrinterConfigData = NULL;
size_t CachedFieldsLen = 0;
size_t PrinterNameLen = 0;
void* DriverName = NULL;
UINT32 DriverNameLen = 0;
void* PnPName = NULL;
UINT32 PnPNameLen = 0;
void* CachedPrinterConfigData = NULL;
UINT32 CachedFieldsLen = 0;
UINT32 PrinterNameLen = 0;
if (!settings || !printer)
return FALSE;
@ -338,8 +323,8 @@ static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* pr
if (!printer_read_setting(path, PRN_CONF_DRIVER, &DriverName, &DriverNameLen))
{
DriverNameLen = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &DriverName,
0) * 2 + 1;
DriverNameLen =
ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, (LPWSTR*)&DriverName, 0) * 2 + 1;
}
if (!printer_read_setting(path, PRN_CONF_DATA, &CachedPrinterConfigData, &CachedFieldsLen))
@ -352,7 +337,7 @@ static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* pr
goto fail;
Stream_Write_UINT32(printer_dev->device.data, flags);
Stream_Write_UINT32(printer_dev->device.data, 0); /* CodePage, reserved */
Stream_Write_UINT32(printer_dev->device.data, 0); /* CodePage, reserved */
Stream_Write_UINT32(printer_dev->device.data, PnPNameLen); /* PnPNameLen */
Stream_Write_UINT32(printer_dev->device.data, DriverNameLen);
Stream_Write_UINT32(printer_dev->device.data, PrinterNameLen);
@ -441,8 +426,8 @@ static UINT printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp)
rdpPrintJob* printjob = NULL;
if (printer_dev->printer)
printjob = printer_dev->printer->CreatePrintJob(printer_dev->printer,
irp->devman->id_sequence++);
printjob =
printer_dev->printer->CreatePrintJob(printer_dev->printer, irp->devman->id_sequence++);
if (printjob)
{
@ -467,8 +452,7 @@ static UINT printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp)
rdpPrintJob* printjob = NULL;
if (printer_dev->printer)
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer,
irp->FileId);
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
if (!printjob)
{
@ -494,13 +478,18 @@ static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
UINT64 Offset;
rdpPrintJob* printjob = NULL;
UINT error = CHANNEL_RC_OK;
void* ptr;
if (Stream_GetRemainingLength(irp->input) < 32)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, Length);
Stream_Read_UINT64(irp->input, Offset);
Stream_Seek(irp->input, 20); /* Padding */
ptr = Stream_Pointer(irp->input);
if (!Stream_SafeSeek(irp->input, Length))
return ERROR_INVALID_DATA;
if (printer_dev->printer)
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer,
irp->FileId);
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
if (!printjob)
{
@ -509,12 +498,12 @@ static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
}
else
{
error = printjob->Write(printjob, Stream_Pointer(irp->input), Length);
error = printjob->Write(printjob, ptr, Length);
}
if (error)
{
WLog_ERR(TAG, "printjob->Write failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "printjob->Write failed with error %" PRIu32 "!", error);
return error;
}
@ -528,8 +517,7 @@ static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT printer_process_irp_device_control(PRINTER_DEVICE* printer_dev,
IRP* irp)
static UINT printer_process_irp_device_control(PRINTER_DEVICE* printer_dev, IRP* irp)
{
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
return irp->Complete(irp);
@ -549,7 +537,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
case IRP_MJ_CREATE:
if ((error = printer_process_irp_create(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_create failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "printer_process_irp_create failed with error %" PRIu32 "!", error);
return error;
}
@ -558,7 +546,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
case IRP_MJ_CLOSE:
if ((error = printer_process_irp_close(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_close failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "printer_process_irp_close failed with error %" PRIu32 "!", error);
return error;
}
@ -567,7 +555,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
case IRP_MJ_WRITE:
if ((error = printer_process_irp_write(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_write failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "printer_process_irp_write failed with error %" PRIu32 "!", error);
return error;
}
@ -576,7 +564,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
case IRP_MJ_DEVICE_CONTROL:
if ((error = printer_process_irp_device_control(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp_device_control failed with error %"PRIu32"!",
WLog_ERR(TAG, "printer_process_irp_device_control failed with error %" PRIu32 "!",
error);
return error;
}
@ -595,8 +583,8 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
static DWORD WINAPI printer_thread_func(LPVOID arg)
{
IRP* irp;
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) arg;
HANDLE obj[] = {printer_dev->event, printer_dev->stopEvent};
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)arg;
HANDLE obj[] = { printer_dev->event, printer_dev->stopEvent };
UINT error = CHANNEL_RC_OK;
while (1)
@ -606,7 +594,7 @@ static DWORD WINAPI printer_thread_func(LPVOID arg)
if (rc == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
break;
}
@ -616,7 +604,7 @@ static DWORD WINAPI printer_thread_func(LPVOID arg)
continue;
ResetEvent(printer_dev->event);
irp = (IRP*) InterlockedPopEntrySList(printer_dev->pIrpList);
irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList);
if (irp == NULL)
{
@ -627,14 +615,13 @@ static DWORD WINAPI printer_thread_func(LPVOID arg)
if ((error = printer_process_irp(printer_dev, irp)))
{
WLog_ERR(TAG, "printer_process_irp failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "printer_process_irp failed with error %" PRIu32 "!", error);
break;
}
}
if (error && printer_dev->rdpcontext)
setChannelError(printer_dev->rdpcontext, error,
"printer_thread_func reported an error");
setChannelError(printer_dev->rdpcontext, error, "printer_thread_func reported an error");
ExitThread(error);
return error;
@ -647,7 +634,7 @@ static DWORD WINAPI printer_thread_func(LPVOID arg)
*/
static UINT printer_irp_request(DEVICE* device, IRP* irp)
{
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device;
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
InterlockedPushEntrySList(printer_dev->pIrpList, &(irp->ItemEntry));
SetEvent(printer_dev->event);
return CHANNEL_RC_OK;
@ -656,7 +643,7 @@ static UINT printer_irp_request(DEVICE* device, IRP* irp)
static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 packetId, wStream* s)
{
UINT32 eventID;
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device;
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
const rdpSettings* settings = printer_dev->rdpcontext->settings;
if (component != RDPDR_CTYP_PRN)
@ -673,156 +660,156 @@ static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 pa
switch (eventID)
{
case RDPDR_ADD_PRINTER_EVENT:
{
char PortDosName[8];
UINT32 PnPNameLen, DriverNameLen, PrintNameLen, CacheFieldsLen;
const WCHAR* PnPName, *DriverName, *PrinterName;
const BYTE* CachedPrinterConfigData;
{
char PortDosName[8];
UINT32 PnPNameLen, DriverNameLen, PrintNameLen, CacheFieldsLen;
const WCHAR *PnPName, *DriverName, *PrinterName;
const BYTE* CachedPrinterConfigData;
if (Stream_GetRemainingLength(s) < 24)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 24)
return ERROR_INVALID_DATA;
Stream_Read(s, PortDosName, sizeof(PortDosName));
Stream_Read_UINT32(s, PnPNameLen);
Stream_Read_UINT32(s, DriverNameLen);
Stream_Read_UINT32(s, PrintNameLen);
Stream_Read_UINT32(s, CacheFieldsLen);
Stream_Read(s, PortDosName, sizeof(PortDosName));
Stream_Read_UINT32(s, PnPNameLen);
Stream_Read_UINT32(s, DriverNameLen);
Stream_Read_UINT32(s, PrintNameLen);
Stream_Read_UINT32(s, CacheFieldsLen);
if (Stream_GetRemainingLength(s) < PnPNameLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < PnPNameLen)
return ERROR_INVALID_DATA;
PnPName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PnPNameLen);
PnPName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PnPNameLen);
if (Stream_GetRemainingLength(s) < DriverNameLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < DriverNameLen)
return ERROR_INVALID_DATA;
DriverName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, DriverNameLen);
DriverName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, DriverNameLen);
if (Stream_GetRemainingLength(s) < PrintNameLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < PrintNameLen)
return ERROR_INVALID_DATA;
PrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PrintNameLen);
PrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PrintNameLen);
if (Stream_GetRemainingLength(s) < CacheFieldsLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < CacheFieldsLen)
return ERROR_INVALID_DATA;
CachedPrinterConfigData = Stream_Pointer(s);
Stream_Seek(s, CacheFieldsLen);
CachedPrinterConfigData = Stream_Pointer(s);
Stream_Seek(s, CacheFieldsLen);
if (!printer_save_to_config(settings,
PortDosName, sizeof(PortDosName),
PnPName, PnPNameLen,
DriverName, DriverNameLen,
PrinterName, PrintNameLen,
CachedPrinterConfigData, CacheFieldsLen))
return ERROR_INTERNAL_ERROR;
}
break;
if (!printer_save_to_config(settings, PortDosName, sizeof(PortDosName), PnPName,
PnPNameLen, DriverName, DriverNameLen, PrinterName,
PrintNameLen, CachedPrinterConfigData,
CacheFieldsLen))
return ERROR_INTERNAL_ERROR;
}
break;
case RDPDR_UPDATE_PRINTER_EVENT:
{
UINT32 PrinterNameLen, ConfigDataLen;
const WCHAR* PrinterName;
const BYTE* ConfigData;
{
UINT32 PrinterNameLen, ConfigDataLen;
const WCHAR* PrinterName;
const BYTE* ConfigData;
if (Stream_GetRemainingLength(s) < 8)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 8)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, PrinterNameLen);
Stream_Read_UINT32(s, ConfigDataLen);
Stream_Read_UINT32(s, PrinterNameLen);
Stream_Read_UINT32(s, ConfigDataLen);
if (Stream_GetRemainingLength(s) < PrinterNameLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < PrinterNameLen)
return ERROR_INVALID_DATA;
PrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PrinterNameLen);
PrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PrinterNameLen);
if (Stream_GetRemainingLength(s) < ConfigDataLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < ConfigDataLen)
return ERROR_INVALID_DATA;
ConfigData = Stream_Pointer(s);
Stream_Seek(s, ConfigDataLen);
ConfigData = Stream_Pointer(s);
Stream_Seek(s, ConfigDataLen);
if (!printer_update_to_config(settings, PrinterName, PrinterNameLen, ConfigData, ConfigDataLen))
return ERROR_INTERNAL_ERROR;
}
break;
if (!printer_update_to_config(settings, PrinterName, PrinterNameLen, ConfigData,
ConfigDataLen))
return ERROR_INTERNAL_ERROR;
}
break;
case RDPDR_DELETE_PRINTER_EVENT:
{
UINT32 PrinterNameLen;
const WCHAR* PrinterName;
{
UINT32 PrinterNameLen;
const WCHAR* PrinterName;
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, PrinterNameLen);
Stream_Read_UINT32(s, PrinterNameLen);
if (Stream_GetRemainingLength(s) < PrinterNameLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < PrinterNameLen)
return ERROR_INVALID_DATA;
PrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PrinterNameLen);
printer_remove_config(settings, PrinterName, PrinterNameLen);
}
break;
PrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, PrinterNameLen);
printer_remove_config(settings, PrinterName, PrinterNameLen);
}
break;
case RDPDR_RENAME_PRINTER_EVENT:
{
UINT32 OldPrinterNameLen, NewPrinterNameLen;
const WCHAR* OldPrinterName;
const WCHAR* NewPrinterName;
{
UINT32 OldPrinterNameLen, NewPrinterNameLen;
const WCHAR* OldPrinterName;
const WCHAR* NewPrinterName;
if (Stream_GetRemainingLength(s) < 8)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 8)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, OldPrinterNameLen);
Stream_Read_UINT32(s, NewPrinterNameLen);
Stream_Read_UINT32(s, OldPrinterNameLen);
Stream_Read_UINT32(s, NewPrinterNameLen);
if (Stream_GetRemainingLength(s) < OldPrinterNameLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < OldPrinterNameLen)
return ERROR_INVALID_DATA;
OldPrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, OldPrinterNameLen);
OldPrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, OldPrinterNameLen);
if (Stream_GetRemainingLength(s) < NewPrinterNameLen)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < NewPrinterNameLen)
return ERROR_INVALID_DATA;
NewPrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, NewPrinterNameLen);
NewPrinterName = (const WCHAR*)Stream_Pointer(s);
Stream_Seek(s, NewPrinterNameLen);
if (!printer_move_config(settings, OldPrinterName, OldPrinterNameLen, NewPrinterName,
NewPrinterNameLen))
return ERROR_INTERNAL_ERROR;
}
break;
if (!printer_move_config(settings, OldPrinterName, OldPrinterNameLen,
NewPrinterName, NewPrinterNameLen))
return ERROR_INTERNAL_ERROR;
}
break;
default:
WLog_ERR(TAG, "Unknown cache data eventID: 0x%08"PRIX32"", eventID);
WLog_ERR(TAG, "Unknown cache data eventID: 0x%08" PRIX32 "", eventID);
return ERROR_INVALID_DATA;
}
break;
case PAKID_PRN_USING_XPS:
{
UINT32 flags;
{
UINT32 flags;
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, flags);
WLog_ERR(TAG,
"Ignoring unhandled message PAKID_PRN_USING_XPS [printerID=%08"PRIx32", flags=%08"PRIx32"]",
eventID, flags);
}
break;
Stream_Read_UINT32(s, flags);
WLog_ERR(TAG,
"Ignoring unhandled message PAKID_PRN_USING_XPS [printerID=%08" PRIx32
", flags=%08" PRIx32 "]",
eventID, flags);
}
break;
default:
WLog_ERR(TAG, "Unknown printing component packetID: 0x%04"PRIX16"", packetId);
WLog_ERR(TAG, "Unknown printing component packetID: 0x%04" PRIX16 "", packetId);
return ERROR_INVALID_DATA;
}
@ -837,14 +824,14 @@ static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 pa
static UINT printer_free(DEVICE* device)
{
IRP* irp;
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device;
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
UINT error;
SetEvent(printer_dev->stopEvent);
if (WaitForSingleObject(printer_dev->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
/* The analyzer is confused by this premature return value.
* Since this case can not be handled gracefully silence the
@ -854,7 +841,7 @@ static UINT printer_free(DEVICE* device)
#endif
}
while ((irp = (IRP*) InterlockedPopEntrySList(printer_dev->pIrpList)) != NULL)
while ((irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList)) != NULL)
irp->Discard(irp);
CloseHandle(printer_dev->thread);
@ -863,7 +850,7 @@ static UINT printer_free(DEVICE* device)
_aligned_free(printer_dev->pIrpList);
if (printer_dev->printer)
printer_dev->printer->Free(printer_dev->printer);
printer_dev->printer->ReleaseRef(printer_dev->printer);
Stream_Free(printer_dev->device.data, TRUE);
free(printer_dev);
@ -875,12 +862,11 @@ static UINT printer_free(DEVICE* device)
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
rdpPrinter* printer)
static UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer)
{
PRINTER_DEVICE* printer_dev;
UINT error = ERROR_INTERNAL_ERROR;
printer_dev = (PRINTER_DEVICE*) calloc(1, sizeof(PRINTER_DEVICE));
printer_dev = (PRINTER_DEVICE*)calloc(1, sizeof(PRINTER_DEVICE));
if (!printer_dev)
{
@ -893,7 +879,7 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
if (!printer_dev->device.data)
goto error_out;
sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%d", printer->id);
sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%" PRIdz, printer->id);
printer_dev->device.type = RDPDR_DTYP_PRINT;
printer_dev->device.name = printer_dev->port;
printer_dev->device.IRPRequest = printer_irp_request;
@ -901,8 +887,8 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
printer_dev->device.Free = printer_free;
printer_dev->rdpcontext = pEntryPoints->rdpcontext;
printer_dev->printer = printer;
printer_dev->pIrpList = (WINPR_PSLIST_HEADER) _aligned_malloc(sizeof(
WINPR_SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);
printer_dev->pIrpList = (WINPR_PSLIST_HEADER)_aligned_malloc(sizeof(WINPR_SLIST_HEADER),
MEMORY_ALLOCATION_ALIGNMENT);
if (!printer_dev->pIrpList)
{
@ -930,102 +916,158 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
goto error_out;
}
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman,
(DEVICE*) printer_dev)))
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)printer_dev)))
{
WLog_ERR(TAG, "RegisterDevice failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
goto error_out;
}
if (!(printer_dev->thread = CreateThread(NULL, 0, printer_thread_func, (void*) printer_dev, 0,
NULL)))
if (!(printer_dev->thread =
CreateThread(NULL, 0, printer_thread_func, (void*)printer_dev, 0, NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
error = ERROR_INTERNAL_ERROR;
goto error_out;
}
printer->AddRef(printer);
return CHANNEL_RC_OK;
error_out:
printer_free(&printer_dev->device);
return error;
}
#ifdef BUILTIN_CHANNELS
#define DeviceServiceEntry printer_DeviceServiceEntry
#else
#define DeviceServiceEntry FREERDP_API DeviceServiceEntry
#endif
static rdpPrinterDriver* printer_load_backend(const char* backend)
{
typedef rdpPrinterDriver* (*backend_load_t)(void);
union {
PVIRTUALCHANNELENTRY entry;
backend_load_t backend;
} fktconv;
fktconv.entry = freerdp_load_channel_addin_entry("printer", backend, NULL, 0);
if (!fktconv.entry)
return NULL;
return fktconv.backend();
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
UINT
#ifdef BUILTIN_CHANNELS
printer_DeviceServiceEntry
#else
FREERDP_API
DeviceServiceEntry
#endif
(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
int i;
char* name;
char* driver_name;
rdpPrinter* printer;
rdpPrinter** printers;
RDPDR_PRINTER* device;
BOOL default_backend = TRUE;
RDPDR_PRINTER* device = NULL;
rdpPrinterDriver* driver = NULL;
UINT error;
#ifdef WITH_CUPS
driver = printer_cups_get_driver();
#endif
#if defined(_WIN32) && !defined(_UWP)
driver = printer_win_get_driver();
UINT error = CHANNEL_RC_OK;
if (!pEntryPoints || !pEntryPoints->device)
return ERROR_INVALID_PARAMETER;
device = (RDPDR_PRINTER*)pEntryPoints->device;
name = device->Name;
driver_name = _strdup(device->DriverName);
/* Secondary argument is one of the following:
*
* <driver_name> ... name of a printer driver
* <driver_name>:<backend_name> ... name of a printer driver and local printer backend to use
*/
if (driver_name)
{
char* sep = strstr(driver_name, ":");
if (sep)
{
const char* backend = sep + 1;
*sep = '\0';
driver = printer_load_backend(backend);
default_backend = FALSE;
}
}
if (!driver && default_backend)
{
const char* backend =
#if defined(WITH_CUPS)
"cups"
#elif defined(_WIN32)
"win"
#else
""
#endif
;
driver = printer_load_backend(backend);
}
if (!driver)
{
WLog_ERR(TAG, "Could not get a printer driver!");
return CHANNEL_RC_INITIALIZATION_ERROR;
error = CHANNEL_RC_INITIALIZATION_ERROR;
goto fail;
}
device = (RDPDR_PRINTER*) pEntryPoints->device;
name = device->Name;
driver_name = device->DriverName;
if (name && name[0])
{
printer = driver->GetPrinter(driver, name, driver_name);
rdpPrinter* printer = driver->GetPrinter(driver, name, driver_name);
if (!printer)
{
WLog_ERR(TAG, "Could not get printer %s!", name);
return CHANNEL_RC_INITIALIZATION_ERROR;
error = CHANNEL_RC_INITIALIZATION_ERROR;
goto fail;
}
if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer))
return CHANNEL_RC_INITIALIZATION_ERROR;
{
error = CHANNEL_RC_INITIALIZATION_ERROR;
printer->ReleaseRef(printer);
goto fail;
}
if ((error = printer_register(pEntryPoints, printer)))
{
WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error);
return error;
WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error);
printer->ReleaseRef(printer);
goto fail;
}
}
else
{
printers = driver->EnumPrinters(driver);
rdpPrinter** printers = driver->EnumPrinters(driver);
rdpPrinter** current = printers;
for (i = 0; printers[i]; i++)
for (i = 0; current[i]; i++)
{
printer = printers[i];
rdpPrinter* printer = current[i];
if ((error = printer_register(pEntryPoints, printer)))
{
WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error);
free(printers);
return error;
WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error);
break;
}
}
free(printers);
driver->ReleaseEnumPrinters(printers);
}
return CHANNEL_RC_OK;
fail:
free(driver_name);
if (driver)
driver->ReleaseRef(driver);
return error;
}

View File

@ -1,341 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Print Virtual Channel - WIN driver
*
* Copyright 2012 Gerald Richter
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/string.h>
#include <winpr/windows.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winspool.h>
#include "printer_main.h"
#include "printer_win.h"
typedef struct rdp_win_printer_driver rdpWinPrinterDriver;
typedef struct rdp_win_printer rdpWinPrinter;
typedef struct rdp_win_print_job rdpWinPrintJob;
struct rdp_win_printer_driver
{
rdpPrinterDriver driver;
int id_sequence;
};
struct rdp_win_printer
{
rdpPrinter printer;
HANDLE hPrinter;
rdpWinPrintJob* printjob;
};
struct rdp_win_print_job
{
rdpPrintJob printjob;
DOC_INFO_1 di;
DWORD handle;
void* printjob_object;
int printjob_id;
};
static void printer_win_get_printjob_name(char* buf, int size)
{
time_t tt;
struct tm* t;
tt = time(NULL);
t = localtime(&tt);
sprintf_s(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
{
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
LPVOID pBuf = data;
DWORD cbBuf = size;
DWORD pcWritten;
if(!WritePrinter(((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten))
return ERROR_INTERNAL_ERROR;
return CHANNEL_RC_OK;
}
static void printer_win_close_printjob(rdpPrintJob* printjob)
{
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
if (!EndPagePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
{
}
if (!ClosePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
{
}
((rdpWinPrinter*) printjob->printer)->printjob = NULL;
free(win_printjob);
}
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
rdpWinPrintJob* win_printjob;
if (win_printer->printjob != NULL)
return NULL;
win_printjob = (rdpWinPrintJob*) calloc(1, sizeof(rdpWinPrintJob));
if (!win_printjob)
return NULL;
win_printjob->printjob.id = id;
win_printjob->printjob.printer = printer;
win_printjob->di.pDocName = L"FREERDPjob";
win_printjob->di.pDatatype= NULL;
win_printjob->di.pOutputFile = NULL;
win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) &(win_printjob->di));
if (!win_printjob->handle)
{
free(win_printjob);
return NULL;
}
if (!StartPagePrinter(win_printer->hPrinter))
{
free(win_printjob);
return NULL;
}
win_printjob->printjob.Write = printer_win_write_printjob;
win_printjob->printjob.Close = printer_win_close_printjob;
win_printer->printjob = win_printjob;
return (rdpPrintJob*) win_printjob;
}
static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
if (!win_printer->printjob)
return NULL;
if (win_printer->printjob->printjob.id != id)
return NULL;
return (rdpPrintJob*) win_printer->printjob;
}
static void printer_win_free_printer(rdpPrinter* printer)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
if (win_printer->printjob)
win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob);
free(printer->name);
free(printer->driver);
free(printer);
}
static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver,
const WCHAR* name, const WCHAR* drivername, BOOL is_default)
{
rdpWinPrinter* win_printer;
DWORD needed = 0;
int status;
PRINTER_INFO_2 *prninfo=NULL;
win_printer = (rdpWinPrinter*) calloc(1, sizeof(rdpWinPrinter));
if (!win_printer)
return NULL;
win_printer->printer.id = win_driver->id_sequence++;
if (ConvertFromUnicode(CP_UTF8, 0, name, -1, &win_printer->printer.name, 0, NULL, NULL) < 1)
{
free(win_printer);
return NULL;
}
if (!win_printer->printer.name)
{
free(win_printer);
return NULL;
}
win_printer->printer.is_default = is_default;
win_printer->printer.CreatePrintJob = printer_win_create_printjob;
win_printer->printer.FindPrintJob = printer_win_find_printjob;
win_printer->printer.Free = printer_win_free_printer;
if (!OpenPrinter(name, &(win_printer->hPrinter), NULL))
{
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
/* How many memory should be allocated for printer data */
GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed);
if (needed == 0)
{
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
if (!prninfo)
{
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, needed, &needed))
{
GlobalFree(prninfo);
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
if (drivername)
status = ConvertFromUnicode(CP_UTF8, 0, drivername, -1, &win_printer->printer.driver, 0, NULL, NULL);
else
status = ConvertFromUnicode(CP_UTF8, 0, prninfo->pDriverName, -1, &win_printer->printer.driver, 0, NULL, NULL);
if (!win_printer->printer.driver || (status <= 0))
{
GlobalFree(prninfo);
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
return (rdpPrinter*)win_printer;
}
static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
{
rdpPrinter** printers;
int num_printers;
int i;
PRINTER_INFO_2* prninfo = NULL;
DWORD needed, returned;
/* find required size for the buffer */
EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
/* allocate array of PRINTER_INFO structures */
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
if (!prninfo)
return NULL;
/* call again */
if (!EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned))
{
}
printers = (rdpPrinter**) calloc((returned + 1), sizeof(rdpPrinter*));
if (!printers)
{
GlobalFree(prninfo);
return NULL;
}
num_printers = 0;
for (i = 0; i < (int) returned; i++)
{
printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver,
prninfo[i].pPrinterName, prninfo[i].pDriverName, 0);
}
GlobalFree(prninfo);
return printers;
}
static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver,
const char* name, const char* driverName)
{
WCHAR* driverNameW = NULL;
rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
rdpPrinter *myPrinter = NULL;
if (driverName)
{
ConvertToUnicode(CP_UTF8, 0, driverName, -1, &driverNameW, 0);
if (!driverNameW)
return NULL;
}
myPrinter = printer_win_new_printer(win_driver, name, driverNameW,
win_driver->id_sequence == 1 ? TRUE : FALSE);
free(driverNameW);
return myPrinter;
}
static rdpWinPrinterDriver* win_driver = NULL;
rdpPrinterDriver* printer_win_get_driver(void)
{
if (!win_driver)
{
win_driver = (rdpWinPrinterDriver*) calloc(1, sizeof(rdpWinPrinterDriver));
if (!win_driver)
return NULL;
win_driver->driver.EnumPrinters = printer_win_enum_printers;
win_driver->driver.GetPrinter = printer_win_get_printer;
win_driver->id_sequence = 1;
}
return (rdpPrinterDriver*) win_driver;
}

View File

@ -0,0 +1,29 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2019 Armin Novak <armin.novak@thincast.com>
# Copyright 2019 Thincast Technologies GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_client_subsystem("printer" "win" "")
set(${MODULE_PREFIX}_SRCS
printer_win.c)
include_directories(..)
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -0,0 +1,459 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Print Virtual Channel - WIN driver
*
* Copyright 2012 Gerald Richter
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/string.h>
#include <winpr/windows.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winspool.h>
#include <freerdp/client/printer.h>
#define PRINTER_TAG CHANNELS_TAG("printer.client")
#ifdef WITH_DEBUG_WINPR
#define DEBUG_WINPR(...) WLog_DBG(PRINTER_TAG, __VA_ARGS__)
#else
#define DEBUG_WINPR(...) \
do \
{ \
} while (0)
#endif
typedef struct rdp_win_printer_driver rdpWinPrinterDriver;
typedef struct rdp_win_printer rdpWinPrinter;
typedef struct rdp_win_print_job rdpWinPrintJob;
struct rdp_win_printer_driver
{
rdpPrinterDriver driver;
size_t id_sequence;
size_t references;
};
struct rdp_win_printer
{
rdpPrinter printer;
HANDLE hPrinter;
rdpWinPrintJob* printjob;
};
struct rdp_win_print_job
{
rdpPrintJob printjob;
DOC_INFO_1 di;
DWORD handle;
void* printjob_object;
int printjob_id;
};
static WCHAR* printer_win_get_printjob_name(size_t id)
{
time_t tt;
struct tm tres;
struct tm* t;
WCHAR* str;
size_t len = 1024;
int rc;
tt = time(NULL);
t = localtime_s(&tt, &tres);
str = calloc(len, sizeof(WCHAR));
if (!str)
return NULL;
rc = swprintf_s(str, len, L"FreeRDP Print %04d-%02d-%02d% 02d-%02d-%02d - Job %lu\0",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
id);
return str;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT printer_win_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size)
{
rdpWinPrinter* printer;
LPCVOID pBuf = data;
DWORD cbBuf = size;
DWORD pcWritten;
if (!printjob || !data)
return ERROR_BAD_ARGUMENTS;
printer = (rdpWinPrinter*)printjob->printer;
if (!printer)
return ERROR_BAD_ARGUMENTS;
if (!WritePrinter(printer->hPrinter, pBuf, cbBuf, &pcWritten))
return ERROR_INTERNAL_ERROR;
return CHANNEL_RC_OK;
}
static void printer_win_close_printjob(rdpPrintJob* printjob)
{
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
rdpWinPrinter* win_printer;
if (!printjob)
return;
win_printer = (rdpWinPrinter*)printjob->printer;
if (!win_printer)
return;
if (!EndPagePrinter(win_printer->hPrinter))
{
}
if (!ClosePrinter(win_printer->hPrinter))
{
}
win_printer->printjob = NULL;
free(win_printjob->di.pDocName);
free(win_printjob);
}
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
rdpWinPrintJob* win_printjob;
if (win_printer->printjob != NULL)
return NULL;
win_printjob = (rdpWinPrintJob*)calloc(1, sizeof(rdpWinPrintJob));
if (!win_printjob)
return NULL;
win_printjob->printjob.id = id;
win_printjob->printjob.printer = printer;
win_printjob->di.pDocName = printer_win_get_printjob_name(id);
win_printjob->di.pDatatype = NULL;
win_printjob->di.pOutputFile = NULL;
win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) & (win_printjob->di));
if (!win_printjob->handle)
{
free(win_printjob->di.pDocName);
free(win_printjob);
return NULL;
}
if (!StartPagePrinter(win_printer->hPrinter))
{
free(win_printjob->di.pDocName);
free(win_printjob);
return NULL;
}
win_printjob->printjob.Write = printer_win_write_printjob;
win_printjob->printjob.Close = printer_win_close_printjob;
win_printer->printjob = win_printjob;
return &win_printjob->printjob;
}
static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
if (!win_printer->printjob)
return NULL;
if (win_printer->printjob->printjob.id != id)
return NULL;
return (rdpPrintJob*)win_printer->printjob;
}
static void printer_win_free_printer(rdpPrinter* printer)
{
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
if (win_printer->printjob)
win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob);
if (printer->backend)
printer->backend->ReleaseRef(printer->backend);
free(printer->name);
free(printer->driver);
free(printer);
}
static void printer_win_add_ref_printer(rdpPrinter* printer)
{
if (printer)
printer->references++;
}
static void printer_win_release_ref_printer(rdpPrinter* printer)
{
if (!printer)
return;
if (printer->references <= 1)
printer_win_free_printer(printer);
else
printer->references--;
}
static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, const WCHAR* name,
const WCHAR* drivername, BOOL is_default)
{
rdpWinPrinter* win_printer;
DWORD needed = 0;
int status;
PRINTER_INFO_2* prninfo = NULL;
win_printer = (rdpWinPrinter*)calloc(1, sizeof(rdpWinPrinter));
if (!win_printer)
return NULL;
win_printer->printer.backend = &win_driver->driver;
win_printer->printer.id = win_driver->id_sequence++;
if (ConvertFromUnicode(CP_UTF8, 0, name, -1, &win_printer->printer.name, 0, NULL, NULL) < 1)
{
free(win_printer);
return NULL;
}
if (!win_printer->printer.name)
{
free(win_printer);
return NULL;
}
win_printer->printer.is_default = is_default;
win_printer->printer.CreatePrintJob = printer_win_create_printjob;
win_printer->printer.FindPrintJob = printer_win_find_printjob;
win_printer->printer.AddRef = printer_win_add_ref_printer;
win_printer->printer.ReleaseRef = printer_win_release_ref_printer;
if (!OpenPrinter(name, &(win_printer->hPrinter), NULL))
{
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
/* How many memory should be allocated for printer data */
GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, 0, &needed);
if (needed == 0)
{
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
if (!prninfo)
{
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, needed, &needed))
{
GlobalFree(prninfo);
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
if (drivername)
status = ConvertFromUnicode(CP_UTF8, 0, drivername, -1, &win_printer->printer.driver, 0,
NULL, NULL);
else
status = ConvertFromUnicode(CP_UTF8, 0, prninfo->pDriverName, -1,
&win_printer->printer.driver, 0, NULL, NULL);
if (!win_printer->printer.driver || (status <= 0))
{
GlobalFree(prninfo);
free(win_printer->printer.name);
free(win_printer);
return NULL;
}
win_printer->printer.AddRef(&win_printer->printer);
win_printer->printer.backend->AddRef(win_printer->printer.backend);
return &win_printer->printer;
}
static void printer_win_release_enum_printers(rdpPrinter** printers)
{
rdpPrinter** cur = printers;
while ((cur != NULL) && ((*cur) != NULL))
{
if ((*cur)->ReleaseRef)
(*cur)->ReleaseRef(*cur);
cur++;
}
free(printers);
}
static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
{
rdpPrinter** printers;
int num_printers;
int i;
PRINTER_INFO_2* prninfo = NULL;
DWORD needed, returned;
/* find required size for the buffer */
EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed,
&returned);
/* allocate array of PRINTER_INFO structures */
prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed);
if (!prninfo)
return NULL;
/* call again */
if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE)prninfo,
needed, &needed, &returned))
{
}
printers = (rdpPrinter**)calloc((returned + 1), sizeof(rdpPrinter*));
if (!printers)
{
GlobalFree(prninfo);
return NULL;
}
num_printers = 0;
for (i = 0; i < (int)returned; i++)
{
rdpPrinter* current = printers[num_printers];
current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName,
prninfo[i].pDriverName, 0);
if (!current)
{
printer_win_release_enum_printers(printers);
printers = NULL;
break;
}
printers[num_printers++] = current;
}
GlobalFree(prninfo);
return printers;
}
static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char* name,
const char* driverName)
{
WCHAR* driverNameW = NULL;
WCHAR* nameW = NULL;
rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
rdpPrinter* myPrinter = NULL;
if (name)
{
ConvertToUnicode(CP_UTF8, 0, name, -1, &nameW, 0);
if (!driverNameW)
return NULL;
}
if (driverName)
{
ConvertToUnicode(CP_UTF8, 0, driverName, -1, &driverNameW, 0);
if (!driverNameW)
return NULL;
}
myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW,
win_driver->id_sequence == 1 ? TRUE : FALSE);
free(driverNameW);
free(nameW);
return myPrinter;
}
static void printer_win_add_ref_driver(rdpPrinterDriver* driver)
{
rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
if (win)
win->references++;
}
/* Singleton */
static rdpWinPrinterDriver* win_driver = NULL;
static void printer_win_release_ref_driver(rdpPrinterDriver* driver)
{
rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver;
if (win->references <= 1)
{
free(win);
win_driver = NULL;
}
else
win->references--;
}
#ifdef BUILTIN_CHANNELS
rdpPrinterDriver* win_freerdp_printer_client_subsystem_entry(void)
#else
FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void)
#endif
{
if (!win_driver)
{
win_driver = (rdpWinPrinterDriver*)calloc(1, sizeof(rdpWinPrinterDriver));
if (!win_driver)
return NULL;
win_driver->driver.EnumPrinters = printer_win_enum_printers;
win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers;
win_driver->driver.GetPrinter = printer_win_get_printer;
win_driver->driver.AddRef = printer_win_add_ref_driver;
win_driver->driver.ReleaseRef = printer_win_release_ref_driver;
win_driver->id_sequence = 1;
}
win_driver->driver.AddRef(&win_driver->driver);
return &win_driver->driver;
}

View File

@ -21,17 +21,16 @@
#define FREERDP_CHANNEL_PRINTER_PRINTER_H
/* SERVER_PRINTER_CACHE_EVENT.cachedata */
#define RDPDR_ADD_PRINTER_EVENT 0x00000001
#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002
#define RDPDR_DELETE_PRINTER_EVENT 0x00000003
#define RDPDR_RENAME_PRINTER_EVENT 0x00000004
#define RDPDR_ADD_PRINTER_EVENT 0x00000001
#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002
#define RDPDR_DELETE_PRINTER_EVENT 0x00000003
#define RDPDR_RENAME_PRINTER_EVENT 0x00000004
/* DR_PRN_DEVICE_ANNOUNCE.Flags */
#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001
#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002
#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004
#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008
#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010
#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001
#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002
#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004
#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008
#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010
#endif /* FREERDP_CHANNEL_PRINTER_PRINTER_H */

View File

@ -20,3 +20,7 @@ define_channel("rail")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -42,7 +42,7 @@ RailClientContext* rail_get_client_interface(railPlugin* rail)
if (!rail)
return NULL;
pInterface = (RailClientContext*) rail->channelEntryPoints.pInterface;
pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface;
return pInterface;
}
@ -56,15 +56,18 @@ static UINT rail_send(railPlugin* rail, wStream* s)
UINT status;
if (!rail)
{
Stream_Free(s, TRUE);
return CHANNEL_RC_BAD_INIT_HANDLE;
}
status = rail->channelEntryPoints.pVirtualChannelWriteEx(rail->InitHandle, rail->OpenHandle,
Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s);
status = rail->channelEntryPoints.pVirtualChannelWriteEx(
rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s);
if (status != CHANNEL_RC_OK)
{
Stream_Free(s, TRUE);
WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08"PRIX32"]",
WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
WTSErrorToString(status), status);
}
@ -76,13 +79,15 @@ static UINT rail_send(railPlugin* rail, wStream* s)
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length)
UINT rail_send_channel_data(railPlugin* rail, wStream* src)
{
wStream* s = NULL;
wStream* s;
size_t length;
if (!rail || !data)
if (!rail || !src)
return ERROR_INVALID_PARAMETER;
length = Stream_GetPosition(src);
s = Stream_New(NULL, length);
if (!s)
@ -91,7 +96,7 @@ UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length)
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write(s, data, length);
Stream_Write(s, Stream_Buffer(src), length);
return rail_send(rail, s);
}
@ -104,8 +109,7 @@ UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_client_execute(RailClientContext* context,
const RAIL_EXEC_ORDER* exec)
static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDER* exec)
{
char* exeOrFile;
UINT error;
@ -118,25 +122,19 @@ static UINT rail_client_execute(RailClientContext* context,
if (!context || !exec)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
exeOrFile = exec->RemoteApplicationProgram;
flags = exec->flags;
if (!exeOrFile)
return ERROR_INVALID_PARAMETER;
if (strnlen(exeOrFile, MAX_PATH) >= 2)
{
if (strncmp(exeOrFile, "||", 2) != 0)
flags |= RAIL_EXEC_FLAG_FILE;
}
if (!rail_string_to_unicode_string(exec->RemoteApplicationProgram,
&ruExeOrFile) || /* RemoteApplicationProgram */
!rail_string_to_unicode_string(exec->RemoteApplicationWorkingDir,
&ruWorkingDir) || /* ShellWorkingDirectory */
!rail_string_to_unicode_string(exec->RemoteApplicationArguments,
&ruArguments)) /* RemoteApplicationCmdLine */
if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram,
&ruExeOrFile) || /* RemoteApplicationProgram */
!utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir,
&ruWorkingDir) || /* ShellWorkingDirectory */
!utf8_string_to_rail_string(exec->RemoteApplicationArguments,
&ruArguments)) /* RemoteApplicationCmdLine */
error = ERROR_INTERNAL_ERROR;
else
error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments);
@ -152,15 +150,14 @@ static UINT rail_client_execute(RailClientContext* context,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_client_activate(RailClientContext* context,
const RAIL_ACTIVATE_ORDER* activate)
static UINT rail_client_activate(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate)
{
railPlugin* rail;
if (!context || !activate)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_activate_order(rail, activate);
}
@ -169,18 +166,18 @@ static UINT rail_client_activate(RailClientContext* context,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_send_client_sysparam(RailClientContext* context,
RAIL_SYSPARAM_ORDER* sysparam)
static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_ORDER* sysparam)
{
wStream* s;
size_t length = RAIL_SYSPARAM_ORDER_LENGTH;
railPlugin* rail;
UINT error;
BOOL extendedSpiSupported;
if (!context || !sysparam)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
switch (sysparam->param)
{
@ -201,9 +198,18 @@ static UINT rail_send_client_sysparam(RailClientContext* context,
length += sysparam->highContrast.colorSchemeLength + 10;
break;
default:
length += 8;
case SPI_SETFILTERKEYS:
length += 20;
break;
case SPI_SETSTICKYKEYS:
case SPI_SETCARETWIDTH:
case SPI_SETTOGGLEKEYS:
length += 4;
break;
default:
return ERROR_BAD_ARGUMENTS;
}
s = rail_pdu_init(length);
@ -214,16 +220,17 @@ static UINT rail_send_client_sysparam(RailClientContext* context,
return CHANNEL_RC_NO_MEMORY;
}
if ((error = rail_write_client_sysparam_order(s, sysparam)))
extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags);
if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported)))
{
WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error);
Stream_Free(s, TRUE);
return error;
}
if ((error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSPARAM)))
if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM)))
{
WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error);
}
Stream_Free(s, TRUE);
@ -252,7 +259,7 @@ static UINT rail_client_system_param(RailClientContext* context,
if ((error = rail_send_client_sysparam(context, &sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
return error;
}
}
@ -263,7 +270,7 @@ static UINT rail_client_system_param(RailClientContext* context,
if ((error = rail_send_client_sysparam(context, &sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
return error;
}
}
@ -274,7 +281,7 @@ static UINT rail_client_system_param(RailClientContext* context,
if ((error = rail_send_client_sysparam(context, &sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
return error;
}
}
@ -285,7 +292,7 @@ static UINT rail_client_system_param(RailClientContext* context,
if ((error = rail_send_client_sysparam(context, &sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
return error;
}
}
@ -296,7 +303,7 @@ static UINT rail_client_system_param(RailClientContext* context,
if ((error = rail_send_client_sysparam(context, &sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
return error;
}
}
@ -307,7 +314,7 @@ static UINT rail_client_system_param(RailClientContext* context,
if ((error = rail_send_client_sysparam(context, &sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
return error;
}
}
@ -318,7 +325,7 @@ static UINT rail_client_system_param(RailClientContext* context,
if ((error = rail_send_client_sysparam(context, &sysparam)))
{
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error);
return error;
}
}
@ -326,20 +333,6 @@ static UINT rail_client_system_param(RailClientContext* context,
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_system_param(RailClientContext* context,
const RAIL_SYSPARAM_ORDER* sysparam)
{
if (!context || !sysparam)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
@ -353,7 +346,7 @@ static UINT rail_client_system_command(RailClientContext* context,
if (!context || !syscommand)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_syscommand_order(rail, syscommand);
}
@ -362,63 +355,17 @@ static UINT rail_client_system_command(RailClientContext* context,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_client_handshake(RailClientContext* context,
const RAIL_HANDSHAKE_ORDER* handshake)
static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake)
{
railPlugin* rail;
if (!context || !handshake)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_handshake_order(rail, handshake);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_handshake(RailClientContext* context,
const RAIL_HANDSHAKE_ORDER* handshake)
{
if (!context || !handshake)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_client_handshake_ex(RailClientContext* context,
const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
{
railPlugin* rail;
if (!context || !handshakeEx)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
return rail_send_handshake_ex_order(rail, handshakeEx);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_handshake_ex(RailClientContext* context,
const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
{
if (!context || !handshakeEx)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
@ -432,7 +379,7 @@ static UINT rail_client_notify_event(RailClientContext* context,
if (!context || !notifyEvent)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_notify_event_order(rail, notifyEvent);
}
@ -449,38 +396,10 @@ static UINT rail_client_window_move(RailClientContext* context,
if (!context || !windowMove)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_window_move_order(rail, windowMove);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_local_move_size(RailClientContext* context,
const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
{
if (!context || !localMoveSize)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_min_max_info(RailClientContext* context,
const RAIL_MINMAXINFO_ORDER* minMaxInfo)
{
if (!context || !minMaxInfo)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
@ -494,7 +413,7 @@ static UINT rail_client_information(RailClientContext* context,
if (!context || !clientStatus)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_status_order(rail, clientStatus);
}
@ -503,15 +422,14 @@ static UINT rail_client_information(RailClientContext* context,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_client_system_menu(RailClientContext* context,
const RAIL_SYSMENU_ORDER* sysmenu)
static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu)
{
railPlugin* rail;
if (!context || !sysmenu)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_sysmenu_order(rail, sysmenu);
}
@ -521,43 +439,27 @@ static UINT rail_client_system_menu(RailClientContext* context,
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_client_language_bar_info(RailClientContext* context,
const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
{
railPlugin* rail;
if (!context || !langBarInfo)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_langbar_info_order(rail, langBarInfo);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_language_bar_info(RailClientContext* context,
const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
static UINT rail_client_language_ime_info(RailClientContext* context,
const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo)
{
if (!context || !langBarInfo)
railPlugin* rail;
if (!context || !langImeInfo)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_execute_result(RailClientContext* context,
const RAIL_EXEC_RESULT_ORDER* execResult)
{
if (!context || !execResult)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
rail = (railPlugin*)context->handle;
return rail_send_client_languageime_info_order(rail, langImeInfo);
}
/**
@ -566,29 +468,49 @@ static UINT rail_server_execute_result(RailClientContext* context,
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_client_get_appid_request(RailClientContext* context,
const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
const RAIL_GET_APPID_REQ_ORDER* getAppIdReq)
{
railPlugin* rail;
if (!context || !getAppIdReq || !context->handle)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*) context->handle;
rail = (railPlugin*)context->handle;
return rail_send_client_get_appid_req_order(rail, getAppIdReq);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_server_get_appid_response(RailClientContext* context,
const RAIL_GET_APPID_RESP_ORDER* getAppIdResp)
static UINT rail_client_compartment_info(RailClientContext* context,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo)
{
if (!context || !getAppIdResp)
railPlugin* rail;
if (!context || !compartmentInfo || !context->handle)
return ERROR_INVALID_PARAMETER;
return CHANNEL_RC_OK; /* stub - should be registered by client */
rail = (railPlugin*)context->handle;
return rail_send_client_compartment_info_order(rail, compartmentInfo);
}
static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak)
{
railPlugin* rail;
if (!context || !cloak || !context->handle)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*)context->handle;
return rail_send_client_cloak_order(rail, cloak);
}
static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap)
{
railPlugin* rail;
if (!context || !snap || !context->handle)
return ERROR_INVALID_PARAMETER;
rail = (railPlugin*)context->handle;
return rail_send_client_snap_arrange_order(rail, snap);
}
/**
@ -596,8 +518,9 @@ static UINT rail_server_get_appid_response(RailClientContext* context,
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_virtual_channel_event_data_received(railPlugin* rail,
void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
static UINT rail_virtual_channel_event_data_received(railPlugin* rail, void* pData,
UINT32 dataLength, UINT32 totalLength,
UINT32 dataFlags)
{
wStream* data_in;
@ -622,7 +545,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail,
data_in = rail->data_in;
if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength))
if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
@ -634,7 +557,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail,
{
if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
{
WLog_ERR(TAG, "rail_plugin_process_received: read error");
WLog_ERR(TAG, "rail_plugin_process_received: read error");
return ERROR_INTERNAL_ERROR;
}
@ -642,7 +565,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail,
Stream_SealLength(data_in);
Stream_SetPosition(data_in, 0);
if (!MessageQueue_Post(rail->queue, NULL, 0, (void*) data_in, NULL))
if (!MessageQueue_Post(rail->queue, NULL, 0, (void*)data_in, NULL))
{
WLog_ERR(TAG, "MessageQueue_Post failed!");
return ERROR_INTERNAL_ERROR;
@ -653,36 +576,42 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail,
}
static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
UINT event,
LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
UINT event, LPVOID pData,
UINT32 dataLength, UINT32 totalLength,
UINT32 dataFlags)
{
UINT error = CHANNEL_RC_OK;
railPlugin* rail = (railPlugin*) lpUserParam;
if (!rail || (rail->OpenHandle != openHandle))
{
WLog_ERR(TAG, "error no match");
return;
}
railPlugin* rail = (railPlugin*)lpUserParam;
switch (event)
{
case CHANNEL_EVENT_DATA_RECEIVED:
if (!rail || (rail->OpenHandle != openHandle))
{
WLog_ERR(TAG, "error no match");
return;
}
if ((error = rail_virtual_channel_event_data_received(rail, pData, dataLength,
totalLength, dataFlags)))
WLog_ERR(TAG, "rail_virtual_channel_event_data_received failed with error %"PRIu32"!",
totalLength, dataFlags)))
WLog_ERR(TAG,
"rail_virtual_channel_event_data_received failed with error %" PRIu32 "!",
error);
break;
case CHANNEL_EVENT_WRITE_CANCELLED:
case CHANNEL_EVENT_WRITE_COMPLETE:
break;
{
wStream* s = (wStream*)pData;
Stream_Free(s, TRUE);
}
break;
case CHANNEL_EVENT_USER:
break;
}
if (error && rail->rdpcontext)
if (error && rail && rail->rdpcontext)
setChannelError(rail->rdpcontext, error,
"rail_virtual_channel_open_event reported an error");
@ -693,7 +622,7 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg)
{
wStream* data;
wMessage message;
railPlugin* rail = (railPlugin*) arg;
railPlugin* rail = (railPlugin*)arg;
UINT error = CHANNEL_RC_OK;
while (1)
@ -717,13 +646,13 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg)
if (message.id == 0)
{
data = (wStream*) message.wParam;
data = (wStream*)message.wParam;
error = rail_order_recv(rail, data);
Stream_Free(data, TRUE);
if (error)
{
WLog_ERR(TAG, "rail_order_recv failed with error %"PRIu32"!", error);
WLog_ERR(TAG, "rail_order_recv failed with error %" PRIu32 "!", error);
break;
}
}
@ -742,20 +671,30 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg)
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData,
UINT32 dataLength)
static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength)
{
RailClientContext* context = rail_get_client_interface(rail);
UINT status;
status = rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle,
&rail->OpenHandle, rail->channelDef.name, rail_virtual_channel_open_event_ex);
status = rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle,
rail->channelDef.name,
rail_virtual_channel_open_event_ex);
if (status != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08"PRIX32"]",
WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08" PRIX32 "]",
WTSErrorToString(status), status);
return status;
}
if (context)
{
IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake);
if (status != CHANNEL_RC_OK)
WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]",
WTSErrorToString(status), status);
}
rail->queue = MessageQueue_New(NULL);
if (!rail->queue)
@ -764,9 +703,8 @@ static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData,
return CHANNEL_RC_NO_MEMORY;
}
if (!(rail->thread = CreateThread(NULL, 0,
rail_virtual_channel_client_thread, (void*) rail, 0,
NULL)))
if (!(rail->thread =
CreateThread(NULL, 0, rail_virtual_channel_client_thread, (void*)rail, 0, NULL)))
{
WLog_ERR(TAG, "CreateThread failed!");
MessageQueue_Free(rail->queue);
@ -789,11 +727,11 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
if (rail->OpenHandle == 0)
return CHANNEL_RC_OK;
if (MessageQueue_PostQuit(rail->queue, 0)
&& (WaitForSingleObject(rail->thread, INFINITE) == WAIT_FAILED))
if (MessageQueue_PostQuit(rail->queue, 0) &&
(WaitForSingleObject(rail->thread, INFINITE) == WAIT_FAILED))
{
rc = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", rc);
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
return rc;
}
@ -805,8 +743,8 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail)
if (CHANNEL_RC_OK != rc)
{
WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08"PRIX32"]",
WTSErrorToString(rc), rc);
WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
rc);
return rc;
}
@ -829,14 +767,14 @@ static void rail_virtual_channel_event_terminated(railPlugin* rail)
}
static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
UINT event, LPVOID pData, UINT dataLength)
UINT event, LPVOID pData, UINT dataLength)
{
UINT error = CHANNEL_RC_OK;
railPlugin* rail = (railPlugin*) lpUserParam;
railPlugin* rail = (railPlugin*)lpUserParam;
if (!rail || (rail->InitHandle != pInitHandle))
{
WLog_ERR(TAG, "error no match");
WLog_ERR(TAG, "error no match");
return;
}
@ -844,14 +782,15 @@ static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPV
{
case CHANNEL_EVENT_CONNECTED:
if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength)))
WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %"PRIu32"!",
WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!",
error);
break;
case CHANNEL_EVENT_DISCONNECTED:
if ((error = rail_virtual_channel_event_disconnected(rail)))
WLog_ERR(TAG, "rail_virtual_channel_event_disconnected failed with error %"PRIu32"!",
WLog_ERR(TAG,
"rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!",
error);
break;
@ -867,11 +806,12 @@ static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPV
}
if (error && rail->rdpcontext)
setChannelError(rail->rdpcontext, error, "rail_virtual_channel_init_event_ex reported an error");
setChannelError(rail->rdpcontext, error,
"rail_virtual_channel_init_event_ex reported an error");
}
/* rail is always built-in */
#define VirtualChannelEntryEx rail_VirtualChannelEntryEx
#define VirtualChannelEntryEx rail_VirtualChannelEntryEx
BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
{
@ -880,7 +820,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
RailClientContext* context = NULL;
CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx;
BOOL isFreerdp = FALSE;
rail = (railPlugin*) calloc(1, sizeof(railPlugin));
rail = (railPlugin*)calloc(1, sizeof(railPlugin));
if (!rail)
{
@ -888,18 +828,17 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
return FALSE;
}
rail->channelDef.options =
CHANNEL_OPTION_INITIALIZED |
CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP |
CHANNEL_OPTION_SHOW_PROTOCOL;
sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), "rail");
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints;
/* Default to automatically replying to server handshakes */
rail->sendHandshake = TRUE;
rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME);
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
{
context = (RailClientContext*) calloc(1, sizeof(RailClientContext));
context = (RailClientContext*)calloc(1, sizeof(RailClientContext));
if (!context)
{
@ -908,28 +847,23 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
return FALSE;
}
context->handle = (void*) rail;
context->handle = (void*)rail;
context->custom = NULL;
context->ClientExecute = rail_client_execute;
context->ClientActivate = rail_client_activate;
context->ClientSystemParam = rail_client_system_param;
context->ServerSystemParam = rail_server_system_param;
context->ClientSystemCommand = rail_client_system_command;
context->ClientHandshake = rail_client_handshake;
context->ServerHandshake = rail_server_handshake;
context->ClientHandshakeEx = rail_client_handshake_ex;
context->ServerHandshakeEx = rail_server_handshake_ex;
context->ClientNotifyEvent = rail_client_notify_event;
context->ClientWindowMove = rail_client_window_move;
context->ServerLocalMoveSize = rail_server_local_move_size;
context->ServerMinMaxInfo = rail_server_min_max_info;
context->ClientInformation = rail_client_information;
context->ClientSystemMenu = rail_client_system_menu;
context->ClientLanguageBarInfo = rail_client_language_bar_info;
context->ServerLanguageBarInfo = rail_server_language_bar_info;
context->ServerExecuteResult = rail_server_execute_result;
context->ClientLanguageIMEInfo = rail_client_language_ime_info;
context->ClientGetAppIdRequest = rail_client_get_appid_request;
context->ServerGetAppIdResponse = rail_server_get_appid_response;
context->ClientSnapArrange = rail_client_snap_arrange;
context->ClientCloak = rail_client_cloak;
context->ClientCompartmentInfo = rail_client_compartment_info;
rail->rdpcontext = pEntryPointsEx->context;
rail->context = context;
isFreerdp = TRUE;
@ -937,17 +871,15 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p
rail->log = WLog_Get("com.freerdp.channels.rail.client");
WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx");
CopyMemory(&(rail->channelEntryPoints), pEntryPoints,
sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
rail->InitHandle = pInitHandle;
rc = rail->channelEntryPoints.pVirtualChannelInitEx(rail, context, pInitHandle,
&rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
rail_virtual_channel_init_event_ex);
rc = rail->channelEntryPoints.pVirtualChannelInitEx(
rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
rail_virtual_channel_init_event_ex);
if (CHANNEL_RC_OK != rc)
{
WLog_ERR(TAG, "failed with %s [%08"PRIX32"]",
WTSErrorToString(rc), rc);
WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc);
goto error_out;
}

View File

@ -50,10 +50,14 @@ struct rail_plugin
DWORD OpenHandle;
wMessageQueue* queue;
rdpContext* rdpcontext;
DWORD channelBuildNumber;
DWORD channelFlags;
RAIL_CLIENT_STATUS_ORDER clientStatus;
BOOL sendHandshake;
};
typedef struct rail_plugin railPlugin;
RailClientContext* rail_get_client_interface(railPlugin* rail);
UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length);
UINT rail_send_channel_data(railPlugin* rail, wStream* s);
#endif /* FREERDP_CHANNEL_RAIL_CLIENT_MAIN_H */

File diff suppressed because it is too large Load Diff

View File

@ -29,8 +29,6 @@
#define TAG CHANNELS_TAG("rail.client")
UINT rail_write_client_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam);
UINT rail_order_recv(railPlugin* rail, wStream* s);
UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType);
@ -38,18 +36,25 @@ UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* han
UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx);
UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus);
UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags,
const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir,
const RAIL_UNICODE_STRING* exeOrFile,
const RAIL_UNICODE_STRING* workingDir,
const RAIL_UNICODE_STRING* arguments);
UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate);
UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu);
UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand);
UINT rail_send_client_notify_event_order(railPlugin* rail,
const RAIL_NOTIFY_EVENT_ORDER* notifyEvent);
const RAIL_NOTIFY_EVENT_ORDER* notifyEvent);
UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove);
UINT rail_send_client_get_appid_req_order(railPlugin* rail,
const RAIL_GET_APPID_REQ_ORDER* getAppIdReq);
const RAIL_GET_APPID_REQ_ORDER* getAppIdReq);
UINT rail_send_client_langbar_info_order(railPlugin* rail,
const RAIL_LANGBAR_INFO_ORDER* langBarInfo);
const RAIL_LANGBAR_INFO_ORDER* langBarInfo);
UINT rail_send_client_languageime_info_order(railPlugin* rail,
const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo);
UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak);
UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap);
UINT rail_send_client_compartment_info_order(railPlugin* rail,
const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo);
#endif /* FREERDP_CHANNEL_RAIL_CLIENT_ORDERS_H */

View File

@ -23,56 +23,76 @@
#include "rail_common.h"
#include <winpr/crt.h>
#include <freerdp/channels/log.h>
const char* const RAIL_ORDER_TYPE_STRINGS[] =
#define TAG CHANNELS_TAG("rail.common")
const char* rail_get_order_type_string(UINT16 orderType)
{
"",
"Execute",
"Activate",
"System Parameters Update",
"System Command",
"Handshake",
"Notify Event",
"",
"Window Move",
"Local Move/Size",
"Min Max Info",
"Client Status",
"System Menu",
"Language Bar Info",
"Get Application ID Request",
"Get Application ID Response",
"Execute Result",
"",
"",
"",
"",
"",
""
};
BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string)
{
WCHAR* buffer = NULL;
int length = 0;
free(unicode_string->string);
unicode_string->string = NULL;
unicode_string->length = 0;
if (!string || strlen(string) < 1)
return TRUE;
length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0);
if ((length < 0) || ((size_t)length * sizeof(WCHAR) > UINT16_MAX))
switch (orderType)
{
free(buffer);
return FALSE;
case TS_RAIL_ORDER_EXEC:
return "TS_RAIL_ORDER_EXEC";
case TS_RAIL_ORDER_ACTIVATE:
return "TS_RAIL_ORDER_ACTIVATE";
case TS_RAIL_ORDER_SYSPARAM:
return "TS_RAIL_ORDER_SYSPARAM";
case TS_RAIL_ORDER_SYSCOMMAND:
return "TS_RAIL_ORDER_SYSCOMMAND";
case TS_RAIL_ORDER_HANDSHAKE:
return "TS_RAIL_ORDER_HANDSHAKE";
case TS_RAIL_ORDER_NOTIFY_EVENT:
return "TS_RAIL_ORDER_NOTIFY_EVENT";
case TS_RAIL_ORDER_WINDOWMOVE:
return "TS_RAIL_ORDER_WINDOWMOVE";
case TS_RAIL_ORDER_LOCALMOVESIZE:
return "TS_RAIL_ORDER_LOCALMOVESIZE";
case TS_RAIL_ORDER_MINMAXINFO:
return "TS_RAIL_ORDER_MINMAXINFO";
case TS_RAIL_ORDER_CLIENTSTATUS:
return "TS_RAIL_ORDER_CLIENTSTATUS";
case TS_RAIL_ORDER_SYSMENU:
return "TS_RAIL_ORDER_SYSMENU";
case TS_RAIL_ORDER_LANGBARINFO:
return "TS_RAIL_ORDER_LANGBARINFO";
case TS_RAIL_ORDER_GET_APPID_REQ:
return "TS_RAIL_ORDER_GET_APPID_REQ";
case TS_RAIL_ORDER_GET_APPID_RESP:
return "TS_RAIL_ORDER_GET_APPID_RESP";
case TS_RAIL_ORDER_TASKBARINFO:
return "TS_RAIL_ORDER_TASKBARINFO";
case TS_RAIL_ORDER_LANGUAGEIMEINFO:
return "TS_RAIL_ORDER_LANGUAGEIMEINFO";
case TS_RAIL_ORDER_COMPARTMENTINFO:
return "TS_RAIL_ORDER_COMPARTMENTINFO";
case TS_RAIL_ORDER_HANDSHAKE_EX:
return "TS_RAIL_ORDER_HANDSHAKE_EX";
case TS_RAIL_ORDER_ZORDER_SYNC:
return "TS_RAIL_ORDER_ZORDER_SYNC";
case TS_RAIL_ORDER_CLOAK:
return "TS_RAIL_ORDER_CLOAK";
case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST:
return "TS_RAIL_ORDER_POWER_DISPLAY_REQUEST";
case TS_RAIL_ORDER_SNAP_ARRANGE:
return "TS_RAIL_ORDER_SNAP_ARRANGE";
case TS_RAIL_ORDER_GET_APPID_RESP_EX:
return "TS_RAIL_ORDER_GET_APPID_RESP_EX";
case TS_RAIL_ORDER_EXEC_RESULT:
return "TS_RAIL_ORDER_EXEC_RESULT";
case TS_RAIL_ORDER_TEXTSCALEINFO:
return "TS_RAIL_ORDER_TEXTSCALEINFO";
case TS_RAIL_ORDER_CARETBLINKINFO:
return "TS_RAIL_ORDER_CARETBLINKINFO";
default:
return "TS_RAIL_ORDER_UNKNOWN";
}
}
unicode_string->string = (BYTE*) buffer;
unicode_string->length = (UINT16) length * sizeof(WCHAR);
return TRUE;
const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length)
{
_snprintf(buffer, length, "%s[0x%04" PRIx16 "]", rail_get_order_type_string(orderType),
orderType);
return buffer;
}
/**
@ -88,14 +108,14 @@ UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength)
if (Stream_GetRemainingLength(s) < 4)
return ERROR_INVALID_DATA;
Stream_Read_UINT16(s, *orderType); /* orderType (2 bytes) */
Stream_Read_UINT16(s, *orderType); /* orderType (2 bytes) */
Stream_Read_UINT16(s, *orderLength); /* orderLength (2 bytes) */
return CHANNEL_RC_OK;
}
void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength)
{
Stream_Write_UINT16(s, orderType); /* orderType (2 bytes) */
Stream_Write_UINT16(s, orderType); /* orderType (2 bytes) */
Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */
}
@ -140,13 +160,459 @@ UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshake
if (Stream_GetRemainingLength(s) < 8)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
return CHANNEL_RC_OK;
}
void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
{
Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */
Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
{
if (!s || !unicode_string)
return ERROR_INVALID_PARAMETER;
if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
Stream_Write(s, unicode_string->string, unicode_string->length); /* string */
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
{
size_t length;
if (!s || !unicode_string)
return ERROR_INVALID_PARAMETER;
length = unicode_string->length;
if (length > 0)
{
if (!Stream_EnsureRemainingCapacity(s, length))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return CHANNEL_RC_NO_MEMORY;
}
Stream_Write(s, unicode_string->string, length); /* string */
}
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast)
{
if (!s || !highContrast)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 8)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, highContrast->flags); /* flags (4 bytes) */
Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */
if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */
return ERROR_INTERNAL_ERROR;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast)
{
UINT32 colorSchemeLength;
if (!s || !highContrast)
return ERROR_INVALID_PARAMETER;
if (!Stream_EnsureRemainingCapacity(s, 8))
return CHANNEL_RC_NO_MEMORY;
colorSchemeLength = highContrast->colorScheme.length + 2;
Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */
Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */
return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys)
{
if (!s || !filterKeys)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 20)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(s, filterKeys->Flags);
Stream_Read_UINT32(s, filterKeys->WaitTime);
Stream_Read_UINT32(s, filterKeys->DelayTime);
Stream_Read_UINT32(s, filterKeys->RepeatTime);
Stream_Read_UINT32(s, filterKeys->BounceTime);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys)
{
if (!s || !filterKeys)
return ERROR_INVALID_PARAMETER;
if (!Stream_EnsureRemainingCapacity(s, 20))
return CHANNEL_RC_NO_MEMORY;
Stream_Write_UINT32(s, filterKeys->Flags);
Stream_Write_UINT32(s, filterKeys->WaitTime);
Stream_Write_UINT32(s, filterKeys->DelayTime);
Stream_Write_UINT32(s, filterKeys->RepeatTime);
Stream_Write_UINT32(s, filterKeys->BounceTime);
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported)
{
BYTE body;
UINT error = CHANNEL_RC_OK;
if (!s || !sysparam)
return ERROR_INVALID_PARAMETER;
if (Stream_GetRemainingLength(s) < 5)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
sysparam->params = 0; /* bitflags of received params */
switch (sysparam->param)
{
/* Client sysparams */
case SPI_SET_DRAG_FULL_WINDOWS:
sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->dragFullWindows = body != 0;
break;
case SPI_SET_KEYBOARD_CUES:
sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES;
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->keyboardCues = body != 0;
break;
case SPI_SET_KEYBOARD_PREF:
sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF;
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->keyboardPref = body != 0;
break;
case SPI_SET_MOUSE_BUTTON_SWAP:
sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->mouseButtonSwap = body != 0;
break;
case SPI_SET_WORK_AREA:
sysparam->params |= SPI_MASK_SET_WORK_AREA;
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
Stream_Read_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
Stream_Read_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
break;
case SPI_DISPLAY_CHANGE:
sysparam->params |= SPI_MASK_DISPLAY_CHANGE;
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
Stream_Read_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
Stream_Read_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
break;
case SPI_TASKBAR_POS:
sysparam->params |= SPI_MASK_TASKBAR_POS;
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
Stream_Read_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
Stream_Read_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
break;
case SPI_SET_HIGH_CONTRAST:
sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST;
if (Stream_GetRemainingLength(s) < 8)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
error = rail_read_high_contrast(s, &sysparam->highContrast);
break;
case SPI_SETCARETWIDTH:
sysparam->params |= SPI_MASK_SET_CARET_WIDTH;
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, sysparam->caretWidth);
if (sysparam->caretWidth < 0x0001)
return ERROR_INVALID_DATA;
break;
case SPI_SETSTICKYKEYS:
sysparam->params |= SPI_MASK_SET_STICKY_KEYS;
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, sysparam->stickyKeys);
break;
case SPI_SETTOGGLEKEYS:
sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS;
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
Stream_Read_UINT32(s, sysparam->toggleKeys);
break;
case SPI_SETFILTERKEYS:
sysparam->params |= SPI_MASK_SET_FILTER_KEYS;
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
if (Stream_GetRemainingLength(s) < 20)
{
WLog_ERR(TAG, "Stream_GetRemainingLength failed!");
return ERROR_INVALID_DATA;
}
error = rail_read_filterkeys(s, &sysparam->filterKeys);
break;
/* Server sysparams */
case SPI_SETSCREENSAVEACTIVE:
sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE;
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->setScreenSaveActive = body != 0;
break;
case SPI_SETSCREENSAVESECURE:
sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE;
Stream_Read_UINT8(s, body); /* body (1 byte) */
sysparam->setScreenSaveSecure = body != 0;
break;
default:
break;
}
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 err2or code
*/
UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
BOOL extendedSpiSupported)
{
BYTE body;
UINT error = CHANNEL_RC_OK;
if (!s || !sysparam)
return ERROR_INVALID_PARAMETER;
if (!Stream_EnsureRemainingCapacity(s, 12))
return CHANNEL_RC_NO_MEMORY;
Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */
switch (sysparam->param)
{
/* Client sysparams */
case SPI_SET_DRAG_FULL_WINDOWS:
body = sysparam->dragFullWindows ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_KEYBOARD_CUES:
body = sysparam->keyboardCues ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_KEYBOARD_PREF:
body = sysparam->keyboardPref ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_MOUSE_BUTTON_SWAP:
body = sysparam->mouseButtonSwap ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SET_WORK_AREA:
Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */
break;
case SPI_DISPLAY_CHANGE:
Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */
break;
case SPI_TASKBAR_POS:
Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */
Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */
break;
case SPI_SET_HIGH_CONTRAST:
error = rail_write_high_contrast(s, &sysparam->highContrast);
break;
case SPI_SETCARETWIDTH:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
if (sysparam->caretWidth < 0x0001)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->caretWidth);
break;
case SPI_SETSTICKYKEYS:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->stickyKeys);
break;
case SPI_SETTOGGLEKEYS:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
Stream_Write_UINT32(s, sysparam->toggleKeys);
break;
case SPI_SETFILTERKEYS:
if (!extendedSpiSupported)
return ERROR_INVALID_DATA;
error = rail_write_filterkeys(s, &sysparam->filterKeys);
break;
/* Server sysparams */
case SPI_SETSCREENSAVEACTIVE:
body = sysparam->setScreenSaveActive ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
case SPI_SETSCREENSAVESECURE:
body = sysparam->setScreenSaveSecure ? 1 : 0;
Stream_Write_UINT8(s, body);
break;
default:
return ERROR_INVALID_PARAMETER;
}
return error;
}
BOOL rail_is_extended_spi_supported(UINT32 channelFlags)
{
return channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED;
}

View File

@ -26,25 +26,34 @@
#include <freerdp/rail.h>
extern const char* const RAIL_ORDER_TYPE_STRINGS[];
#define RAIL_PDU_HEADER_LENGTH 4
#define RAIL_PDU_HEADER_LENGTH 4
/* Fixed length of PDUs, excluding variable lengths */
#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */
#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */
#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */
#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */
#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */
#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */
#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */
#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */
#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */
#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */
#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */
#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */
#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */
#define RAIL_EXEC_RESULT_ORDER_LENGTH 12 /* variable */
#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */
#define RAIL_MINMAXINFO_ORDER_LENGTH 20 /* fixed */
#define RAIL_LOCALMOVESIZE_ORDER_LENGTH 12 /* fixed */
#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */
#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */
#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */
#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */
#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */
#define RAIL_SNAP_ARRANGE_ORDER_LENGTH 12 /* fixed */
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
#define RAIL_LANGUAGEIME_INFO_ORDER_LENGTH 42 /* fixed */
#define RAIL_COMPARTMENT_INFO_ORDER_LENGTH 16 /* fixed */
#define RAIL_CLOAK_ORDER_LENGTH 5 /* fixed */
#define RAIL_TASKBAR_INFO_ORDER_LENGTH 12 /* fixed */
#define RAIL_Z_ORDER_SYNC_ORDER_LENGTH 4 /* fixed */
#define RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH 4 /* fixed */
#define RAIL_GET_APPID_RESP_ORDER_LENGTH 524 /* fixed */
#define RAIL_GET_APPID_RESP_EX_ORDER_LENGTH 1048 /* fixed */
BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string);
UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake);
void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake);
UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx);
@ -54,4 +63,14 @@ wStream* rail_pdu_init(size_t length);
UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength);
void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength);
UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string);
UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string);
UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported);
UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam,
BOOL extendedSpiSupported);
BOOL rail_is_extended_spi_supported(UINT32 channelsFlags);
const char* rail_get_order_type_string(UINT16 orderType);
const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length);
#endif /* FREERDP_CHANNEL_RAIL_COMMON_H */

View File

@ -0,0 +1,32 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_server("rail")
set(${MODULE_PREFIX}_SRCS
../rail_common.c
../rail_common.h
rail_main.c
rail_main.h)
include_directories(..)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx")
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RAIL Virtual Channel Plugin
*
* Copyright 2019 Mati Shabtay <matishabtay@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_RAIL_SERVER_MAIN_H
#define FREERDP_CHANNEL_RAIL_SERVER_MAIN_H
#include <freerdp/rail.h>
#include <freerdp/server/rail.h>
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/stream.h>
#include "../rail_common.h"
struct _rail_server_private
{
HANDLE thread;
HANDLE stopEvent;
HANDLE channelEvent;
void* rail_channel;
wStream* input_stream;
DWORD channelFlags;
};
#endif /* FREERDP_CHANNEL_RAIL_SERVER_MAIN_H */

View File

@ -0,0 +1,22 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel("rdp2tcp")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -0,0 +1,10 @@
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT OFF)
define_channel_options(NAME "rdp2tcp" TYPE "static"
DESCRIPTION "Tunneling TCP over RDP"
DEFAULT ${OPTION_DEFAULT})
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
define_channel_server_options(${OPTION_SERVER_DEFAULT})

View File

@ -0,0 +1,27 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_client("rdp2tcp")
set(${MODULE_PREFIX}_SRCS
rdp2tcp_main.c)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "VirtualChannelEntryEx")
target_link_libraries(${MODULE_NAME} winpr freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")

View File

@ -0,0 +1,327 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* rdp2tcp Virtual Channel Extension
*
* Copyright 2017 Artur Zaprzala
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <assert.h>
#include <winpr/file.h>
#include <winpr/pipe.h>
#include <winpr/thread.h>
#include <freerdp/svc.h>
#define RDP2TCP_CHAN_NAME "rdp2tcp"
#include <freerdp/log.h>
#define TAG CLIENT_TAG(RDP2TCP_CHAN_NAME)
static int const debug = 0;
typedef struct
{
HANDLE hStdOutputRead;
HANDLE hStdInputWrite;
HANDLE hProcess;
HANDLE copyThread;
HANDLE writeComplete;
DWORD openHandle;
void* initHandle;
CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints;
char buffer[16 * 1024];
} Plugin;
static int init_external_addin(Plugin* plugin)
{
SECURITY_ATTRIBUTES saAttr;
STARTUPINFO siStartInfo;
PROCESS_INFORMATION procInfo;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
// Create pipes
if (!CreatePipe(&plugin->hStdOutputRead, &siStartInfo.hStdOutput, &saAttr, 0))
{
WLog_ERR(TAG, "stdout CreatePipe");
return -1;
}
if (!SetHandleInformation(plugin->hStdOutputRead, HANDLE_FLAG_INHERIT, 0))
{
WLog_ERR(TAG, "stdout SetHandleInformation");
return -1;
}
if (!CreatePipe(&siStartInfo.hStdInput, &plugin->hStdInputWrite, &saAttr, 0))
{
WLog_ERR(TAG, "stdin CreatePipe");
return -1;
}
if (!SetHandleInformation(plugin->hStdInputWrite, HANDLE_FLAG_INHERIT, 0))
{
WLog_ERR(TAG, "stdin SetHandleInformation");
return -1;
}
// Execute plugin
if (!CreateProcess(NULL,
plugin->channelEntryPoints.pExtendedData, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&procInfo // receives PROCESS_INFORMATION
))
{
WLog_ERR(TAG, "fork for addin");
return -1;
}
plugin->hProcess = procInfo.hProcess;
CloseHandle(procInfo.hThread);
CloseHandle(siStartInfo.hStdOutput);
CloseHandle(siStartInfo.hStdInput);
return 0;
}
static void dumpData(char* data, unsigned length)
{
unsigned const limit = 98;
unsigned l = length > limit ? limit / 2 : length;
unsigned i;
for (i = 0; i < l; ++i)
{
printf("%02hhx", data[i]);
}
if (length > limit)
{
printf("...");
for (i = length - l; i < length; ++i)
printf("%02hhx", data[i]);
}
puts("");
}
static DWORD WINAPI copyThread(void* data)
{
Plugin* plugin = (Plugin*)data;
size_t const bufsize = 16 * 1024;
while (1)
{
DWORD dwRead;
char* buffer = malloc(bufsize);
if (!buffer)
{
fprintf(stderr, "rdp2tcp copyThread: malloc failed\n");
goto fail;
}
// if (!ReadFile(plugin->hStdOutputRead, plugin->buffer, sizeof plugin->buffer, &dwRead,
// NULL))
if (!ReadFile(plugin->hStdOutputRead, buffer, bufsize, &dwRead, NULL))
{
free(buffer);
goto fail;
}
if (debug > 1)
{
printf(">%8u ", (unsigned)dwRead);
dumpData(buffer, dwRead);
}
if (plugin->channelEntryPoints.pVirtualChannelWriteEx(
plugin->initHandle, plugin->openHandle, buffer, dwRead, buffer) != CHANNEL_RC_OK)
{
free(buffer);
fprintf(stderr, "rdp2tcp copyThread failed %i\n", (int)dwRead);
goto fail;
}
WaitForSingleObject(plugin->writeComplete, INFINITE);
ResetEvent(plugin->writeComplete);
}
fail:
ExitThread(0);
return 0;
}
static void closeChannel(Plugin* plugin)
{
if (debug)
puts("rdp2tcp closing channel");
plugin->channelEntryPoints.pVirtualChannelCloseEx(plugin->initHandle, plugin->openHandle);
}
static void dataReceived(Plugin* plugin, void* pData, UINT32 dataLength, UINT32 totalLength,
UINT32 dataFlags)
{
DWORD dwWritten;
if (dataFlags & CHANNEL_FLAG_SUSPEND)
{
if (debug)
puts("rdp2tcp Channel Suspend");
return;
}
if (dataFlags & CHANNEL_FLAG_RESUME)
{
if (debug)
puts("rdp2tcp Channel Resume");
return;
}
if (debug > 1)
{
printf("<%c%3u/%3u ", dataFlags & CHANNEL_FLAG_FIRST ? ' ' : '+', totalLength, dataLength);
dumpData(pData, dataLength);
}
if (dataFlags & CHANNEL_FLAG_FIRST)
{
if (!WriteFile(plugin->hStdInputWrite, &totalLength, sizeof(totalLength), &dwWritten, NULL))
closeChannel(plugin);
}
if (!WriteFile(plugin->hStdInputWrite, pData, dataLength, &dwWritten, NULL))
closeChannel(plugin);
}
static void VCAPITYPE VirtualChannelOpenEventEx(LPVOID lpUserParam, DWORD openHandle, UINT event,
LPVOID pData, UINT32 dataLength, UINT32 totalLength,
UINT32 dataFlags)
{
Plugin* plugin = (Plugin*)lpUserParam;
switch (event)
{
case CHANNEL_EVENT_DATA_RECEIVED:
dataReceived(plugin, pData, dataLength, totalLength, dataFlags);
break;
case CHANNEL_EVENT_WRITE_CANCELLED:
free(pData);
break;
case CHANNEL_EVENT_WRITE_COMPLETE:
SetEvent(plugin->writeComplete);
free(pData);
break;
}
}
static VOID VCAPITYPE VirtualChannelInitEventEx(LPVOID lpUserParam, LPVOID pInitHandle, UINT event,
LPVOID pData, UINT dataLength)
{
Plugin* plugin = (Plugin*)lpUserParam;
switch (event)
{
case CHANNEL_EVENT_CONNECTED:
if (debug)
puts("rdp2tcp connected");
plugin->writeComplete = CreateEvent(NULL, TRUE, FALSE, NULL);
plugin->copyThread = CreateThread(NULL, 0, copyThread, plugin, 0, NULL);
if (plugin->channelEntryPoints.pVirtualChannelOpenEx(
pInitHandle, &plugin->openHandle, RDP2TCP_CHAN_NAME,
VirtualChannelOpenEventEx) != CHANNEL_RC_OK)
return;
break;
case CHANNEL_EVENT_DISCONNECTED:
if (debug)
puts("rdp2tcp disconnected");
break;
case CHANNEL_EVENT_TERMINATED:
if (debug)
puts("rdp2tcp terminated");
if (plugin->copyThread)
{
TerminateThread(plugin->copyThread, 0);
CloseHandle(plugin->writeComplete);
}
CloseHandle(plugin->hStdInputWrite);
CloseHandle(plugin->hStdOutputRead);
TerminateProcess(plugin->hProcess, 0);
CloseHandle(plugin->hProcess);
free(plugin);
break;
}
}
#if 1
#define VirtualChannelEntryEx rdp2tcp_VirtualChannelEntryEx
#else
#define VirtualChannelEntryEx FREERDP_API VirtualChannelEntryEx
#endif
BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
{
CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx;
CHANNEL_DEF channelDef;
Plugin* plugin = (Plugin*)calloc(1, sizeof(Plugin));
if (!plugin)
return FALSE;
pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
assert(pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX) &&
pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER);
plugin->initHandle = pInitHandle;
plugin->channelEntryPoints = *pEntryPointsEx;
if (init_external_addin(plugin) < 0)
return FALSE;
strncpy(channelDef.name, RDP2TCP_CHAN_NAME, sizeof(channelDef.name));
channelDef.options =
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
if (pEntryPointsEx->pVirtualChannelInitEx(plugin, NULL, pInitHandle, &channelDef, 1,
VIRTUAL_CHANNEL_VERSION_WIN2000,
VirtualChannelInitEventEx) != CHANNEL_RC_OK)
return FALSE;
return TRUE;
}
// vim:ts=4

View File

@ -41,9 +41,11 @@
#include "devman.h"
#define TAG CHANNELS_TAG("rdpdr.client")
static void devman_device_free(void* obj)
{
DEVICE* device = (DEVICE*) obj;
DEVICE* device = (DEVICE*)obj;
if (!device)
return;
@ -58,21 +60,21 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
if (!rdpdr)
return NULL;
devman = (DEVMAN*) calloc(1, sizeof(DEVMAN));
devman = (DEVMAN*)calloc(1, sizeof(DEVMAN));
if (!devman)
{
WLog_INFO(TAG, "calloc failed!");
WLog_Print(rdpdr->log, WLOG_INFO, "calloc failed!");
return NULL;
}
devman->plugin = (void*) rdpdr;
devman->plugin = (void*)rdpdr;
devman->id_sequence = 1;
devman->devices = ListDictionary_New(TRUE);
if (!devman->devices)
{
WLog_INFO(TAG, "ListDictionary_New failed!");
WLog_Print(rdpdr->log, WLOG_INFO, "ListDictionary_New failed!");
free(devman);
return NULL;
}
@ -94,7 +96,7 @@ void devman_unregister_device(DEVMAN* devman, void* key)
if (!devman || !key)
return;
device = (DEVICE*) ListDictionary_Remove(devman->devices, key);
device = (DEVICE*)ListDictionary_Remove(devman->devices, key);
if (device)
devman_device_free(device);
@ -113,11 +115,11 @@ static UINT devman_register_device(DEVMAN* devman, DEVICE* device)
return ERROR_INVALID_PARAMETER;
device->id = devman->id_sequence++;
key = (void*)(size_t) device->id;
key = (void*)(size_t)device->id;
if (!ListDictionary_Add(devman->devices, key, device))
{
WLog_INFO(TAG, "ListDictionary_Add failed!");
WLog_INFO(TAG, "ListDictionary_Add failed!");
return ERROR_INTERNAL_ERROR;
}
@ -127,12 +129,12 @@ static UINT devman_register_device(DEVMAN* devman, DEVICE* device)
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id)
{
DEVICE* device = NULL;
void* key = (void*)(size_t) id;
void* key = (void*)(size_t)id;
if (!devman)
return NULL;
device = (DEVICE*) ListDictionary_GetItemValue(devman->devices, key);
device = (DEVICE*)ListDictionary_GetItemValue(devman->devices, key);
return device;
}
@ -150,7 +152,7 @@ DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type)
for (x = 0; x < count; x++)
{
DEVICE* cur = (DEVICE*) ListDictionary_GetItemValue(devman->devices, (void*)keys[x]);
DEVICE* cur = (DEVICE*)ListDictionary_GetItemValue(devman->devices, (void*)keys[x]);
if (!cur)
continue;
@ -167,23 +169,28 @@ DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type)
return device;
}
static char DRIVE_SERVICE_NAME[] = "drive";
static char PRINTER_SERVICE_NAME[] = "printer";
static char SMARTCARD_SERVICE_NAME[] = "smartcard";
static char SERIAL_SERVICE_NAME[] = "serial";
static char PARALLEL_SERVICE_NAME[] = "parallel";
static const char DRIVE_SERVICE_NAME[] = "drive";
static const char PRINTER_SERVICE_NAME[] = "printer";
static const char SMARTCARD_SERVICE_NAME[] = "smartcard";
static const char SERIAL_SERVICE_NAME[] = "serial";
static const char PARALLEL_SERVICE_NAME[] = "parallel";
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext)
UINT devman_load_device_service(DEVMAN* devman, const RDPDR_DEVICE* device, rdpContext* rdpcontext)
{
char* ServiceName = NULL;
const char* ServiceName = NULL;
DEVICE_SERVICE_ENTRY_POINTS ep;
PDEVICE_SERVICE_ENTRY entry = NULL;
union {
const RDPDR_DEVICE* cdp;
RDPDR_DEVICE* dp;
} devconv;
devconv.cdp = device;
if (!devman || !device || !rdpcontext)
return ERROR_INVALID_PARAMETER;
@ -200,27 +207,27 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext
if (!ServiceName)
{
WLog_INFO(TAG, "ServiceName %s did not match!", ServiceName);
WLog_INFO(TAG, "ServiceName %s did not match!", ServiceName);
return ERROR_INVALID_NAME;
}
if (device->Name)
WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name);
WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name);
else
WLog_INFO(TAG, "Loading device service %s (static)", ServiceName);
WLog_INFO(TAG, "Loading device service %s (static)", ServiceName);
entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL,
"DeviceServiceEntry", 0);
entry = (PDEVICE_SERVICE_ENTRY)freerdp_load_channel_addin_entry(ServiceName, NULL,
"DeviceServiceEntry", 0);
if (!entry)
{
WLog_INFO(TAG, "freerdp_load_channel_addin_entry failed!");
WLog_INFO(TAG, "freerdp_load_channel_addin_entry failed!");
return ERROR_INTERNAL_ERROR;
}
ep.devman = devman;
ep.RegisterDevice = devman_register_device;
ep.device = device;
ep.device = devconv.dp;
ep.rdpcontext = rdpcontext;
return entry(&ep);
}

View File

@ -26,7 +26,7 @@
#include "rdpdr_main.h"
void devman_unregister_device(DEVMAN* devman, void* key);
UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext);
UINT devman_load_device_service(DEVMAN* devman, const RDPDR_DEVICE* device, rdpContext* rdpcontext);
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id);
DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type);

View File

@ -63,7 +63,7 @@ static UINT irp_complete(IRP* irp)
rdpdrPlugin* rdpdr;
UINT error;
rdpdr = (rdpdrPlugin*) irp->devman->plugin;
rdpdr = (rdpdrPlugin*)irp->devman->plugin;
pos = Stream_GetPosition(irp->output);
Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4);
@ -73,17 +73,16 @@ static UINT irp_complete(IRP* irp)
error = rdpdr_send(rdpdr, irp->output);
irp->output = NULL;
irp_free(irp);
return error;
return irp_free(irp);
}
IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error)
IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error)
{
IRP* irp;
DEVICE* device;
UINT32 DeviceId;
if (Stream_GetRemainingLength(s) < 20)
if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
{
if (error)
*error = ERROR_INVALID_DATA;
@ -95,49 +94,48 @@ IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error)
if (!device)
{
WLog_WARN(TAG, "devman_get_device_by_id failed!");
WLog_Print(log, WLOG_WARN, "devman_get_device_by_id failed!");
if (error)
*error = CHANNEL_RC_OK;
return NULL;
};
irp = (IRP*) _aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
irp = (IRP*)_aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
if (!irp)
{
WLog_ERR(TAG, "_aligned_malloc failed!");
WLog_Print(log, WLOG_ERROR, "_aligned_malloc failed!");
if (error)
*error = CHANNEL_RC_NO_MEMORY;
return NULL;
}
ZeroMemory(irp, sizeof(IRP));
irp->input = s;
irp->device = device;
irp->devman = devman;
Stream_Read_UINT32(s, irp->FileId); /* FileId (4 bytes) */
Stream_Read_UINT32(s, irp->CompletionId); /* CompletionId (4 bytes) */
Stream_Read_UINT32(s, irp->FileId); /* FileId (4 bytes) */
Stream_Read_UINT32(s, irp->CompletionId); /* CompletionId (4 bytes) */
Stream_Read_UINT32(s, irp->MajorFunction); /* MajorFunction (4 bytes) */
Stream_Read_UINT32(s, irp->MinorFunction); /* MinorFunction (4 bytes) */
irp->output = Stream_New(NULL, 256);
if (!irp->output)
{
WLog_ERR(TAG, "Stream_New failed!");
WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
_aligned_free(irp);
if (error)
*error = CHANNEL_RC_NO_MEMORY;
return NULL;
}
Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE); /* Component (2 bytes) */
Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE); /* Component (2 bytes) */
Stream_Write_UINT16(irp->output, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */
Stream_Write_UINT32(irp->output, DeviceId); /* DeviceId (4 bytes) */
Stream_Write_UINT32(irp->output, irp->CompletionId); /* CompletionId (4 bytes) */
Stream_Write_UINT32(irp->output, 0); /* IoStatus (4 bytes) */
Stream_Write_UINT32(irp->output, DeviceId); /* DeviceId (4 bytes) */
Stream_Write_UINT32(irp->output, irp->CompletionId); /* CompletionId (4 bytes) */
Stream_Write_UINT32(irp->output, 0); /* IoStatus (4 bytes) */
irp->Complete = irp_complete;
irp->Discard = irp_free;

View File

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

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