From 36a6641c4322eacab427dd3378343053ae57eccf Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 7 May 2019 08:01:10 -0400 Subject: [PATCH] import mingw-spice-vdagent-0.9.0-3.el8 --- .gitignore | 1 + .mingw-spice-vdagent.metadata | 1 + ...-from_bitmap-return-a-BMP-file-forma.patch | 56 ++++ ...ave-PNG-file-using-a-helper-function.patch | 62 +++++ ...test-Save-BMP-file-using-BitmapCoder.patch | 89 ++++++ ...4-vdagent-Removed-unused-declaration.patch | 26 ++ ...o-use-names-with-reserved-characters.patch | 63 +++++ ...8-vcproj-Remove-reference-to-CxImage.patch | 92 +++++++ .../0009-vcproj-Add-some-missing-files.patch | 44 +++ ...010-Fix-minor-compiler-compatibility.patch | 38 +++ .../0011-Avoid-unused-variable-warning.patch | 29 ++ .../0012-msi-Do-not-generate-deps.txt.patch | 61 +++++ ...ove-FileXferTask-structure-alignment.patch | 39 +++ ...-file_xfer-Remove-too-C-syntax-for-C.patch | 39 +++ ...xfer-Use-destructor-for-FileXferTask.patch | 99 +++++++ ...ared_ptr-to-simplify-memory-manageme.patch | 130 +++++++++ ...nt-Fix-loss-of-mouse-movement-events.patch | 257 ++++++++++++++++++ ...ocol-macros-instead-of-defining-new-.patch | 54 ++++ ...Do-not-append-line-terminator-to-log.patch | 29 ++ ...uffer-overflows-reading-registry-inf.patch | 80 ++++++ SOURCES/0021-Use-enumeration-types.patch | 62 +++++ SOURCES/0022-Minimal-message-size-check.patch | 80 ++++++ ...Use-proper-type-for-_clipboard_owner.patch | 27 ++ ...Reduce-indentation-returning-earlier.patch | 82 ++++++ ...5-Minor-overflow-checks-improvements.patch | 43 +++ ...-an-assert-with-proper-handling-code.patch | 33 +++ ...e-std-unique_ptr-for-_desktop_layout.patch | 55 ++++ ...s-TCHAR-to-read-string-from-registry.patch | 103 +++++++ ...ility-function-to-read-strings-from-.patch | 159 +++++++++++ ...haracter-reading-strings-from-regist.patch | 67 +++++ ...trol_event-and-_stop_event-just-once.patch | 60 ++++ ...0032-Avoid-declaring-event_thread_id.patch | 37 +++ ...oid-declaring-_system_version-member.patch | 64 +++++ ...ids-to-call-supported_system_version.patch | 61 +++++ ...emove-the-lookup-table-for-log-types.patch | 62 +++++ ...-a-logf-function-to-avoid-long-LOG-m.patch | 86 ++++++ ...alTime-instead-of-multiple-C-functio.patch | 46 ++++ ...proper-invalid-value-for-_vio_serial.patch | 32 +++ ...uce-an-helper-to-close-VirtIo-device.patch | 54 ++++ ...structor-instead-of-cleanup-function.patch | 102 +++++++ ...vdagent-Stop-correctly-helper-thread.patch | 67 +++++ ...mment-around-WinSta0_DesktopSwitch-e.patch | 36 +++ ...dle-to-get-some-functions-from-user3.patch | 61 +++++ SPECS/mingw-spice-vdagent.spec | 204 ++++++++++++++ 44 files changed, 2972 insertions(+) create mode 100644 .gitignore create mode 100644 .mingw-spice-vdagent.metadata create mode 100644 SOURCES/0001-Make-BitmapCoder-from_bitmap-return-a-BMP-file-forma.patch create mode 100644 SOURCES/0002-imagetest-Save-PNG-file-using-a-helper-function.patch create mode 100644 SOURCES/0003-imagetest-Save-BMP-file-using-BitmapCoder.patch create mode 100644 SOURCES/0004-vdagent-Removed-unused-declaration.patch create mode 100644 SOURCES/0005-Avoid-to-use-names-with-reserved-characters.patch create mode 100644 SOURCES/0008-vcproj-Remove-reference-to-CxImage.patch create mode 100644 SOURCES/0009-vcproj-Add-some-missing-files.patch create mode 100644 SOURCES/0010-Fix-minor-compiler-compatibility.patch create mode 100644 SOURCES/0011-Avoid-unused-variable-warning.patch create mode 100644 SOURCES/0012-msi-Do-not-generate-deps.txt.patch create mode 100644 SOURCES/0013-file_xfer-Remove-FileXferTask-structure-alignment.patch create mode 100644 SOURCES/0014-file_xfer-Remove-too-C-syntax-for-C.patch create mode 100644 SOURCES/0015-file_xfer-Use-destructor-for-FileXferTask.patch create mode 100644 SOURCES/0016-file_xfer-Use-shared_ptr-to-simplify-memory-manageme.patch create mode 100644 SOURCES/0017-vdagent-Fix-loss-of-mouse-movement-events.patch create mode 100644 SOURCES/0018-Reuse-spice-protocol-macros-instead-of-defining-new-.patch create mode 100644 SOURCES/0019-vdservice-Do-not-append-line-terminator-to-log.patch create mode 100644 SOURCES/0020-Fix-some-minor-buffer-overflows-reading-registry-inf.patch create mode 100644 SOURCES/0021-Use-enumeration-types.patch create mode 100644 SOURCES/0022-Minimal-message-size-check.patch create mode 100644 SOURCES/0023-Use-proper-type-for-_clipboard_owner.patch create mode 100644 SOURCES/0024-Reduce-indentation-returning-earlier.patch create mode 100644 SOURCES/0025-Minor-overflow-checks-improvements.patch create mode 100644 SOURCES/0026-Replace-an-assert-with-proper-handling-code.patch create mode 100644 SOURCES/0027-Use-std-unique_ptr-for-_desktop_layout.patch create mode 100644 SOURCES/0028-Use-always-TCHAR-to-read-string-from-registry.patch create mode 100644 SOURCES/0029-Factor-out-an-utility-function-to-read-strings-from-.patch create mode 100644 SOURCES/0030-Allow-one-more-character-reading-strings-from-regist.patch create mode 100644 SOURCES/0031-Allocate-_control_event-and-_stop_event-just-once.patch create mode 100644 SOURCES/0032-Avoid-declaring-event_thread_id.patch create mode 100644 SOURCES/0033-Avoid-declaring-_system_version-member.patch create mode 100644 SOURCES/0034-Avoids-to-call-supported_system_version.patch create mode 100644 SOURCES/0035-vdlog-Remove-the-lookup-table-for-log-types.patch create mode 100644 SOURCES/0036-vdlog-Factor-our-a-logf-function-to-avoid-long-LOG-m.patch create mode 100644 SOURCES/0037-vdlog-Use-GetLocalTime-instead-of-multiple-C-functio.patch create mode 100644 SOURCES/0038-Use-proper-invalid-value-for-_vio_serial.patch create mode 100644 SOURCES/0039-Introduce-an-helper-to-close-VirtIo-device.patch create mode 100644 SOURCES/0040-Use-destructor-instead-of-cleanup-function.patch create mode 100644 SOURCES/0041-vdagent-Stop-correctly-helper-thread.patch create mode 100644 SOURCES/0042-vdagent-Add-a-comment-around-WinSta0_DesktopSwitch-e.patch create mode 100644 SOURCES/0043-Use-GetModuleHandle-to-get-some-functions-from-user3.patch create mode 100644 SPECS/mingw-spice-vdagent.spec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3491e5e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/vdagent-win-0.9.0.tar.xz diff --git a/.mingw-spice-vdagent.metadata b/.mingw-spice-vdagent.metadata new file mode 100644 index 0000000..d8d6f24 --- /dev/null +++ b/.mingw-spice-vdagent.metadata @@ -0,0 +1 @@ +e053d42313e9a201313052af0694c5489b643bc4 SOURCES/vdagent-win-0.9.0.tar.xz diff --git a/SOURCES/0001-Make-BitmapCoder-from_bitmap-return-a-BMP-file-forma.patch b/SOURCES/0001-Make-BitmapCoder-from_bitmap-return-a-BMP-file-forma.patch new file mode 100644 index 0000000..fd32710 --- /dev/null +++ b/SOURCES/0001-Make-BitmapCoder-from_bitmap-return-a-BMP-file-forma.patch @@ -0,0 +1,56 @@ +From aaeecf129424752b13373a9242bcede58337e047 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Tue, 22 Aug 2017 12:51:45 +0100 +Subject: [PATCH 01/43] Make BitmapCoder::from_bitmap return a BMP file format + +The network expect the format of the data to match a file +format so prepending DIB data with BITMAPFILEHEADER change +the format from DIB to BMP file. + +Signed-off-by: Frediano Ziglio +Acked-by: Uri Lublin +--- + vdagent/image.cpp | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/vdagent/image.cpp b/vdagent/image.cpp +index 82cfb0e..15bd4fa 100644 +--- a/vdagent/image.cpp ++++ b/vdagent/image.cpp +@@ -150,6 +150,8 @@ void BitmapCoder::get_dib_data(uint8_t *dib, const uint8_t *data, size_t size) + + uint8_t *BitmapCoder::from_bitmap(const BITMAPINFO& info, const void *bits, long &size) + { ++ BITMAPFILEHEADER file_hdr; ++ + const BITMAPINFOHEADER& head(info.bmiHeader); + + const DWORD max_palette_colors = head.biBitCount <= 8 ? 1 << head.biBitCount : 0; +@@ -157,14 +159,21 @@ uint8_t *BitmapCoder::from_bitmap(const BITMAPINFO& info, const void *bits, long + + const size_t stride = compute_dib_stride(head.biWidth, head.biBitCount); + const size_t image_size = stride * head.biHeight; +- size = sizeof(head) + palette_size + image_size; ++ size = sizeof(file_hdr) + sizeof(head) + palette_size + image_size; ++ ++ file_hdr.bfType = 'B' + 'M'*256u; ++ file_hdr.bfSize = size; ++ file_hdr.bfReserved1 = 0; ++ file_hdr.bfReserved2 = 0; ++ file_hdr.bfOffBits = sizeof(file_hdr) + sizeof(head) + palette_size; + + uint8_t *data = (uint8_t *) malloc(size); + if (!data) { + return NULL; + } +- memcpy(data, &info, sizeof(head) + palette_size); +- memcpy(data + sizeof(head) + palette_size, bits, image_size); ++ memcpy(data, &file_hdr, sizeof(file_hdr)); ++ memcpy(data + sizeof(file_hdr), &info, sizeof(head) + palette_size); ++ memcpy(data + sizeof(file_hdr) + sizeof(head) + palette_size, bits, image_size); + return data; + } + +-- +2.17.1 + diff --git a/SOURCES/0002-imagetest-Save-PNG-file-using-a-helper-function.patch b/SOURCES/0002-imagetest-Save-PNG-file-using-a-helper-function.patch new file mode 100644 index 0000000..ef8296d --- /dev/null +++ b/SOURCES/0002-imagetest-Save-PNG-file-using-a-helper-function.patch @@ -0,0 +1,62 @@ +From 9c85f8d3caf826099d8a1db562e23e5cf4e8b243 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Tue, 22 Aug 2017 12:57:16 +0100 +Subject: [PATCH 02/43] imagetest: Save PNG file using a helper function + +This allows to reuse the code to save a DIB to a file. + +Signed-off-by: Frediano Ziglio +Acked-by: Uri Lublin +--- + vdagent/imagetest.cpp | 28 ++++++++++++++++++---------- + 1 file changed, 18 insertions(+), 10 deletions(-) + +diff --git a/vdagent/imagetest.cpp b/vdagent/imagetest.cpp +index 319b188..3a553a9 100644 +--- a/vdagent/imagetest.cpp ++++ b/vdagent/imagetest.cpp +@@ -23,6 +23,23 @@ + #include "image.h" + #include "imagepng.h" + ++static void ++save_dib_to_file(ImageCoder& coder, const uint8_t *raw_dib, const char *filename) ++{ ++ const BITMAPINFO& info(*(BITMAPINFO*) raw_dib); ++ const uint8_t *raw_bits = &raw_dib[sizeof(BITMAPINFOHEADER) + 4 * info.bmiHeader.biClrUsed]; ++ ++ long size = 0; ++ uint8_t *raw_file = coder.from_bitmap(info, raw_bits, size); ++ assert(raw_file && size > 0); ++ ++ FILE *f = fopen(filename, "wb"); ++ assert(f); ++ assert(fwrite(raw_file, 1, size, f) == (unsigned long) size); ++ fclose(f); ++ free(raw_file); ++} ++ + int main(int argc, char **argv) + { + ImageCoder *coder = create_png_coder(); +@@ -66,16 +83,7 @@ int main(int argc, char **argv) + fclose(f); + + // convert back to PNG +- long png_size = 0; +- uint8_t *png = coder->from_bitmap(*((BITMAPINFO*)&out[0]), &out[sizeof(BITMAPINFOHEADER) + 4 * info.biClrUsed], png_size); +- assert(png && png_size > 0); +- +- f = fopen(argc > 3 ? argv[3] : "out.png", "wb"); +- assert(f); +- assert(fwrite(png, 1, png_size, f) == (unsigned long) png_size); +- fclose(f); +- free(png); +- png = NULL; ++ save_dib_to_file(*coder, &out[0], argc > 3 ? argv[3] : "out.png"); + + return 0; + } +-- +2.17.1 + diff --git a/SOURCES/0003-imagetest-Save-BMP-file-using-BitmapCoder.patch b/SOURCES/0003-imagetest-Save-BMP-file-using-BitmapCoder.patch new file mode 100644 index 0000000..a6060dd --- /dev/null +++ b/SOURCES/0003-imagetest-Save-BMP-file-using-BitmapCoder.patch @@ -0,0 +1,89 @@ +From 16aee83802ee436cc5216bd55cb8f7760c30f50a Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Tue, 22 Aug 2017 12:58:25 +0100 +Subject: [PATCH 03/43] imagetest: Save BMP file using BitmapCoder + +This allows to test BitmapCoder::from_bitmap. + +Signed-off-by: Frediano Ziglio +Acked-by: Uri Lublin +--- + vdagent/image.cpp | 2 -- + vdagent/image.h | 2 ++ + vdagent/imagetest.cpp | 20 ++++++-------------- + 3 files changed, 8 insertions(+), 16 deletions(-) + +diff --git a/vdagent/image.cpp b/vdagent/image.cpp +index 15bd4fa..1b21b53 100644 +--- a/vdagent/image.cpp ++++ b/vdagent/image.cpp +@@ -23,8 +23,6 @@ + #include "image.h" + #include "imagepng.h" + +-ImageCoder *create_bitmap_coder(); +- + static ImageCoder *get_coder(uint32_t vdagent_type) + { + switch (vdagent_type) { +diff --git a/vdagent/image.h b/vdagent/image.h +index da549d3..326d7f9 100644 +--- a/vdagent/image.h ++++ b/vdagent/image.h +@@ -39,6 +39,8 @@ static inline size_t compute_dib_stride(unsigned int width, unsigned int bit_cou + return ((width * bit_count + 31u) & ~31u) / 8u; + } + ++ImageCoder *create_bitmap_coder(); ++ + /** + * Returns image to put in the clipboard. + * +diff --git a/vdagent/imagetest.cpp b/vdagent/imagetest.cpp +index 3a553a9..36b8f6c 100644 +--- a/vdagent/imagetest.cpp ++++ b/vdagent/imagetest.cpp +@@ -18,6 +18,7 @@ + #undef NDEBUG + #include + #include ++#include + + #include "vdcommon.h" + #include "image.h" +@@ -42,7 +43,7 @@ save_dib_to_file(ImageCoder& coder, const uint8_t *raw_dib, const char *filename + + int main(int argc, char **argv) + { +- ImageCoder *coder = create_png_coder(); ++ std::unique_ptr coder(create_png_coder()); + + assert(coder); + if (argc < 2) { +@@ -68,19 +69,10 @@ int main(int argc, char **argv) + memset(&out[0], 0xcc, dib_size); + coder->get_dib_data(&out[0], &data[0], len); + +- // looks like many tools wants this header so craft it +- BITMAPFILEHEADER head; +- memset(&head, 0, sizeof(head)); +- head.bfType = 'B'+'M'*256u; +- head.bfSize = sizeof(head) + dib_size; +- BITMAPINFOHEADER& info(*(BITMAPINFOHEADER*)&out[0]); +- head.bfOffBits = sizeof(head) + sizeof(BITMAPINFOHEADER) + 4 * info.biClrUsed; +- +- f = fopen(argc > 2 ? argv[2] : "out.bmp", "wb"); +- assert(f); +- assert(fwrite(&head, 1, sizeof(head), f) == sizeof(head)); +- assert(fwrite(&out[0], 1, dib_size, f) == dib_size); +- fclose(f); ++ // write BMP file ++ std::unique_ptr bmp_coder(create_bitmap_coder()); ++ assert(bmp_coder); ++ save_dib_to_file(*bmp_coder, &out[0], argc > 2 ? argv[2] : "out.bmp"); + + // convert back to PNG + save_dib_to_file(*coder, &out[0], argc > 3 ? argv[3] : "out.png"); +-- +2.17.1 + diff --git a/SOURCES/0004-vdagent-Removed-unused-declaration.patch b/SOURCES/0004-vdagent-Removed-unused-declaration.patch new file mode 100644 index 0000000..a9d1723 --- /dev/null +++ b/SOURCES/0004-vdagent-Removed-unused-declaration.patch @@ -0,0 +1,26 @@ +From 2aa6f16af4ad2d50ab614dd87b10baae1729c461 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Thu, 24 May 2018 14:01:53 +0100 +Subject: [PATCH 04/43] vdagent: Removed unused declaration + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.cpp | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index f00fbf5..0a364df 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -99,7 +99,6 @@ private: + void dispatch_message(VDAgentMessage* msg, uint32_t port); + uint32_t get_clipboard_format(uint32_t type) const; + uint32_t get_clipboard_type(uint32_t format) const; +- DWORD get_cximage_format(uint32_t type) const; + enum { owner_none, owner_guest, owner_client }; + void set_clipboard_owner(int new_owner); + enum { CONTROL_STOP, CONTROL_RESET, CONTROL_DESKTOP_SWITCH, CONTROL_LOGON, CONTROL_CLIPBOARD }; +-- +2.17.1 + diff --git a/SOURCES/0005-Avoid-to-use-names-with-reserved-characters.patch b/SOURCES/0005-Avoid-to-use-names-with-reserved-characters.patch new file mode 100644 index 0000000..1437234 --- /dev/null +++ b/SOURCES/0005-Avoid-to-use-names-with-reserved-characters.patch @@ -0,0 +1,63 @@ +From e2ced9f094bf676856ae78779f4a791936eb535f Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Mon, 5 Sep 2016 14:51:56 +0100 +Subject: [PATCH 05/43] Avoid to use names with reserved characters. + +Some characters are reserved and should not be used in Windows +independently by the file system used. +This avoid to use paths in the filename which could lead to some +nasty hacks (like names like "..\hack.txt"). +The return statement cause the file transfer to be aborted with +VD_AGENT_FILE_XFER_STATUS_ERROR as status. + +":" is used to separate filenames from stream names and can be used +to create hidden streams. Also is used for drive separator (A:) +or device names (NUL:). +"/" and "\" are reserved for components (directory, filename, drive, +share, server) separators. +"*" and "?" are wildcards (which on Windows are supported by +different APIs too). +"<", ">", """ and "|" are reserved for shell usage. + +More information on "Naming Files, Paths, and Namespaces" page at +https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx + +This fixes also https://bugzilla.redhat.com/show_bug.cgi?id=1520393. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/file_xfer.cpp | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/vdagent/file_xfer.cpp b/vdagent/file_xfer.cpp +index e877cca..8203b99 100644 +--- a/vdagent/file_xfer.cpp ++++ b/vdagent/file_xfer.cpp +@@ -33,6 +33,12 @@ + #include "file_xfer.h" + #include "as_user.h" + ++#define FILENAME_RESERVED_CHAR_LIST \ ++ ":" /* streams and devices */ \ ++ "/\\" /* components separator */ \ ++ "?*" /* wildcards */ \ ++ "<>\"|" /* reserved to shell */ ++ + void FileXfer::reset() + { + FileXferTasks::iterator iter; +@@ -72,6 +78,10 @@ void FileXfer::handle_start(VDAgentFileXferStartMessage* start, + return; + } + vd_printf("%u %s (%" PRIu64 ")", start->id, file_name, file_size); ++ if (strcspn(file_name, FILENAME_RESERVED_CHAR_LIST) != strlen(file_name)) { ++ vd_printf("filename contains invalid characters"); ++ return; ++ } + if (!as_user.begin()) { + vd_printf("as_user failed"); + return; +-- +2.17.1 + diff --git a/SOURCES/0008-vcproj-Remove-reference-to-CxImage.patch b/SOURCES/0008-vcproj-Remove-reference-to-CxImage.patch new file mode 100644 index 0000000..9d0233f --- /dev/null +++ b/SOURCES/0008-vcproj-Remove-reference-to-CxImage.patch @@ -0,0 +1,92 @@ +From 9a929bd24ade5e25b33afd43509ff04acf4352a0 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 25 May 2018 19:47:20 +0100 +Subject: [PATCH 08/43] vcproj: Remove reference to CxImage + +Not used anymore. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.vcproj | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj +index f9f4228..f830b0f 100644 +--- a/vdagent/vdagent.vcproj ++++ b/vdagent/vdagent.vcproj +@@ -44,7 +44,7 @@ + + + + + + + +Date: Fri, 25 May 2018 19:47:32 +0100 +Subject: [PATCH 09/43] vcproj: Add some missing files + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.vcproj | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj +index f830b0f..376ddd4 100644 +--- a/vdagent/vdagent.vcproj ++++ b/vdagent/vdagent.vcproj +@@ -349,6 +349,10 @@ + RelativePath=".\desktop_layout.cpp" + > + ++ ++ + +@@ -357,6 +361,14 @@ + RelativePath=".\file_xfer.cpp" + > + ++ ++ ++ ++ + +-- +2.17.1 + diff --git a/SOURCES/0010-Fix-minor-compiler-compatibility.patch b/SOURCES/0010-Fix-minor-compiler-compatibility.patch new file mode 100644 index 0000000..2a00059 --- /dev/null +++ b/SOURCES/0010-Fix-minor-compiler-compatibility.patch @@ -0,0 +1,38 @@ +From 1982d50375e4f3fdf5d5ca5e497328743af4e559 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 26 May 2018 07:51:59 +0100 +Subject: [PATCH 10/43] Fix minor compiler compatibility + +Ensure std::min is declared including directly algorithm header. +Undefine possible min and max macros, some Windows headers define them. +Currently happens using Visual Studio 2015. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/image.cpp | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/vdagent/image.cpp b/vdagent/image.cpp +index 1b21b53..c0bcdb5 100644 +--- a/vdagent/image.cpp ++++ b/vdagent/image.cpp +@@ -18,11 +18,15 @@ + #include + #include + #include ++#include + + #include "vdcommon.h" + #include "image.h" + #include "imagepng.h" + ++#undef max ++#undef min ++ + static ImageCoder *get_coder(uint32_t vdagent_type) + { + switch (vdagent_type) { +-- +2.17.1 + diff --git a/SOURCES/0011-Avoid-unused-variable-warning.patch b/SOURCES/0011-Avoid-unused-variable-warning.patch new file mode 100644 index 0000000..f73d063 --- /dev/null +++ b/SOURCES/0011-Avoid-unused-variable-warning.patch @@ -0,0 +1,29 @@ +From 022c56ac6ae2f7f9a082b81e44872d48aace35b2 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 26 May 2018 07:50:53 +0100 +Subject: [PATCH 11/43] Avoid unused variable warning + +Currently happens using Visual Studio 2015. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/display_configuration.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/vdagent/display_configuration.cpp b/vdagent/display_configuration.cpp +index 6e7624b..cdbbe23 100644 +--- a/vdagent/display_configuration.cpp ++++ b/vdagent/display_configuration.cpp +@@ -259,7 +259,7 @@ DisplayConfig* DisplayConfig::create_config() + try { + new_interface = new WDDMInterface(); + } +- catch (std::exception& e) { ++ catch (std::exception&) { + new_interface = new XPDMInterface(); + } + return new_interface; +-- +2.17.1 + diff --git a/SOURCES/0012-msi-Do-not-generate-deps.txt.patch b/SOURCES/0012-msi-Do-not-generate-deps.txt.patch new file mode 100644 index 0000000..91dbbdb --- /dev/null +++ b/SOURCES/0012-msi-Do-not-generate-deps.txt.patch @@ -0,0 +1,61 @@ +From d4a4fb28ea0c057428ef1f28bc689b8d0f085dc6 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Mon, 28 May 2018 09:20:41 +0100 +Subject: [PATCH 12/43] msi: Do not generate deps.txt + +There's no reason to tell the package installed on the build system +used. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + Makefile.am | 5 +---- + spice-vdagent.wxs.in | 4 ---- + 2 files changed, 1 insertion(+), 8 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 62640f2..3020824 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -100,15 +100,12 @@ test_log_win_SOURCES = \ + common/test-log.cpp \ + $(NULL) + +-deps.txt: +- $(AM_V_GEN)rpm -qa | grep $(host_os) | sort | unix2dos > $@ +- + MANUFACTURER = The Spice Project + + EXTRA_DIST += spice-vdagent.wxs.in + CONFIG_STATUS_DEPENDENCIES = spice-vdagent.wxs.in + +-spice-vdagent-$(WIXL_ARCH)-$(VERSION)$(BUILDID).msi: spice-vdagent.wxs deps.txt all ++spice-vdagent-$(WIXL_ARCH)-$(VERSION)$(BUILDID).msi: spice-vdagent.wxs all + $(AM_V_GEN)DESTDIR=`mktemp -d`&& \ + make -C $(top_builddir) install DESTDIR=$$DESTDIR >/dev/null && \ + MANUFACTURER="$(MANUFACTURER)" wixl -D SourceDir=$(prefix) \ +diff --git a/spice-vdagent.wxs.in b/spice-vdagent.wxs.in +index 452f995..7432ca9 100644 +--- a/spice-vdagent.wxs.in ++++ b/spice-vdagent.wxs.in +@@ -61,9 +61,6 @@ + Wait="yes"/> + + +- +- +- + + + +@@ -71,7 +68,6 @@ + + + +- + + + +-- +2.17.1 + diff --git a/SOURCES/0013-file_xfer-Remove-FileXferTask-structure-alignment.patch b/SOURCES/0013-file_xfer-Remove-FileXferTask-structure-alignment.patch new file mode 100644 index 0000000..d9afa81 --- /dev/null +++ b/SOURCES/0013-file_xfer-Remove-FileXferTask-structure-alignment.patch @@ -0,0 +1,39 @@ +From 0de788aa6175fa6035b9f79a7dcfda8b98cd1e6f Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 25 May 2018 19:41:26 +0100 +Subject: [PATCH 13/43] file_xfer: Remove FileXferTask structure alignment + +There's no reason beside losing performances to align +that structure, is not passed as binary data. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/file_xfer.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/vdagent/file_xfer.h b/vdagent/file_xfer.h +index 25cd5c2..029d0e7 100644 +--- a/vdagent/file_xfer.h ++++ b/vdagent/file_xfer.h +@@ -21,7 +21,7 @@ + #include + #include "vdcommon.h" + +-typedef struct ALIGN_VC FileXferTask { ++typedef struct FileXferTask { + FileXferTask(HANDLE _handle, uint64_t _size, const TCHAR* _name): + handle(_handle), size(_size), pos(0) { + // FIXME: should raise an error if name is too long.. +@@ -36,7 +36,7 @@ typedef struct ALIGN_VC FileXferTask { + TCHAR name[MAX_PATH]; + + void cancel(); +-} ALIGN_GCC FileXferTask; ++} FileXferTask; + + typedef std::map FileXferTasks; + +-- +2.17.1 + diff --git a/SOURCES/0014-file_xfer-Remove-too-C-syntax-for-C.patch b/SOURCES/0014-file_xfer-Remove-too-C-syntax-for-C.patch new file mode 100644 index 0000000..adc680b --- /dev/null +++ b/SOURCES/0014-file_xfer-Remove-too-C-syntax-for-C.patch @@ -0,0 +1,39 @@ +From e8ab5856a116f6b7b9bd28781fcf2f685cc6645f Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 25 May 2018 19:46:34 +0100 +Subject: [PATCH 14/43] file_xfer: Remove too C syntax for C++ + +In C++ simply declaring the struct add the structure name to the global +namespace, no needs for additional typedef. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/file_xfer.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/vdagent/file_xfer.h b/vdagent/file_xfer.h +index 029d0e7..747c29c 100644 +--- a/vdagent/file_xfer.h ++++ b/vdagent/file_xfer.h +@@ -21,7 +21,7 @@ + #include + #include "vdcommon.h" + +-typedef struct FileXferTask { ++struct FileXferTask { + FileXferTask(HANDLE _handle, uint64_t _size, const TCHAR* _name): + handle(_handle), size(_size), pos(0) { + // FIXME: should raise an error if name is too long.. +@@ -36,7 +36,7 @@ typedef struct FileXferTask { + TCHAR name[MAX_PATH]; + + void cancel(); +-} FileXferTask; ++}; + + typedef std::map FileXferTasks; + +-- +2.17.1 + diff --git a/SOURCES/0015-file_xfer-Use-destructor-for-FileXferTask.patch b/SOURCES/0015-file_xfer-Use-destructor-for-FileXferTask.patch new file mode 100644 index 0000000..616ceb8 --- /dev/null +++ b/SOURCES/0015-file_xfer-Use-destructor-for-FileXferTask.patch @@ -0,0 +1,99 @@ +From aefc220c027c98c0877cbb6dc7140e72f119262b Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 25 May 2018 20:01:11 +0100 +Subject: [PATCH 15/43] file_xfer: Use destructor for FileXferTask + +Limit too much manual work. +By default delete the file, unless success() is called. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/file_xfer.cpp | 24 +++++++++++++++--------- + vdagent/file_xfer.h | 4 +++- + 2 files changed, 18 insertions(+), 10 deletions(-) + +diff --git a/vdagent/file_xfer.cpp b/vdagent/file_xfer.cpp +index 8203b99..ff4c0b9 100644 +--- a/vdagent/file_xfer.cpp ++++ b/vdagent/file_xfer.cpp +@@ -46,7 +46,6 @@ void FileXfer::reset() + + for (iter = _tasks.begin(); iter != _tasks.end(); iter++) { + task = iter->second; +- task->cancel(); + delete task; + } + _tasks.clear(); +@@ -181,14 +180,11 @@ bool FileXfer::handle_data(VDAgentFileXferDataMessage* data, + return false; + } + vd_printf("%u completed", iter->first); ++ task->success(); + status->result = VD_AGENT_FILE_XFER_STATUS_SUCCESS; + + fin: + if (task) { +- CloseHandle(task->handle); +- if (status->result != VD_AGENT_FILE_XFER_STATUS_SUCCESS) { +- DeleteFile(task->name); +- } + _tasks.erase(iter); + delete task; + } +@@ -196,10 +192,21 @@ fin: + return true; + } + +-void FileXferTask::cancel() ++FileXferTask::~FileXferTask() + { +- CloseHandle(handle); +- DeleteFile(name); ++ if (handle != INVALID_HANDLE_VALUE) { ++ CloseHandle(handle); ++ DeleteFile(name); ++ } ++} ++ ++void FileXferTask::success() ++{ ++ // close the handle so the destructor won't delete the file ++ if (handle != INVALID_HANDLE_VALUE) { ++ CloseHandle(handle); ++ handle = INVALID_HANDLE_VALUE; ++ } + } + + void FileXfer::handle_status(VDAgentFileXferStatusMessage* status) +@@ -218,7 +225,6 @@ void FileXfer::handle_status(VDAgentFileXferStatusMessage* status) + return; + } + task = iter->second; +- task->cancel(); + _tasks.erase(iter); + delete task; + } +diff --git a/vdagent/file_xfer.h b/vdagent/file_xfer.h +index 747c29c..41f677a 100644 +--- a/vdagent/file_xfer.h ++++ b/vdagent/file_xfer.h +@@ -30,12 +30,14 @@ struct FileXferTask { + lstrcpyn(name, _name, ARRAYSIZE(name)); + name[ARRAYSIZE(name)-1] = 0; + } ++ ~FileXferTask(); ++ + HANDLE handle; + uint64_t size; + uint64_t pos; + TCHAR name[MAX_PATH]; + +- void cancel(); ++ void success(); + }; + + typedef std::map FileXferTasks; +-- +2.17.1 + diff --git a/SOURCES/0016-file_xfer-Use-shared_ptr-to-simplify-memory-manageme.patch b/SOURCES/0016-file_xfer-Use-shared_ptr-to-simplify-memory-manageme.patch new file mode 100644 index 0000000..21ae854 --- /dev/null +++ b/SOURCES/0016-file_xfer-Use-shared_ptr-to-simplify-memory-manageme.patch @@ -0,0 +1,130 @@ +From 7b0c48b15bfe3c02c4158c7cb213403739d078b5 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 25 May 2018 23:03:18 +0100 +Subject: [PATCH 16/43] file_xfer: Use shared_ptr to simplify memory management + +Clear automatically tasks items. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/file_xfer.cpp | 25 ++++--------------------- + vdagent/file_xfer.h | 3 ++- + 2 files changed, 6 insertions(+), 22 deletions(-) + +diff --git a/vdagent/file_xfer.cpp b/vdagent/file_xfer.cpp +index ff4c0b9..ada3b47 100644 +--- a/vdagent/file_xfer.cpp ++++ b/vdagent/file_xfer.cpp +@@ -41,19 +41,11 @@ + + void FileXfer::reset() + { +- FileXferTasks::iterator iter; +- FileXferTask* task; +- +- for (iter = _tasks.begin(); iter != _tasks.end(); iter++) { +- task = iter->second; +- delete task; +- } + _tasks.clear(); + } + + FileXfer::~FileXfer() + { +- reset(); + } + + void FileXfer::handle_start(VDAgentFileXferStartMessage* start, +@@ -63,7 +55,6 @@ void FileXfer::handle_start(VDAgentFileXferStartMessage* start, + TCHAR file_path[MAX_PATH]; + char file_name[MAX_PATH]; + ULARGE_INTEGER free_bytes; +- FileXferTask* task; + uint64_t file_size; + HANDLE handle; + AsUser as_user; +@@ -146,7 +137,7 @@ void FileXfer::handle_start(VDAgentFileXferStartMessage* start, + vd_printf("Failed creating %ls. More than 63 copies exist?", file_path); + return; + } +- task = new FileXferTask(handle, file_size, file_path); ++ auto task = std::make_shared(handle, file_size, file_path); + _tasks[start->id] = task; + status->result = VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA; + } +@@ -155,7 +146,6 @@ bool FileXfer::handle_data(VDAgentFileXferDataMessage* data, + VDAgentFileXferStatusMessage* status) + { + FileXferTasks::iterator iter; +- FileXferTask* task = NULL; + DWORD written; + + status->id = data->id; +@@ -163,9 +153,9 @@ bool FileXfer::handle_data(VDAgentFileXferDataMessage* data, + iter = _tasks.find(data->id); + if (iter == _tasks.end()) { + vd_printf("file id %u not found", data->id); +- goto fin; ++ return true; + } +- task = iter->second; ++ auto task = iter->second; + task->pos += data->size; + if (task->pos > task->size) { + vd_printf("file xfer is longer than expected"); +@@ -184,11 +174,7 @@ bool FileXfer::handle_data(VDAgentFileXferDataMessage* data, + status->result = VD_AGENT_FILE_XFER_STATUS_SUCCESS; + + fin: +- if (task) { +- _tasks.erase(iter); +- delete task; +- } +- ++ _tasks.erase(iter); + return true; + } + +@@ -212,7 +198,6 @@ void FileXferTask::success() + void FileXfer::handle_status(VDAgentFileXferStatusMessage* status) + { + FileXferTasks::iterator iter; +- FileXferTask* task; + + vd_printf("id %u result %u", status->id, status->result); + if (status->result != VD_AGENT_FILE_XFER_STATUS_CANCELLED) { +@@ -224,9 +209,7 @@ void FileXfer::handle_status(VDAgentFileXferStatusMessage* status) + vd_printf("file id %u not found", status->id); + return; + } +- task = iter->second; + _tasks.erase(iter); +- delete task; + } + + bool FileXfer::dispatch(VDAgentMessage* msg, VDAgentFileXferStatusMessage* status) +diff --git a/vdagent/file_xfer.h b/vdagent/file_xfer.h +index 41f677a..b138019 100644 +--- a/vdagent/file_xfer.h ++++ b/vdagent/file_xfer.h +@@ -19,6 +19,7 @@ + #define _H_FILE_XFER + + #include ++#include + #include "vdcommon.h" + + struct FileXferTask { +@@ -40,7 +41,7 @@ struct FileXferTask { + void success(); + }; + +-typedef std::map FileXferTasks; ++typedef std::map > FileXferTasks; + + class FileXfer { + public: +-- +2.17.1 + diff --git a/SOURCES/0017-vdagent-Fix-loss-of-mouse-movement-events.patch b/SOURCES/0017-vdagent-Fix-loss-of-mouse-movement-events.patch new file mode 100644 index 0000000..3e7da7c --- /dev/null +++ b/SOURCES/0017-vdagent-Fix-loss-of-mouse-movement-events.patch @@ -0,0 +1,257 @@ +From b291e4ca14b611ad20cb93d90dc98c8a715b91f9 Mon Sep 17 00:00:00 2001 +From: "free.user.name" +Date: Fri, 16 Feb 2018 15:05:39 +0300 +Subject: [PATCH 17/43] vdagent: Fix loss of mouse movement events + +send_input() may not be immediately called from handle_mouse_event() on +movement. INPUT structure is generated and stored and a timer may be set +instead. If subsequent call to handle_mouse_event() occurs before timer +expires, prepared INPUT structure gets overwritten and MOUSEEVENTF_MOVE +bit is lost. Windows doesn't see updated mouse position as the result. + +Make handle_mouse_event() merely store the new mouse state, and move +INPUT structure generation to send_input(). Shuffle new mouse state to +previous only after mouse events are submitted to SendInput() Windows +API function. + +This patch was sent to the mailing list by an anonymous contributor +with minimal style changes. + +You can easily test increasing VD_INPUT_INTERVAL_MS (like 1000). +For instance you can try in a word processor to move the cursor +clicking the mouse on different positions. + +Acked-by: Victor Toso +--- + vdagent/vdagent.cpp | 145 +++++++++++++++++++++----------------------- + 1 file changed, 70 insertions(+), 75 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 0a364df..ca1f8fa 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -89,8 +89,7 @@ private: + void on_clipboard_grab(); + void on_clipboard_request(UINT format); + void on_clipboard_release(); +- DWORD get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state, +- DWORD mask, DWORD down_flag, DWORD up_flag); ++ DWORD get_buttons_change(DWORD mask, DWORD down_flag, DWORD up_flag); + static HGLOBAL utf8_alloc(LPCSTR data, int size); + static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); + static DWORD WINAPI event_thread_proc(LPVOID param); +@@ -130,10 +129,8 @@ private: + int _system_version; + int _clipboard_owner; + DWORD _clipboard_tick; +- DWORD _buttons_state; +- ULONG _mouse_x; +- ULONG _mouse_y; +- INPUT _input; ++ VDAgentMouseState _new_mouse = {}; ++ VDAgentMouseState _last_mouse = {}; + DWORD _input_time; + HANDLE _control_event; + HANDLE _stop_event; +@@ -190,9 +187,6 @@ VDAgent::VDAgent() + , _remove_clipboard_listener (NULL) + , _clipboard_owner (owner_none) + , _clipboard_tick (0) +- , _buttons_state (0) +- , _mouse_x (0) +- , _mouse_y (0) + , _input_time (0) + , _control_event (NULL) + , _stop_event (NULL) +@@ -220,7 +214,6 @@ VDAgent::VDAgent() + swprintf_s(log_path, MAX_PATH, VD_AGENT_LOG_PATH, temp_path); + _log = VDLog::get(log_path); + } +- ZeroMemory(&_input, sizeof(_input)); + ZeroMemory(&_read_overlapped, sizeof(_read_overlapped)); + ZeroMemory(&_write_overlapped, sizeof(_write_overlapped)); + ZeroMemory(_read_buf, sizeof(_read_buf)); +@@ -521,113 +514,115 @@ void VDAgent::event_dispatcher(DWORD timeout, DWORD wake_mask) + } + } + +-DWORD VDAgent::get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state, +- DWORD mask, DWORD down_flag, DWORD up_flag) ++DWORD VDAgent::get_buttons_change(DWORD mask, DWORD down_flag, DWORD up_flag) + { + DWORD ret = 0; +- if (!(last_buttons_state & mask) && (new_buttons_state & mask)) { ++ if (!(_last_mouse.buttons & mask) && (_new_mouse.buttons & mask)) { + ret = down_flag; +- } else if ((last_buttons_state & mask) && !(new_buttons_state & mask)) { ++ } else if ((_last_mouse.buttons & mask) && !(_new_mouse.buttons & mask)) { + ret = up_flag; + } + return ret; + } + + bool VDAgent::send_input() +-{ +- bool ret = true; +- _desktop_layout->lock(); +- if (_pending_input) { +- if (KillTimer(_hwnd, VD_TIMER_ID)) { +- _pending_input = false; +- } else { +- vd_printf("KillTimer failed: %lu", GetLastError()); +- _running = false; +- _desktop_layout->unlock(); +- return false; +- } +- } +- if (!SendInput(1, &_input, sizeof(INPUT))) { +- DWORD err = GetLastError(); +- // Don't stop agent due to UIPI blocking, which is usually only for specific windows +- // of system security applications (anti-viruses etc.) +- if (err != ERROR_SUCCESS && err != ERROR_ACCESS_DENIED) { +- vd_printf("SendInput failed: %lu", err); +- ret = _running = false; +- } +- } +- _input_time = GetTickCount(); +- _desktop_layout->unlock(); +- return ret; +-} +- +-bool VDAgent::handle_mouse_event(VDAgentMouseState* state) + { + DisplayMode* mode = NULL; + DWORD mouse_move = 0; + DWORD buttons_change = 0; + DWORD mouse_wheel = 0; + bool ret = true; ++ INPUT input; ++ ++ if (_pending_input) { ++ if (KillTimer(_hwnd, VD_TIMER_ID)) { ++ _pending_input = false; ++ } else { ++ vd_printf("KillTimer failed: %lu", GetLastError()); ++ _running = false; ++ return false; ++ } ++ } + + ASSERT(_desktop_layout); + _desktop_layout->lock(); +- if (state->display_id < _desktop_layout->get_display_count()) { +- mode = _desktop_layout->get_display(state->display_id); ++ if (_new_mouse.display_id < _desktop_layout->get_display_count()) { ++ mode = _desktop_layout->get_display(_new_mouse.display_id); + } + if (!mode || !mode->get_attached()) { + _desktop_layout->unlock(); + return true; + } +- ZeroMemory(&_input, sizeof(INPUT)); +- _input.type = INPUT_MOUSE; +- if (state->x != _mouse_x || state->y != _mouse_y) { ++ ZeroMemory(&input, sizeof(INPUT)); ++ input.type = INPUT_MOUSE; ++ if (_new_mouse.x != _last_mouse.x || _new_mouse.y != _last_mouse.y) { + DWORD w = _desktop_layout->get_total_width(); + DWORD h = _desktop_layout->get_total_height(); + w = (w > 1) ? w-1 : 1; /* coordinates are 0..w-1, protect w==0 */ + h = (h > 1) ? h-1 : 1; /* coordinates are 0..h-1, protect h==0 */ +- _mouse_x = state->x; +- _mouse_y = state->y; + mouse_move = MOUSEEVENTF_MOVE; +- _input.mi.dx = (mode->get_pos_x() + _mouse_x) * 0xffff / w; +- _input.mi.dy = (mode->get_pos_y() + _mouse_y) * 0xffff / h; ++ input.mi.dx = (mode->get_pos_x() + _new_mouse.x) * 0xffff / w; ++ input.mi.dy = (mode->get_pos_y() + _new_mouse.y) * 0xffff / h; + } +- if (state->buttons != _buttons_state) { +- buttons_change = get_buttons_change(_buttons_state, state->buttons, VD_AGENT_LBUTTON_MASK, ++ if (_new_mouse.buttons != _last_mouse.buttons) { ++ buttons_change = get_buttons_change(VD_AGENT_LBUTTON_MASK, + MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP) | +- get_buttons_change(_buttons_state, state->buttons, VD_AGENT_MBUTTON_MASK, ++ get_buttons_change(VD_AGENT_MBUTTON_MASK, + MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP) | +- get_buttons_change(_buttons_state, state->buttons, VD_AGENT_RBUTTON_MASK, ++ get_buttons_change(VD_AGENT_RBUTTON_MASK, + MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP); +- mouse_wheel = get_buttons_change(_buttons_state, state->buttons, +- VD_AGENT_UBUTTON_MASK | VD_AGENT_DBUTTON_MASK, ++ mouse_wheel = get_buttons_change(VD_AGENT_UBUTTON_MASK | VD_AGENT_DBUTTON_MASK, + MOUSEEVENTF_WHEEL, 0); + if (mouse_wheel) { +- if (state->buttons & VD_AGENT_UBUTTON_MASK) { +- _input.mi.mouseData = WHEEL_DELTA; +- } else if (state->buttons & VD_AGENT_DBUTTON_MASK) { +- _input.mi.mouseData = (DWORD)(-WHEEL_DELTA); ++ if (_new_mouse.buttons & VD_AGENT_UBUTTON_MASK) { ++ input.mi.mouseData = WHEEL_DELTA; ++ } else if (_new_mouse.buttons & VD_AGENT_DBUTTON_MASK) { ++ input.mi.mouseData = (DWORD)(-WHEEL_DELTA); + } + } +- _buttons_state = state->buttons; + } + +- _input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | mouse_move | +- mouse_wheel | buttons_change; ++ input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | mouse_move | ++ mouse_wheel | buttons_change; + +- if ((mouse_move && GetTickCount() - _input_time > VD_INPUT_INTERVAL_MS) || buttons_change || +- mouse_wheel) { +- ret = send_input(); +- } else if (!_pending_input) { +- if (SetTimer(_hwnd, VD_TIMER_ID, VD_INPUT_INTERVAL_MS, NULL)) { ++ if (!SendInput(1, &input, sizeof(INPUT))) { ++ DWORD err = GetLastError(); ++ // Don't stop agent due to UIPI blocking, which is usually only for specific windows ++ // of system security applications (anti-viruses etc.) ++ if (err != ERROR_SUCCESS && err != ERROR_ACCESS_DENIED) { ++ vd_printf("SendInput failed: %lu", err); ++ ret = _running = false; ++ } ++ } else { ++ _last_mouse = _new_mouse; ++ } ++ _input_time = GetTickCount(); ++ _desktop_layout->unlock(); ++ return ret; ++} ++ ++bool VDAgent::handle_mouse_event(VDAgentMouseState* state) ++{ ++ _new_mouse = *state; ++ if (_new_mouse.buttons != _last_mouse.buttons) { ++ return send_input(); ++ } ++ ++ if (_new_mouse.x != _last_mouse.x || _new_mouse.y != _last_mouse.y) { ++ if (GetTickCount() - _input_time > VD_INPUT_INTERVAL_MS) { ++ return send_input(); ++ } ++ ++ if (!_pending_input) { ++ if (!SetTimer(_hwnd, VD_TIMER_ID, VD_INPUT_INTERVAL_MS, NULL)) { ++ vd_printf("SetTimer failed: %lu", GetLastError()); ++ _running = false; ++ return false; ++ } + _pending_input = true; +- } else { +- vd_printf("SetTimer failed: %lu", GetLastError()); +- _running = false; +- ret = false; + } + } +- _desktop_layout->unlock(); +- return ret; ++ return true; + } + + bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port) +-- +2.17.1 + diff --git a/SOURCES/0018-Reuse-spice-protocol-macros-instead-of-defining-new-.patch b/SOURCES/0018-Reuse-spice-protocol-macros-instead-of-defining-new-.patch new file mode 100644 index 0000000..fc1dfb3 --- /dev/null +++ b/SOURCES/0018-Reuse-spice-protocol-macros-instead-of-defining-new-.patch @@ -0,0 +1,54 @@ +From 531dd85f60e3de8fd6deddc820f3f6a92d83186c Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Mon, 28 May 2018 10:50:14 +0100 +Subject: [PATCH 18/43] Reuse spice-protocol macros instead of defining new + ones for alignment + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + common/vdcommon.h | 8 -------- + vdagent/vdagent.cpp | 6 ++++-- + 2 files changed, 4 insertions(+), 10 deletions(-) + +diff --git a/common/vdcommon.h b/common/vdcommon.h +index c1920e9..ac58efe 100644 +--- a/common/vdcommon.h ++++ b/common/vdcommon.h +@@ -67,14 +67,6 @@ typedef Mutex mutex_t; + #define VD_AGENT_REGISTRY_KEY "SOFTWARE\\Red Hat\\Spice\\vdagent\\" + #define VD_AGENT_STOP_EVENT TEXT("Global\\vdagent_stop_event") + +-#if defined __GNUC__ +-#define ALIGN_GCC __attribute__ ((packed)) +-#define ALIGN_VC +-#else +-#define ALIGN_GCC +-#define ALIGN_VC __declspec (align(1)) +-#endif +- + /* + * Note: OLDMSVCRT, which is defined (in the Makefile) for mingw builds, and + * is not defined for Visual Studio builds. +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index ca1f8fa..e22687c 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -55,10 +55,12 @@ static const VDClipboardFormat clipboard_formats[] = { + + #define clipboard_formats_count SPICE_N_ELEMENTS(clipboard_formats) + +-typedef struct ALIGN_VC VDIChunk { ++#include ++typedef struct SPICE_ATTR_PACKED VDIChunk { + VDIChunkHeader hdr; + uint8_t data[0]; +-} ALIGN_GCC VDIChunk; ++} VDIChunk; ++#include + + #define VD_MESSAGE_HEADER_SIZE (sizeof(VDIChunk) + sizeof(VDAgentMessage)) + #define VD_READ_BUF_SIZE (sizeof(VDIChunk) + VD_AGENT_MAX_DATA_SIZE) +-- +2.17.1 + diff --git a/SOURCES/0019-vdservice-Do-not-append-line-terminator-to-log.patch b/SOURCES/0019-vdservice-Do-not-append-line-terminator-to-log.patch new file mode 100644 index 0000000..eeb9e9f --- /dev/null +++ b/SOURCES/0019-vdservice-Do-not-append-line-terminator-to-log.patch @@ -0,0 +1,29 @@ +From 14769f88c923945aba4aa257f9a8632a5b685210 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Tue, 29 May 2018 10:29:52 +0100 +Subject: [PATCH 19/43] vdservice: Do not append line terminator to log + +vd_printf already add a line terminator + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdservice/vdservice.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/vdservice/vdservice.cpp b/vdservice/vdservice.cpp +index ec6243e..7564fbb 100644 +--- a/vdservice/vdservice.cpp ++++ b/vdservice/vdservice.cpp +@@ -337,7 +337,7 @@ VOID WINAPI VDService::main(DWORD argc, TCHAR* argv[]) + s->_status_handle = RegisterServiceCtrlHandlerEx(VD_SERVICE_NAME, &VDService::control_handler, + s); + if (!s->_status_handle) { +- vd_printf("RegisterServiceCtrlHandler failed\n"); ++ vd_printf("RegisterServiceCtrlHandler failed"); + return; + } + +-- +2.17.1 + diff --git a/SOURCES/0020-Fix-some-minor-buffer-overflows-reading-registry-inf.patch b/SOURCES/0020-Fix-some-minor-buffer-overflows-reading-registry-inf.patch new file mode 100644 index 0000000..fc1f3a2 --- /dev/null +++ b/SOURCES/0020-Fix-some-minor-buffer-overflows-reading-registry-inf.patch @@ -0,0 +1,80 @@ +From 13fb63e328f799a4e87dc62f81f3d58faab6987c Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 25 May 2018 21:50:57 +0100 +Subject: [PATCH 20/43] Fix some minor buffer overflows reading registry + informations + +Strings in the registry can be not NUL-terminated. +Current code to make sure they are NUL-terminated can add an extra +NUL character at the end of the buffer. +Also RegQueryValueEx returns the number of bytes read, not the number +of characters so the value must be fixed to avoid overflows. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/display_setting.cpp | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/vdagent/display_setting.cpp b/vdagent/display_setting.cpp +index 25a248e..2b22144 100644 +--- a/vdagent/display_setting.cpp ++++ b/vdagent/display_setting.cpp +@@ -285,7 +285,7 @@ bool DisplaySetting::disable_wallpaper() + bool DisplaySetting::reload_wallpaper(HKEY desktop_reg_key) + { + TCHAR wallpaper_path[MAX_PATH + 1]; +- DWORD value_size = sizeof(wallpaper_path); ++ DWORD value_size = sizeof(wallpaper_path) - sizeof(wallpaper_path[0]); + DWORD value_type; + LONG status; + TCHAR cur_wallpaper[MAX_PATH + 1]; +@@ -303,7 +303,8 @@ bool DisplaySetting::reload_wallpaper(HKEY desktop_reg_key) + return false; + } + +- if (wallpaper_path[value_size - 1] != '\0') { ++ value_size /= sizeof(wallpaper_path[0]); ++ if (!value_size || wallpaper_path[value_size - 1] != '\0') { + wallpaper_path[value_size] = '\0'; + } + +@@ -339,7 +340,7 @@ bool DisplaySetting::disable_font_smoothing() + bool DisplaySetting::reload_font_smoothing(HKEY desktop_reg_key) + { + CHAR smooth_value[4]; +- DWORD value_size = sizeof(smooth_value); ++ DWORD value_size = sizeof(smooth_value)-1; + DWORD value_type; + LONG status; + BOOL cur_font_smooth; +@@ -357,7 +358,7 @@ bool DisplaySetting::reload_font_smoothing(HKEY desktop_reg_key) + return false; + } + +- if (smooth_value[value_size - 1] != '\0') { ++ if (!value_size || smooth_value[value_size - 1] != '\0') { + smooth_value[value_size] = '\0'; + } + +@@ -412,7 +413,7 @@ bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key) + { + HKEY win_metrics_hkey; + CHAR win_anim_value[4]; +- DWORD value_size = sizeof(win_anim_value); ++ DWORD value_size = sizeof(win_anim_value)-1; + DWORD value_type; + LONG status; + ANIMATIONINFO active_win_animation; +@@ -441,7 +442,7 @@ bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key) + return false; + } + +- if (win_anim_value[value_size - 1] != '\0') { ++ if (!value_size || win_anim_value[value_size - 1] != '\0') { + win_anim_value[value_size] = '\0'; + } + +-- +2.17.1 + diff --git a/SOURCES/0021-Use-enumeration-types.patch b/SOURCES/0021-Use-enumeration-types.patch new file mode 100644 index 0000000..17403e5 --- /dev/null +++ b/SOURCES/0021-Use-enumeration-types.patch @@ -0,0 +1,62 @@ +From ae94c50ee912ab8925cda61449235a8027d49c77 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 30 May 2018 14:21:00 +0100 +Subject: [PATCH 21/43] Use enumeration types + +No reasons to allow any possible number. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index e22687c..551f326 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -100,10 +100,10 @@ private: + void dispatch_message(VDAgentMessage* msg, uint32_t port); + uint32_t get_clipboard_format(uint32_t type) const; + uint32_t get_clipboard_type(uint32_t format) const; +- enum { owner_none, owner_guest, owner_client }; +- void set_clipboard_owner(int new_owner); +- enum { CONTROL_STOP, CONTROL_RESET, CONTROL_DESKTOP_SWITCH, CONTROL_LOGON, CONTROL_CLIPBOARD }; +- void set_control_event(int control_command); ++ enum clipboard_owner_t { owner_none, owner_guest, owner_client }; ++ void set_clipboard_owner(clipboard_owner_t new_owner); ++ enum control_command_t { CONTROL_STOP, CONTROL_RESET, CONTROL_DESKTOP_SWITCH, CONTROL_LOGON, CONTROL_CLIPBOARD }; ++ void set_control_event(control_command_t control_command); + void handle_control_event(); + VDIChunk* new_chunk(DWORD bytes = 0); + void enqueue_chunk(VDIChunk* msg); +@@ -346,7 +346,7 @@ void VDAgent::cleanup() + delete _desktop_layout; + } + +-void VDAgent::set_control_event(int control_command) ++void VDAgent::set_control_event(control_command_t control_command) + { + MutexLocker lock(_control_mutex); + _control_queue.push(control_command); +@@ -1207,7 +1207,7 @@ uint32_t VDAgent::get_clipboard_type(uint32_t format) const + return 0; + } + +-void VDAgent::set_clipboard_owner(int new_owner) ++void VDAgent::set_clipboard_owner(clipboard_owner_t new_owner) + { + // FIXME: Clear requests, clipboard data and state + if (new_owner == owner_none) { +@@ -1455,7 +1455,7 @@ LRESULT CALLBACK VDAgent::wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARA + case WM_CLIPBOARDUPDATE: + case WM_DRAWCLIPBOARD: + if (a->_hwnd != GetClipboardOwner()) { +- a->set_clipboard_owner(a->owner_none); ++ a->set_clipboard_owner(owner_none); + a->on_clipboard_grab(); + } + if (a->_hwnd_next_viewer) { +-- +2.17.1 + diff --git a/SOURCES/0022-Minimal-message-size-check.patch b/SOURCES/0022-Minimal-message-size-check.patch new file mode 100644 index 0000000..161d629 --- /dev/null +++ b/SOURCES/0022-Minimal-message-size-check.patch @@ -0,0 +1,80 @@ +From 8251fa25ac0c0a9a8055a6eb7299d7d379341b94 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 30 May 2018 14:32:10 +0100 +Subject: [PATCH 22/43] Minimal message size check + +Avoid some possible integer overflows. + +Signed-off-by: Frediano Ziglio +--- + vdagent/vdagent.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 551f326..1e8f27c 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -1231,6 +1231,60 @@ void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port) + { + bool res = true; + ++ // check minimal message size ++ int min_size = -1; ++ switch (msg->type) { ++ case VD_AGENT_MOUSE_STATE: ++ min_size = sizeof(VDAgentMouseState); ++ break; ++ case VD_AGENT_MONITORS_CONFIG: ++ min_size = sizeof(VDAgentMonitorsConfig); ++ break; ++ case VD_AGENT_CLIPBOARD: ++ min_size = sizeof(VDAgentClipboard); ++ break; ++ case VD_AGENT_CLIPBOARD_GRAB: ++ min_size = sizeof(VDAgentClipboardGrab); ++ break; ++ case VD_AGENT_CLIPBOARD_REQUEST: ++ min_size = sizeof(VDAgentClipboardRequest); ++ break; ++ case VD_AGENT_CLIPBOARD_RELEASE: ++ min_size = sizeof(VDAgentClipboardRelease); ++ break; ++ case VD_AGENT_DISPLAY_CONFIG: ++ min_size = sizeof(VDAgentDisplayConfig); ++ break; ++ case VD_AGENT_ANNOUNCE_CAPABILITIES: ++ min_size = sizeof(VDAgentAnnounceCapabilities); ++ break; ++ case VD_AGENT_FILE_XFER_START: ++ min_size = sizeof(VDAgentFileXferStatusMessage); ++ break; ++ case VD_AGENT_FILE_XFER_STATUS: ++ min_size = sizeof(VDAgentFileXferStatusMessage); ++ break; ++ case VD_AGENT_FILE_XFER_DATA: ++ min_size = sizeof(VDAgentFileXferDataMessage); ++ break; ++ case VD_AGENT_CLIENT_DISCONNECTED: ++ min_size = 0; ++ break; ++ case VD_AGENT_MAX_CLIPBOARD: ++ min_size = sizeof(VDAgentMaxClipboard); ++ break; ++ } ++ if (min_size < 0) { ++ vd_printf("Unsupported message type %u size %u", msg->type, msg->size); ++ _running = false; ++ return; ++ } ++ if (msg->size < (unsigned) min_size) { ++ vd_printf("Unexpected msg size %u for message type %u", msg->size, msg->type); ++ _running = false; ++ return; ++ } ++ + switch (msg->type) { + case VD_AGENT_MOUSE_STATE: + res = handle_mouse_event((VDAgentMouseState*)msg->data); +-- +2.17.1 + diff --git a/SOURCES/0023-Use-proper-type-for-_clipboard_owner.patch b/SOURCES/0023-Use-proper-type-for-_clipboard_owner.patch new file mode 100644 index 0000000..49039df --- /dev/null +++ b/SOURCES/0023-Use-proper-type-for-_clipboard_owner.patch @@ -0,0 +1,27 @@ +From bc3384f359765fe84aa8e53e0330886d5b6e42f3 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 06:02:27 +0100 +Subject: [PATCH 23/43] Use proper type for _clipboard_owner + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe de Dinechin +--- + vdagent/vdagent.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 1e8f27c..78c42d1 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -129,7 +129,7 @@ private: + PCLIPBOARD_OP _add_clipboard_listener; + PCLIPBOARD_OP _remove_clipboard_listener; + int _system_version; +- int _clipboard_owner; ++ clipboard_owner_t _clipboard_owner; + DWORD _clipboard_tick; + VDAgentMouseState _new_mouse = {}; + VDAgentMouseState _last_mouse = {}; +-- +2.17.1 + diff --git a/SOURCES/0024-Reduce-indentation-returning-earlier.patch b/SOURCES/0024-Reduce-indentation-returning-earlier.patch new file mode 100644 index 0000000..dde88ce --- /dev/null +++ b/SOURCES/0024-Reduce-indentation-returning-earlier.patch @@ -0,0 +1,82 @@ +From 873464cecceb1895a620ca3606004f7c856cfd79 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 29 Jun 2018 07:50:44 +0100 +Subject: [PATCH 24/43] Reduce indentation returning earlier + +Also add some comments. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 45 ++++++++++++++++++++++++++------------------- + 2 files changed, 27 insertions(+), 20 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 78c42d1..cf492cc 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -1393,6 +1393,7 @@ void VDAgent::handle_chunk(VDIChunk* chunk) + { + //FIXME: currently assumes that multi-part msg arrives only from client port + if (_in_msg_pos == 0 || chunk->hdr.port == VDP_SERVER_PORT) { ++ // ignore the chunk if too short + if (chunk->hdr.size < sizeof(VDAgentMessage)) { + return; + } +@@ -1404,28 +1405,34 @@ void VDAgent::handle_chunk(VDIChunk* chunk) + } + uint32_t msg_size = sizeof(VDAgentMessage) + msg->size; + if (chunk->hdr.size == msg_size) { ++ // we got an entire message, handle it + dispatch_message(msg, chunk->hdr.port); ++ return; ++ } ++ ++ // got just the start, start to collapse all chunks into a ++ // single buffer ++ ASSERT(chunk->hdr.size < msg_size); ++ _in_msg = (VDAgentMessage*)new uint8_t[msg_size]; ++ memcpy(_in_msg, chunk->data, chunk->hdr.size); ++ _in_msg_pos = chunk->hdr.size; ++ return; ++ } ++ ++ // the previous chunk was a partial message, so append this chunk to the previous chunk ++ memcpy((uint8_t*)_in_msg + _in_msg_pos, chunk->data, chunk->hdr.size); ++ _in_msg_pos += chunk->hdr.size; ++ // update clipboard tick on each clipboard chunk for timeout setting ++ if (_in_msg->type == VD_AGENT_CLIPBOARD && _clipboard_tick) { ++ _clipboard_tick = GetTickCount(); ++ } ++ if (_in_msg_pos == sizeof(VDAgentMessage) + _in_msg->size) { ++ if (_in_msg->type == VD_AGENT_CLIPBOARD && !_clipboard_tick) { ++ vd_printf("Clipboard received but dropped due to timeout"); + } else { +- ASSERT(chunk->hdr.size < msg_size); +- _in_msg = (VDAgentMessage*)new uint8_t[msg_size]; +- memcpy(_in_msg, chunk->data, chunk->hdr.size); +- _in_msg_pos = chunk->hdr.size; +- } +- } else { +- memcpy((uint8_t*)_in_msg + _in_msg_pos, chunk->data, chunk->hdr.size); +- _in_msg_pos += chunk->hdr.size; +- // update clipboard tick on each clipboard chunk for timeout setting +- if (_in_msg->type == VD_AGENT_CLIPBOARD && _clipboard_tick) { +- _clipboard_tick = GetTickCount(); +- } +- if (_in_msg_pos == sizeof(VDAgentMessage) + _in_msg->size) { +- if (_in_msg->type == VD_AGENT_CLIPBOARD && !_clipboard_tick) { +- vd_printf("Clipboard received but dropped due to timeout"); +- } else { +- dispatch_message(_in_msg, 0); +- } +- cleanup_in_msg(); ++ dispatch_message(_in_msg, 0); + } ++ cleanup_in_msg(); + } + } + +-- +2.17.1 + diff --git a/SOURCES/0025-Minor-overflow-checks-improvements.patch b/SOURCES/0025-Minor-overflow-checks-improvements.patch new file mode 100644 index 0000000..9a93e09 --- /dev/null +++ b/SOURCES/0025-Minor-overflow-checks-improvements.patch @@ -0,0 +1,43 @@ +From 3e8cab6da1a1572db9a91ee21687ab5dca7671b1 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 26 May 2018 07:53:51 +0100 +Subject: [PATCH 25/43] Minor overflow checks improvements + +Although source of these data should be safe, improve data checks +to avoid some overflows and make the code more robust. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index cf492cc..9fbff3d 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -1368,7 +1368,7 @@ VOID VDAgent::read_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlapped) + count = sizeof(VDIChunk) - a->_read_pos; + } else if (a->_read_pos == sizeof(VDIChunk)) { + count = chunk->hdr.size; +- if (a->_read_pos + count > sizeof(a->_read_buf)) { ++ if (count > sizeof(a->_read_buf) - a->_read_pos) { + vd_printf("chunk is too large, size %u port %u", chunk->hdr.size, chunk->hdr.port); + a->_running = false; + return; +@@ -1420,6 +1420,12 @@ void VDAgent::handle_chunk(VDIChunk* chunk) + } + + // the previous chunk was a partial message, so append this chunk to the previous chunk ++ if (chunk->hdr.size > sizeof(VDAgentMessage) + _in_msg->size - _in_msg_pos) { ++ vd_printf("Invalid VDAgentMessage message"); ++ _running = false; ++ return; ++ } ++ + memcpy((uint8_t*)_in_msg + _in_msg_pos, chunk->data, chunk->hdr.size); + _in_msg_pos += chunk->hdr.size; + // update clipboard tick on each clipboard chunk for timeout setting +-- +2.17.1 + diff --git a/SOURCES/0026-Replace-an-assert-with-proper-handling-code.patch b/SOURCES/0026-Replace-an-assert-with-proper-handling-code.patch new file mode 100644 index 0000000..aa45ac9 --- /dev/null +++ b/SOURCES/0026-Replace-an-assert-with-proper-handling-code.patch @@ -0,0 +1,33 @@ +From 18cbe9f306f6dcfeeb4952e278dd88e2520d87f6 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 29 Jun 2018 08:02:02 +0100 +Subject: [PATCH 26/43] Replace an assert with proper handling code + +Make sure the condition is handled properly. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 9fbff3d..7b3720d 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -1412,7 +1412,11 @@ void VDAgent::handle_chunk(VDIChunk* chunk) + + // got just the start, start to collapse all chunks into a + // single buffer +- ASSERT(chunk->hdr.size < msg_size); ++ if (chunk->hdr.size >= msg_size) { ++ vd_printf("Invalid VDAgentMessage message"); ++ _running = false; ++ return; ++ } + _in_msg = (VDAgentMessage*)new uint8_t[msg_size]; + memcpy(_in_msg, chunk->data, chunk->hdr.size); + _in_msg_pos = chunk->hdr.size; +-- +2.17.1 + diff --git a/SOURCES/0027-Use-std-unique_ptr-for-_desktop_layout.patch b/SOURCES/0027-Use-std-unique_ptr-for-_desktop_layout.patch new file mode 100644 index 0000000..8743417 --- /dev/null +++ b/SOURCES/0027-Use-std-unique_ptr-for-_desktop_layout.patch @@ -0,0 +1,55 @@ +From 0984079e08c252b0baf5ccab50f8196edd714904 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Fri, 29 Jun 2018 19:33:25 +0100 +Subject: [PATCH 27/43] Use std::unique_ptr for _desktop_layout + +Make automatic the release of this pointer. +Also avoids having a leak if VDAgent::run is called twice. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 7b3720d..1a68e0c 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -142,7 +142,7 @@ private: + bool _running; + bool _session_is_locked; + bool _desktop_switch; +- DesktopLayout* _desktop_layout; ++ std::unique_ptr _desktop_layout; + bool _updating_display_config; + DisplaySetting _display_setting; + FileXfer _file_xfer; +@@ -198,7 +198,6 @@ VDAgent::VDAgent() + , _running (false) + , _session_is_locked (false) + , _desktop_switch (false) +- , _desktop_layout (NULL) + , _display_setting (VD_AGENT_REGISTRY_KEY) + , _vio_serial (NULL) + , _read_pos (0) +@@ -301,7 +300,7 @@ bool VDAgent::run() + cleanup(); + return false; + } +- _desktop_layout = new DesktopLayout(); ++ _desktop_layout.reset(new DesktopLayout()); + if (_desktop_layout->get_display_count() == 0) { + vd_printf("No QXL devices!"); + } +@@ -343,7 +342,6 @@ void VDAgent::cleanup() + CloseHandle(_stop_event); + CloseHandle(_control_event); + CloseHandle(_vio_serial); +- delete _desktop_layout; + } + + void VDAgent::set_control_event(control_command_t control_command) +-- +2.17.1 + diff --git a/SOURCES/0028-Use-always-TCHAR-to-read-string-from-registry.patch b/SOURCES/0028-Use-always-TCHAR-to-read-string-from-registry.patch new file mode 100644 index 0000000..9411c7d --- /dev/null +++ b/SOURCES/0028-Use-always-TCHAR-to-read-string-from-registry.patch @@ -0,0 +1,103 @@ +From 97ef38dc6d69a14365b1245e9a6406105a033a8a Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Mon, 28 May 2018 16:04:34 +0100 +Subject: [PATCH 28/43] Use always TCHAR to read string from registry + +This is a preparation patch in order to factor out code to read +a string from registry. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/display_setting.cpp | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/vdagent/display_setting.cpp b/vdagent/display_setting.cpp +index 2b22144..cef3401 100644 +--- a/vdagent/display_setting.cpp ++++ b/vdagent/display_setting.cpp +@@ -339,15 +339,15 @@ bool DisplaySetting::disable_font_smoothing() + + bool DisplaySetting::reload_font_smoothing(HKEY desktop_reg_key) + { +- CHAR smooth_value[4]; +- DWORD value_size = sizeof(smooth_value)-1; ++ TCHAR smooth_value[4]; ++ DWORD value_size = sizeof(smooth_value)-sizeof(smooth_value[0]); + DWORD value_type; + LONG status; + BOOL cur_font_smooth; + + vd_printf(""); +- status = RegQueryValueExA(desktop_reg_key, "FontSmoothing", NULL, +- &value_type, (LPBYTE)smooth_value, &value_size); ++ status = RegQueryValueEx(desktop_reg_key, TEXT("FontSmoothing"), NULL, ++ &value_type, (LPBYTE)smooth_value, &value_size); + if (status != ERROR_SUCCESS) { + vd_printf("RegQueryValueEx(FontSmoothing) : fail %ld", status); + return false; +@@ -358,15 +358,16 @@ bool DisplaySetting::reload_font_smoothing(HKEY desktop_reg_key) + return false; + } + ++ value_size /= sizeof(smooth_value[0]); + if (!value_size || smooth_value[value_size - 1] != '\0') { + smooth_value[value_size] = '\0'; + } + +- if (strcmp(smooth_value, "0") == 0) { ++ if (_tcscmp(smooth_value, TEXT("0")) == 0) { + vd_printf("font smoothing is disabled in registry. do nothing"); + return true; +- } else if (strcmp(smooth_value, "2") != 0) { +- vd_printf("unexpectd font smoothing value %s", smooth_value); ++ } else if (_tcscmp(smooth_value, TEXT("2")) != 0) { ++ vd_printf("unexpectd font smoothing value %ls", smooth_value); + return false; + } + +@@ -412,8 +413,8 @@ bool DisplaySetting::disable_animation() + bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key) + { + HKEY win_metrics_hkey; +- CHAR win_anim_value[4]; +- DWORD value_size = sizeof(win_anim_value)-1; ++ TCHAR win_anim_value[4]; ++ DWORD value_size = sizeof(win_anim_value)-sizeof(win_anim_value[0]); + DWORD value_type; + LONG status; + ANIMATIONINFO active_win_animation; +@@ -427,8 +428,8 @@ bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key) + return false; + } + +- status = RegQueryValueExA(win_metrics_hkey, "MinAnimate", NULL, +- &value_type, (LPBYTE)win_anim_value, &value_size); ++ status = RegQueryValueEx(win_metrics_hkey, TEXT("MinAnimate"), NULL, ++ &value_type, (LPBYTE)win_anim_value, &value_size); + if (status != ERROR_SUCCESS) { + vd_printf("RegQueryValueEx(MinAnimate) : fail %ld", status); + RegCloseKey(win_metrics_hkey); +@@ -442,15 +443,16 @@ bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key) + return false; + } + ++ value_size /= sizeof(win_anim_value[0]); + if (!value_size || win_anim_value[value_size - 1] != '\0') { + win_anim_value[value_size] = '\0'; + } + +- if (!strcmp(win_anim_value, "0")) { ++ if (!_tcscmp(win_anim_value, TEXT("0"))) { + vd_printf("window animation is disabled in registry. do nothing"); + return true; +- } else if (strcmp(win_anim_value, "1") != 0) { +- vd_printf("unexpectd window animation value %s", win_anim_value); ++ } else if (_tcscmp(win_anim_value, TEXT("1")) != 0) { ++ vd_printf("unexpectd window animation value %ls", win_anim_value); + return false; + } + active_win_animation.cbSize = sizeof(ANIMATIONINFO); +-- +2.17.1 + diff --git a/SOURCES/0029-Factor-out-an-utility-function-to-read-strings-from-.patch b/SOURCES/0029-Factor-out-an-utility-function-to-read-strings-from-.patch new file mode 100644 index 0000000..6fed049 --- /dev/null +++ b/SOURCES/0029-Factor-out-an-utility-function-to-read-strings-from-.patch @@ -0,0 +1,159 @@ +From 1a2e2d1411c131c63703be04a82522462c89918a Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 26 May 2018 07:55:12 +0100 +Subject: [PATCH 29/43] Factor out an utility function to read strings from + registry + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/display_setting.cpp | 91 +++++++++++++++++-------------------- + 1 file changed, 41 insertions(+), 50 deletions(-) + +diff --git a/vdagent/display_setting.cpp b/vdagent/display_setting.cpp +index cef3401..78c67d6 100644 +--- a/vdagent/display_setting.cpp ++++ b/vdagent/display_setting.cpp +@@ -282,32 +282,54 @@ bool DisplaySetting::disable_wallpaper() + } + } + ++#if defined(UNICODE) || defined(_UNICODE) ++#define PRIsTSTR "ls" ++#else ++#define PRIsTSTR "s" ++#endif ++ ++static bool RegReadString(HKEY key, const TCHAR *name, TCHAR *buffer, size_t buffer_len) ++{ ++ DWORD value_size = (buffer_len - 1) * sizeof(buffer[0]); ++ DWORD value_type; ++ LONG status; ++ ++ status = RegQueryValueEx(key, name, NULL, &value_type, (LPBYTE)buffer, &value_size); ++ if (status != ERROR_SUCCESS) { ++ vd_printf("RegQueryValueEx(%" PRIsTSTR ") : fail %ld", name, status); ++ return false; ++ } ++ ++ if (value_type != REG_SZ) { ++ vd_printf("bad %" PRIsTSTR " value type %lu (expected REG_SZ)", name, value_type); ++ return false; ++ } ++ ++ // assure NUL-terminated ++ value_size /= sizeof(buffer[0]); ++ if (!value_size || buffer[value_size - 1] != '\0') { ++ buffer[value_size] = '\0'; ++ } ++ ++ return true; ++} ++ ++template ++static inline bool RegReadString(HKEY key, const TCHAR *name, TCHAR (&buffer)[N]) ++{ ++ return RegReadString(key, name, buffer, N); ++} ++ + bool DisplaySetting::reload_wallpaper(HKEY desktop_reg_key) + { + TCHAR wallpaper_path[MAX_PATH + 1]; +- DWORD value_size = sizeof(wallpaper_path) - sizeof(wallpaper_path[0]); +- DWORD value_type; +- LONG status; + TCHAR cur_wallpaper[MAX_PATH + 1]; + + vd_printf(""); +- status = RegQueryValueEx(desktop_reg_key, TEXT("Wallpaper"), NULL, +- &value_type, (LPBYTE)wallpaper_path, &value_size); +- if (status != ERROR_SUCCESS) { +- vd_printf("RegQueryValueEx(Wallpaper) : fail %ld", status); ++ if (!RegReadString(desktop_reg_key, TEXT("Wallpaper"), wallpaper_path)) { + return false; + } + +- if (value_type != REG_SZ) { +- vd_printf("bad wallpaper value type %lu (expected REG_SZ)", value_type); +- return false; +- } +- +- value_size /= sizeof(wallpaper_path[0]); +- if (!value_size || wallpaper_path[value_size - 1] != '\0') { +- wallpaper_path[value_size] = '\0'; +- } +- + if (SystemParametersInfo(SPI_GETDESKWALLPAPER, SPICE_N_ELEMENTS(cur_wallpaper), cur_wallpaper, 0)) { + if (_tcscmp(cur_wallpaper, TEXT("")) != 0) { + vd_printf("wallpaper wasn't disabled"); +@@ -340,29 +362,13 @@ bool DisplaySetting::disable_font_smoothing() + bool DisplaySetting::reload_font_smoothing(HKEY desktop_reg_key) + { + TCHAR smooth_value[4]; +- DWORD value_size = sizeof(smooth_value)-sizeof(smooth_value[0]); +- DWORD value_type; +- LONG status; + BOOL cur_font_smooth; + + vd_printf(""); +- status = RegQueryValueEx(desktop_reg_key, TEXT("FontSmoothing"), NULL, +- &value_type, (LPBYTE)smooth_value, &value_size); +- if (status != ERROR_SUCCESS) { +- vd_printf("RegQueryValueEx(FontSmoothing) : fail %ld", status); ++ if (!RegReadString(desktop_reg_key, TEXT("FontSmoothing"), smooth_value)) { + return false; + } + +- if (value_type != REG_SZ) { +- vd_printf("bad font smoothing value type %lu (expected REG_SZ)", value_type); +- return false; +- } +- +- value_size /= sizeof(smooth_value[0]); +- if (!value_size || smooth_value[value_size - 1] != '\0') { +- smooth_value[value_size] = '\0'; +- } +- + if (_tcscmp(smooth_value, TEXT("0")) == 0) { + vd_printf("font smoothing is disabled in registry. do nothing"); + return true; +@@ -414,8 +420,6 @@ bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key) + { + HKEY win_metrics_hkey; + TCHAR win_anim_value[4]; +- DWORD value_size = sizeof(win_anim_value)-sizeof(win_anim_value[0]); +- DWORD value_type; + LONG status; + ANIMATIONINFO active_win_animation; + +@@ -428,26 +432,13 @@ bool DisplaySetting::reload_win_animation(HKEY desktop_reg_key) + return false; + } + +- status = RegQueryValueEx(win_metrics_hkey, TEXT("MinAnimate"), NULL, +- &value_type, (LPBYTE)win_anim_value, &value_size); +- if (status != ERROR_SUCCESS) { +- vd_printf("RegQueryValueEx(MinAnimate) : fail %ld", status); ++ if (!RegReadString(win_metrics_hkey, TEXT("MinAnimate"), win_anim_value)) { + RegCloseKey(win_metrics_hkey); + return false; + } + + RegCloseKey(win_metrics_hkey); + +- if (value_type != REG_SZ) { +- vd_printf("bad MinAnimate value type %lu (expected REG_SZ)", value_type); +- return false; +- } +- +- value_size /= sizeof(win_anim_value[0]); +- if (!value_size || win_anim_value[value_size - 1] != '\0') { +- win_anim_value[value_size] = '\0'; +- } +- + if (!_tcscmp(win_anim_value, TEXT("0"))) { + vd_printf("window animation is disabled in registry. do nothing"); + return true; +-- +2.17.1 + diff --git a/SOURCES/0030-Allow-one-more-character-reading-strings-from-regist.patch b/SOURCES/0030-Allow-one-more-character-reading-strings-from-regist.patch new file mode 100644 index 0000000..b8b4e9d --- /dev/null +++ b/SOURCES/0030-Allow-one-more-character-reading-strings-from-regist.patch @@ -0,0 +1,67 @@ +From 7b368a134fac63f4e603969694b83c916df04e17 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 26 May 2018 07:55:12 +0100 +Subject: [PATCH 30/43] Allow one more character reading strings from registry + +The strings in the registry are usually NUL-terminated but this +is not a requirement. +Handle the case when the string, considering the terminator, fit +into the reading buffer. In this case accept the string. In the +case the string fit into the buffer but is not terminated +returns ERROR_MORE_DATA (the error that would be returned if the +string didn't fit in the buffer as there is no place to add the +terminator). + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/display_setting.cpp | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/vdagent/display_setting.cpp b/vdagent/display_setting.cpp +index 78c67d6..b6711d7 100644 +--- a/vdagent/display_setting.cpp ++++ b/vdagent/display_setting.cpp +@@ -290,11 +290,25 @@ bool DisplaySetting::disable_wallpaper() + + static bool RegReadString(HKEY key, const TCHAR *name, TCHAR *buffer, size_t buffer_len) + { +- DWORD value_size = (buffer_len - 1) * sizeof(buffer[0]); ++ DWORD value_size = buffer_len * sizeof(buffer[0]); + DWORD value_type; + LONG status; + + status = RegQueryValueEx(key, name, NULL, &value_type, (LPBYTE)buffer, &value_size); ++ if (status == ERROR_SUCCESS && value_type == REG_SZ) { ++ // ensure NUL-terminated ++ value_size /= sizeof(buffer[0]); ++ if (value_size == buffer_len) { ++ // full buffer but not terminated? ++ if (buffer[value_size-1] != '\0') { ++ status = ERROR_MORE_DATA; ++ } ++ } else { ++ // append a NUL. If there's already a NUL character this ++ // new one will be ignored ++ buffer[value_size] = '\0'; ++ } ++ } + if (status != ERROR_SUCCESS) { + vd_printf("RegQueryValueEx(%" PRIsTSTR ") : fail %ld", name, status); + return false; +@@ -305,12 +319,6 @@ static bool RegReadString(HKEY key, const TCHAR *name, TCHAR *buffer, size_t buf + return false; + } + +- // assure NUL-terminated +- value_size /= sizeof(buffer[0]); +- if (!value_size || buffer[value_size - 1] != '\0') { +- buffer[value_size] = '\0'; +- } +- + return true; + } + +-- +2.17.1 + diff --git a/SOURCES/0031-Allocate-_control_event-and-_stop_event-just-once.patch b/SOURCES/0031-Allocate-_control_event-and-_stop_event-just-once.patch new file mode 100644 index 0000000..4eae0f6 --- /dev/null +++ b/SOURCES/0031-Allocate-_control_event-and-_stop_event-just-once.patch @@ -0,0 +1,60 @@ +From 6a0683707f3fcebcca3d3e5aced46ec3024f3784 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 05:31:13 +0100 +Subject: [PATCH 31/43] Allocate _control_event and _stop_event just once + +Handle _control_event and _stop_event destruction in destructor. +Allows to call VDAgent::run multiple time if needed. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 1a68e0c..64055c4 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -224,6 +224,8 @@ VDAgent::VDAgent() + + VDAgent::~VDAgent() + { ++ CloseHandle(_stop_event); ++ CloseHandle(_control_event); + delete _log; + } + +@@ -285,13 +287,18 @@ bool VDAgent::run() + return false; + } + } +- _control_event = CreateEvent(NULL, FALSE, FALSE, NULL); ++ if (!_control_event) ++ _control_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!_control_event) { + vd_printf("CreateEvent() failed: %lu", GetLastError()); + cleanup(); + return false; + } +- _stop_event = OpenEvent(SYNCHRONIZE, FALSE, VD_AGENT_STOP_EVENT); ++ ResetEvent(_control_event); ++ ++ if (!_stop_event) ++ _stop_event = OpenEvent(SYNCHRONIZE, FALSE, VD_AGENT_STOP_EVENT); ++ + memset(&wcls, 0, sizeof(wcls)); + wcls.lpfnWndProc = &VDAgent::wnd_proc; + wcls.lpszClassName = VD_AGENT_WINCLASS_NAME; +@@ -339,8 +346,6 @@ bool VDAgent::run() + void VDAgent::cleanup() + { + FreeLibrary(_user_lib); +- CloseHandle(_stop_event); +- CloseHandle(_control_event); + CloseHandle(_vio_serial); + } + +-- +2.17.1 + diff --git a/SOURCES/0032-Avoid-declaring-event_thread_id.patch b/SOURCES/0032-Avoid-declaring-event_thread_id.patch new file mode 100644 index 0000000..8d6ebe1 --- /dev/null +++ b/SOURCES/0032-Avoid-declaring-event_thread_id.patch @@ -0,0 +1,37 @@ +From c0a6e42e809a5d177c4863ae24e43cf523ab0b4b Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 09:05:08 +0100 +Subject: [PATCH 32/43] Avoid declaring event_thread_id + +As the value is never used we can pass NULL in CreateThread. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 64055c4..fc8e727 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -255,7 +255,6 @@ DWORD WINAPI VDAgent::event_thread_proc(LPVOID param) + bool VDAgent::run() + { + DWORD session_id; +- DWORD event_thread_id; + HANDLE event_thread; + WNDCLASS wcls; + +@@ -322,7 +321,7 @@ bool VDAgent::run() + return false; + } + _running = true; +- event_thread = CreateThread(NULL, 0, event_thread_proc, this, 0, &event_thread_id); ++ event_thread = CreateThread(NULL, 0, event_thread_proc, this, 0, NULL); + if (!event_thread) { + vd_printf("CreateThread() failed: %lu", GetLastError()); + cleanup(); +-- +2.17.1 + diff --git a/SOURCES/0033-Avoid-declaring-_system_version-member.patch b/SOURCES/0033-Avoid-declaring-_system_version-member.patch new file mode 100644 index 0000000..2cbf9d0 --- /dev/null +++ b/SOURCES/0033-Avoid-declaring-_system_version-member.patch @@ -0,0 +1,64 @@ +From e9421d09b82c7c1ff284175d335b23303ac80e69 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 09:05:40 +0100 +Subject: [PATCH 33/43] Avoid declaring _system_version member + +The check can be done a single time, no reason to cache +supported_system_version() value. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index fc8e727..95783c1 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -128,7 +128,6 @@ private: + HMODULE _user_lib; + PCLIPBOARD_OP _add_clipboard_listener; + PCLIPBOARD_OP _remove_clipboard_listener; +- int _system_version; + clipboard_owner_t _clipboard_owner; + DWORD _clipboard_tick; + VDAgentMouseState _new_mouse = {}; +@@ -210,7 +209,6 @@ VDAgent::VDAgent() + TCHAR log_path[MAX_PATH]; + TCHAR temp_path[MAX_PATH]; + +- _system_version = supported_system_version(); + if (GetTempPath(MAX_PATH, temp_path)) { + swprintf_s(log_path, MAX_PATH, VD_AGENT_LOG_PATH, temp_path); + _log = VDLog::get(log_path); +@@ -270,7 +268,7 @@ bool VDAgent::run() + if (!SetProcessShutdownParameters(0x100, 0)) { + vd_printf("SetProcessShutdownParameters failed %lu", GetLastError()); + } +- if (_system_version == SYS_VER_WIN_7_CLASS) { ++ if (supported_system_version() == SYS_VER_WIN_7_CLASS) { + _user_lib = LoadLibrary(L"User32.dll"); + if (!_user_lib) { + vd_printf("LoadLibrary failed %lu", GetLastError()); +@@ -447,7 +445,7 @@ void VDAgent::input_desktop_message_loop() + if (!WTSRegisterSessionNotification(_hwnd, NOTIFY_FOR_ALL_SESSIONS)) { + vd_printf("WTSRegisterSessionNotification() failed: %lu", GetLastError()); + } +- if (_system_version == SYS_VER_WIN_7_CLASS) { ++ if (_add_clipboard_listener) { + _add_clipboard_listener(_hwnd); + } else { + _hwnd_next_viewer = SetClipboardViewer(_hwnd); +@@ -460,7 +458,7 @@ void VDAgent::input_desktop_message_loop() + KillTimer(_hwnd, VD_TIMER_ID); + _pending_input = false; + } +- if (_system_version == SYS_VER_WIN_7_CLASS) { ++ if (_remove_clipboard_listener) { + _remove_clipboard_listener(_hwnd); + } else { + ChangeClipboardChain(_hwnd, _hwnd_next_viewer); +-- +2.17.1 + diff --git a/SOURCES/0034-Avoids-to-call-supported_system_version.patch b/SOURCES/0034-Avoids-to-call-supported_system_version.patch new file mode 100644 index 0000000..11cbb06 --- /dev/null +++ b/SOURCES/0034-Avoids-to-call-supported_system_version.patch @@ -0,0 +1,61 @@ +From 55290d17666d2237896ba0c8cd9c028ddc29f5c9 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 09:14:08 +0100 +Subject: [PATCH 34/43] Avoids to call supported_system_version() + +The only reason we call this function is to check if the +system should support some APIs. +Instead just check directly if these APIs are supported +calling GetProcAddress directly. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + vdagent/vdagent.cpp | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 95783c1..423c3ee 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -268,22 +268,22 @@ bool VDAgent::run() + if (!SetProcessShutdownParameters(0x100, 0)) { + vd_printf("SetProcessShutdownParameters failed %lu", GetLastError()); + } +- if (supported_system_version() == SYS_VER_WIN_7_CLASS) { +- _user_lib = LoadLibrary(L"User32.dll"); +- if (!_user_lib) { +- vd_printf("LoadLibrary failed %lu", GetLastError()); +- return false; +- } +- _add_clipboard_listener = +- (PCLIPBOARD_OP)GetProcAddress(_user_lib, "AddClipboardFormatListener"); +- _remove_clipboard_listener = +- (PCLIPBOARD_OP)GetProcAddress(_user_lib, "RemoveClipboardFormatListener"); +- if (!_add_clipboard_listener || !_remove_clipboard_listener) { +- vd_printf("GetProcAddress failed %lu", GetLastError()); +- cleanup(); +- return false; +- } ++ ++ _user_lib = LoadLibrary(L"User32.dll"); ++ if (!_user_lib) { ++ vd_printf("LoadLibrary failed %lu", GetLastError()); ++ return false; + } ++ _add_clipboard_listener = ++ (PCLIPBOARD_OP)GetProcAddress(_user_lib, "AddClipboardFormatListener"); ++ _remove_clipboard_listener = ++ (PCLIPBOARD_OP)GetProcAddress(_user_lib, "RemoveClipboardFormatListener"); ++ // do not use FormatListener APIs if not available ++ if (!_add_clipboard_listener || !_remove_clipboard_listener) { ++ _add_clipboard_listener = nullptr; ++ _remove_clipboard_listener = nullptr; ++ } ++ + if (!_control_event) + _control_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!_control_event) { +-- +2.17.1 + diff --git a/SOURCES/0035-vdlog-Remove-the-lookup-table-for-log-types.patch b/SOURCES/0035-vdlog-Remove-the-lookup-table-for-log-types.patch new file mode 100644 index 0000000..f6c2179 --- /dev/null +++ b/SOURCES/0035-vdlog-Remove-the-lookup-table-for-log-types.patch @@ -0,0 +1,62 @@ +From c4b8c5349e3870cde0101e890e6aeb7f78bc89e2 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sun, 1 Jul 2018 06:50:58 +0100 +Subject: [PATCH 35/43] vdlog: Remove the lookup table for log types + +As log type is passed as constant in some macros and the lockup +is basically using this name without the prefix pass to the macro +the name without the prefix. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + common/vdlog.h | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/common/vdlog.h b/common/vdlog.h +index 9f08fc4..d017ac3 100644 +--- a/common/vdlog.h ++++ b/common/vdlog.h +@@ -59,8 +59,7 @@ static const VDLogLevel log_level = LOG_INFO; + #endif + + #define LOG(type, format, ...) do { \ +- if (type >= log_level && type <= LOG_FATAL) { \ +- const char *type_as_char[] = { "DEBUG", "INFO", "WARN", "ERROR", "FATAL" }; \ ++ if (LOG_ ## type >= log_level && LOG_ ## type <= LOG_FATAL) { \ + struct _timeb now; \ + struct tm today; \ + char datetime_str[20]; \ +@@ -68,23 +67,23 @@ static const VDLogLevel log_level = LOG_INFO; + localtime_s(&today, &now.time); \ + strftime(datetime_str, 20, "%Y-%m-%d %H:%M:%S", &today); \ + VDLog::printf("%lu::%s::%s,%.3d::%s::" format "\n", \ +- GetCurrentThreadId(), type_as_char[type], \ ++ GetCurrentThreadId(), #type, \ + datetime_str, now.millitm, \ + __FUNCTION__, ## __VA_ARGS__); \ + } \ + } while(0) + + +-#define vd_printf(format, ...) LOG(LOG_INFO, format, ## __VA_ARGS__) +-#define LOG_INFO(format, ...) LOG(LOG_INFO, format, ## __VA_ARGS__) +-#define LOG_WARN(format, ...) LOG(LOG_WARN, format, ## __VA_ARGS__) +-#define LOG_ERROR(format, ...) LOG(LOG_ERROR, format, ## __VA_ARGS__) ++#define vd_printf(format, ...) LOG(INFO, format, ## __VA_ARGS__) ++#define LOG_INFO(format, ...) LOG(INFO, format, ## __VA_ARGS__) ++#define LOG_WARN(format, ...) LOG(WARN, format, ## __VA_ARGS__) ++#define LOG_ERROR(format, ...) LOG(ERROR, format, ## __VA_ARGS__) + + #define DBGLEVEL 1000 + + #define DBG(level, format, ...) do { \ + if (level <= DBGLEVEL) { \ +- LOG(LOG_DEBUG, format, ## __VA_ARGS__); \ ++ LOG(DEBUG, format, ## __VA_ARGS__); \ + } \ + } while(0) + +-- +2.17.1 + diff --git a/SOURCES/0036-vdlog-Factor-our-a-logf-function-to-avoid-long-LOG-m.patch b/SOURCES/0036-vdlog-Factor-our-a-logf-function-to-avoid-long-LOG-m.patch new file mode 100644 index 0000000..4d86452 --- /dev/null +++ b/SOURCES/0036-vdlog-Factor-our-a-logf-function-to-avoid-long-LOG-m.patch @@ -0,0 +1,86 @@ +From df20de186c5a014c4064a4f6e57bd53493c37348 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Tue, 29 May 2018 01:01:23 +0100 +Subject: [PATCH 36/43] vdlog: Factor our a "logf" function to avoid long "LOG" + macro + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + common/vdlog.cpp | 26 ++++++++++++++++++++++++++ + common/vdlog.h | 15 +++++---------- + 2 files changed, 31 insertions(+), 10 deletions(-) + +diff --git a/common/vdlog.cpp b/common/vdlog.cpp +index 8af6dcc..8c11d33 100644 +--- a/common/vdlog.cpp ++++ b/common/vdlog.cpp +@@ -79,6 +79,32 @@ void VDLog::printf(const char* format, ...) + fflush(fh); + } + ++void VDLog::logf(const char *type, const char *function, const char* format, ...) ++{ ++ FILE *fh = _log ? _log->_handle : stdout; ++ va_list args; ++ ++ struct _timeb now; ++ struct tm today; ++ char datetime_str[20]; ++ _ftime_s(&now); ++ localtime_s(&today, &now.time); ++ strftime(datetime_str, 20, "%Y-%m-%d %H:%M:%S", &today); ++ ++ _lock_file(fh); ++ fprintf(fh, "%lu::%s::%s,%.3d::%s::", ++ GetCurrentThreadId(), type, ++ datetime_str, ++ now.millitm, ++ function); ++ ++ va_start(args, format); ++ vfprintf(fh, format, args); ++ va_end(args); ++ _unlock_file(fh); ++ fflush(fh); ++} ++ + void log_version() + { + // print same version as resource one +diff --git a/common/vdlog.h b/common/vdlog.h +index d017ac3..c80a199 100644 +--- a/common/vdlog.h ++++ b/common/vdlog.h +@@ -35,6 +35,10 @@ public: + __attribute__((__format__ (gnu_printf, 1, 2))) + #endif + static void printf(const char* format, ...); ++#ifdef __GNUC__ ++ __attribute__((__format__ (gnu_printf, 3, 4))) ++#endif ++ static void logf(const char *type, const char *function, const char* format, ...); + + private: + VDLog(FILE* handle); +@@ -60,16 +64,7 @@ static const VDLogLevel log_level = LOG_INFO; + + #define LOG(type, format, ...) do { \ + if (LOG_ ## type >= log_level && LOG_ ## type <= LOG_FATAL) { \ +- struct _timeb now; \ +- struct tm today; \ +- char datetime_str[20]; \ +- _ftime_s(&now); \ +- localtime_s(&today, &now.time); \ +- strftime(datetime_str, 20, "%Y-%m-%d %H:%M:%S", &today); \ +- VDLog::printf("%lu::%s::%s,%.3d::%s::" format "\n", \ +- GetCurrentThreadId(), #type, \ +- datetime_str, now.millitm, \ +- __FUNCTION__, ## __VA_ARGS__); \ ++ VDLog::logf(#type, __FUNCTION__, format "\n", ## __VA_ARGS__); \ + } \ + } while(0) + +-- +2.17.1 + diff --git a/SOURCES/0037-vdlog-Use-GetLocalTime-instead-of-multiple-C-functio.patch b/SOURCES/0037-vdlog-Use-GetLocalTime-instead-of-multiple-C-functio.patch new file mode 100644 index 0000000..a6a6eed --- /dev/null +++ b/SOURCES/0037-vdlog-Use-GetLocalTime-instead-of-multiple-C-functio.patch @@ -0,0 +1,46 @@ +From 9ddddf205f61b3451f37867a3bf7db455c773e53 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Tue, 29 May 2018 01:01:23 +0100 +Subject: [PATCH 37/43] vdlog: Use GetLocalTime instead of multiple C functions + +The GetLocalTime function already returns all information we +need for the log, no needs to call multiple C functions. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +--- + common/vdlog.cpp | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/common/vdlog.cpp b/common/vdlog.cpp +index 8c11d33..e2561e2 100644 +--- a/common/vdlog.cpp ++++ b/common/vdlog.cpp +@@ -84,18 +84,15 @@ void VDLog::logf(const char *type, const char *function, const char* format, ... + FILE *fh = _log ? _log->_handle : stdout; + va_list args; + +- struct _timeb now; +- struct tm today; +- char datetime_str[20]; +- _ftime_s(&now); +- localtime_s(&today, &now.time); +- strftime(datetime_str, 20, "%Y-%m-%d %H:%M:%S", &today); ++ SYSTEMTIME st; ++ GetLocalTime(&st); + + _lock_file(fh); +- fprintf(fh, "%lu::%s::%s,%.3d::%s::", ++ fprintf(fh, "%lu::%s::%.4u-%.2u-%.2u %.2u:%.2u:%.2u,%.3u::%s::", + GetCurrentThreadId(), type, +- datetime_str, +- now.millitm, ++ st.wYear, st.wMonth, st.wDay, ++ st.wHour, st.wMinute, st.wSecond, ++ st.wMilliseconds, + function); + + va_start(args, format); +-- +2.17.1 + diff --git a/SOURCES/0038-Use-proper-invalid-value-for-_vio_serial.patch b/SOURCES/0038-Use-proper-invalid-value-for-_vio_serial.patch new file mode 100644 index 0000000..47bffbb --- /dev/null +++ b/SOURCES/0038-Use-proper-invalid-value-for-_vio_serial.patch @@ -0,0 +1,32 @@ +From 6d1d4241ac9abc59970c4839845a2d174db58854 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 05:46:19 +0100 +Subject: [PATCH 38/43] Use proper invalid value for _vio_serial + +For some reason kernel handles in Windows have 2 invalid values +depending on the type. Files/devices use INVALID_HANDLE_VALUE (-1), +while others use NULL (0). As _vio_serial is a file, created +with CreateFile, use INVALID_HANDLE_VALUE for consistency. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 423c3ee..eed3103 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -198,7 +198,7 @@ VDAgent::VDAgent() + , _session_is_locked (false) + , _desktop_switch (false) + , _display_setting (VD_AGENT_REGISTRY_KEY) +- , _vio_serial (NULL) ++ , _vio_serial (INVALID_HANDLE_VALUE) + , _read_pos (0) + , _write_pos (0) + , _logon_desktop (false) +-- +2.17.1 + diff --git a/SOURCES/0039-Introduce-an-helper-to-close-VirtIo-device.patch b/SOURCES/0039-Introduce-an-helper-to-close-VirtIo-device.patch new file mode 100644 index 0000000..57454e1 --- /dev/null +++ b/SOURCES/0039-Introduce-an-helper-to-close-VirtIo-device.patch @@ -0,0 +1,54 @@ +From 0ac9d687e92165f6274786e5f5485cc65ae5c34a Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 05:48:02 +0100 +Subject: [PATCH 39/43] Introduce an helper to close VirtIo device + +Do not assume we allocated the handle doing the cleanup. +This utility will be reused in next patch. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe de Dinechin +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.cpp | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index eed3103..69d61da 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -110,6 +110,7 @@ private: + bool write_message(uint32_t type, uint32_t size, void* data); + bool write_clipboard(VDAgentMessage* msg, uint32_t size); + bool init_vio_serial(); ++ void close_vio_serial(); + bool send_input(); + void set_display_depth(uint32_t depth); + void load_display_setting(); +@@ -343,7 +344,7 @@ bool VDAgent::run() + void VDAgent::cleanup() + { + FreeLibrary(_user_lib); +- CloseHandle(_vio_serial); ++ close_vio_serial(); + } + + void VDAgent::set_control_event(control_command_t control_command) +@@ -1227,6 +1228,14 @@ bool VDAgent::init_vio_serial() + return true; + } + ++void VDAgent::close_vio_serial() ++{ ++ if (_vio_serial != INVALID_HANDLE_VALUE) { ++ CloseHandle(_vio_serial); ++ _vio_serial = INVALID_HANDLE_VALUE; ++ } ++} ++ + void VDAgent::dispatch_message(VDAgentMessage* msg, uint32_t port) + { + bool res = true; +-- +2.17.1 + diff --git a/SOURCES/0040-Use-destructor-instead-of-cleanup-function.patch b/SOURCES/0040-Use-destructor-instead-of-cleanup-function.patch new file mode 100644 index 0000000..12f76ec --- /dev/null +++ b/SOURCES/0040-Use-destructor-instead-of-cleanup-function.patch @@ -0,0 +1,102 @@ +From 2ae3bd5b9c9548c096e13f5de42855680a63b692 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sun, 1 Jul 2018 06:40:48 +0100 +Subject: [PATCH 40/43] Use destructor instead of cleanup function + +More C++ style. +Also avoids missing cleanup calls. + +Signed-off-by: Frediano Ziglio +Acked-by: Jonathon Jongsma +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.cpp | 17 ++++------------- + 1 file changed, 4 insertions(+), 13 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 69d61da..306bfbd 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -116,7 +116,6 @@ private: + void load_display_setting(); + bool send_announce_capabilities(bool request); + void cleanup_in_msg(); +- void cleanup(); + bool has_capability(unsigned int capability) const { + return VD_AGENT_HAS_CAPABILITY(_client_caps.begin(), _client_caps.size(), + capability); +@@ -223,6 +222,8 @@ VDAgent::VDAgent() + + VDAgent::~VDAgent() + { ++ FreeLibrary(_user_lib); ++ close_vio_serial(); + CloseHandle(_stop_event); + CloseHandle(_control_event); + delete _log; +@@ -257,6 +258,8 @@ bool VDAgent::run() + HANDLE event_thread; + WNDCLASS wcls; + ++ close_vio_serial(); ++ + if (!ProcessIdToSessionId(GetCurrentProcessId(), &session_id)) { + vd_printf("ProcessIdToSessionId failed %lu", GetLastError()); + return false; +@@ -289,7 +292,6 @@ bool VDAgent::run() + _control_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!_control_event) { + vd_printf("CreateEvent() failed: %lu", GetLastError()); +- cleanup(); + return false; + } + ResetEvent(_control_event); +@@ -302,7 +304,6 @@ bool VDAgent::run() + wcls.lpszClassName = VD_AGENT_WINCLASS_NAME; + if (!RegisterClass(&wcls)) { + vd_printf("RegisterClass() failed: %lu", GetLastError()); +- cleanup(); + return false; + } + _desktop_layout.reset(new DesktopLayout()); +@@ -310,20 +311,17 @@ bool VDAgent::run() + vd_printf("No QXL devices!"); + } + if (!init_vio_serial()) { +- cleanup(); + return false; + } + if (!ReadFileEx(_vio_serial, _read_buf, sizeof(VDIChunk), &_read_overlapped, read_completion) && + GetLastError() != ERROR_IO_PENDING) { + vd_printf("vio_serial read error %lu", GetLastError()); +- cleanup(); + return false; + } + _running = true; + event_thread = CreateThread(NULL, 0, event_thread_proc, this, 0, NULL); + if (!event_thread) { + vd_printf("CreateThread() failed: %lu", GetLastError()); +- cleanup(); + return false; + } + send_announce_capabilities(true); +@@ -337,16 +335,9 @@ bool VDAgent::run() + } + vd_printf("Agent stopped"); + CloseHandle(event_thread); +- cleanup(); + return true; + } + +-void VDAgent::cleanup() +-{ +- FreeLibrary(_user_lib); +- close_vio_serial(); +-} +- + void VDAgent::set_control_event(control_command_t control_command) + { + MutexLocker lock(_control_mutex); +-- +2.17.1 + diff --git a/SOURCES/0041-vdagent-Stop-correctly-helper-thread.patch b/SOURCES/0041-vdagent-Stop-correctly-helper-thread.patch new file mode 100644 index 0000000..9abb7c4 --- /dev/null +++ b/SOURCES/0041-vdagent-Stop-correctly-helper-thread.patch @@ -0,0 +1,67 @@ +From 7038aa83b393146ceaaa5ada74fdd76beef150ac Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sun, 8 Jul 2018 20:48:56 +0100 +Subject: [PATCH 41/43] vdagent: Stop correctly helper thread + +The thread launched to detect desktop switches events is not stopped +correctly causing potentially dandling pointers. +Queue a APC to make the loop exit and wait for thread termination +from the main thread. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.cpp | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index 306bfbd..e577679 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -238,20 +238,27 @@ DWORD WINAPI VDAgent::event_thread_proc(LPVOID param) + return 1; + } + while (agent->_running) { +- DWORD wait_ret = WaitForSingleObject(desktop_event, INFINITE); ++ DWORD wait_ret = WaitForSingleObjectEx(desktop_event, INFINITE, TRUE); + switch (wait_ret) { + case WAIT_OBJECT_0: + agent->set_control_event(CONTROL_DESKTOP_SWITCH); + break; ++ case WAIT_IO_COMPLETION: ++ // handle APC events ++ break; + case WAIT_TIMEOUT: + default: +- vd_printf("WaitForSingleObject(): %lu", wait_ret); ++ vd_printf("WaitForSingleObjectEx(): %lu", wait_ret); + } + } + CloseHandle(desktop_event); + return 0; + } + ++static VOID CALLBACK event_thread_stop_proc(ULONG_PTR) ++{ ++} ++ + bool VDAgent::run() + { + DWORD session_id; +@@ -333,8 +340,12 @@ bool VDAgent::run() + set_clipboard_owner(owner_none); + } + } +- vd_printf("Agent stopped"); ++ if (!QueueUserAPC(event_thread_stop_proc, event_thread, 0)) { ++ TerminateThread(event_thread, 0); ++ } ++ WaitForSingleObject(event_thread, INFINITE); + CloseHandle(event_thread); ++ vd_printf("Agent stopped"); + return true; + } + +-- +2.17.1 + diff --git a/SOURCES/0042-vdagent-Add-a-comment-around-WinSta0_DesktopSwitch-e.patch b/SOURCES/0042-vdagent-Add-a-comment-around-WinSta0_DesktopSwitch-e.patch new file mode 100644 index 0000000..e1ca449 --- /dev/null +++ b/SOURCES/0042-vdagent-Add-a-comment-around-WinSta0_DesktopSwitch-e.patch @@ -0,0 +1,36 @@ +From 9264c7f367e44ce2d4e773add80b63e1777e3e0f Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Thu, 5 Jul 2018 16:13:00 +0100 +Subject: [PATCH 42/43] vdagent: Add a comment around WinSta0_DesktopSwitch + event usage + +Multiple times while I was reading this code was not clear why the +synchronization of this event was not done in the main event loop. +Also document why we want to use it not relying just on +WTSRegisterSessionNotification and WM_WTSSESSION_CHANGE. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.cpp | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index e577679..be17ddc 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -232,6 +232,11 @@ VDAgent::~VDAgent() + DWORD WINAPI VDAgent::event_thread_proc(LPVOID param) + { + VDAgent *agent = static_cast(param); ++ // This event is monitored in a separate thread to avoid losing ++ // events as the event is signaled with PulseEvent to wake up all ++ // thread waiting for it. ++ // This event allows to detect desktop switches which do not ++ // change sessions like pressing Ctrl-Alt-Delete. + HANDLE desktop_event = OpenEvent(SYNCHRONIZE, FALSE, L"WinSta0_DesktopSwitch"); + if (!desktop_event) { + vd_printf("OpenEvent() failed: %lu", GetLastError()); +-- +2.17.1 + diff --git a/SOURCES/0043-Use-GetModuleHandle-to-get-some-functions-from-user3.patch b/SOURCES/0043-Use-GetModuleHandle-to-get-some-functions-from-user3.patch new file mode 100644 index 0000000..3333a36 --- /dev/null +++ b/SOURCES/0043-Use-GetModuleHandle-to-get-some-functions-from-user3.patch @@ -0,0 +1,61 @@ +From 348f7ed0cd355451408b5206f8fa423d406bc440 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Sat, 30 Jun 2018 05:13:07 +0100 +Subject: [PATCH 43/43] Use GetModuleHandle to get some functions from user32 + library + +The library is surely already loaded as providing clipboard and +other utilities we need. +user32 is one of the main win32 libraries. +Avoid using LoadLibrary that increment the reference so we don't +need to call FreeLibrary to cleanly decrement the reference. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +--- + vdagent/vdagent.cpp | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp +index be17ddc..89019bb 100644 +--- a/vdagent/vdagent.cpp ++++ b/vdagent/vdagent.cpp +@@ -125,7 +125,6 @@ private: + static VDAgent* _singleton; + HWND _hwnd; + HWND _hwnd_next_viewer; +- HMODULE _user_lib; + PCLIPBOARD_OP _add_clipboard_listener; + PCLIPBOARD_OP _remove_clipboard_listener; + clipboard_owner_t _clipboard_owner; +@@ -183,7 +182,6 @@ VDAgent* VDAgent::get() + VDAgent::VDAgent() + : _hwnd (NULL) + , _hwnd_next_viewer (NULL) +- , _user_lib (NULL) + , _add_clipboard_listener (NULL) + , _remove_clipboard_listener (NULL) + , _clipboard_owner (owner_none) +@@ -222,7 +220,6 @@ VDAgent::VDAgent() + + VDAgent::~VDAgent() + { +- FreeLibrary(_user_lib); + close_vio_serial(); + CloseHandle(_stop_event); + CloseHandle(_control_event); +@@ -285,9 +282,9 @@ bool VDAgent::run() + vd_printf("SetProcessShutdownParameters failed %lu", GetLastError()); + } + +- _user_lib = LoadLibrary(L"User32.dll"); ++ HMODULE _user_lib = GetModuleHandle(L"User32"); + if (!_user_lib) { +- vd_printf("LoadLibrary failed %lu", GetLastError()); ++ vd_printf("GetModuleHandle failed %lu", GetLastError()); + return false; + } + _add_clipboard_listener = +-- +2.17.1 + diff --git a/SPECS/mingw-spice-vdagent.spec b/SPECS/mingw-spice-vdagent.spec new file mode 100644 index 0000000..8bd435b --- /dev/null +++ b/SPECS/mingw-spice-vdagent.spec @@ -0,0 +1,204 @@ +%{?mingw_package_header} +%global _hardened_build 1 + +#define _version_suffix -348f + +Name: mingw-spice-vdagent +Version: 0.9.0 +Release: 3%{?dist} +Summary: MinGW Windows SPICE guest agent + +License: GPLv2+ +URL: http://spice-space.org/ +Source0: vdagent-win-%{version}%{?_version_suffix}.tar.xz + + + +Patch1:0001-Make-BitmapCoder-from_bitmap-return-a-BMP-file-forma.patch +Patch2:0002-imagetest-Save-PNG-file-using-a-helper-function.patch +Patch3:0003-imagetest-Save-BMP-file-using-BitmapCoder.patch +Patch4:0004-vdagent-Removed-unused-declaration.patch +Patch5:0005-Avoid-to-use-names-with-reserved-characters.patch +# do not apply patch6 + its revert -- do not touch Makefile.am +#Patch6:0006-Enable-some-security-options-on-output-executables.patch +#Patch7:0007-Revert-Enable-some-security-options-on-output-execut.patch +Patch8:0008-vcproj-Remove-reference-to-CxImage.patch +Patch9:0009-vcproj-Add-some-missing-files.patch +Patch10:0010-Fix-minor-compiler-compatibility.patch +Patch11:0011-Avoid-unused-variable-warning.patch +Patch12:0012-msi-Do-not-generate-deps.txt.patch +Patch13:0013-file_xfer-Remove-FileXferTask-structure-alignment.patch +Patch14:0014-file_xfer-Remove-too-C-syntax-for-C.patch +Patch15:0015-file_xfer-Use-destructor-for-FileXferTask.patch +Patch16:0016-file_xfer-Use-shared_ptr-to-simplify-memory-manageme.patch +Patch17:0017-vdagent-Fix-loss-of-mouse-movement-events.patch +Patch18:0018-Reuse-spice-protocol-macros-instead-of-defining-new-.patch +Patch19:0019-vdservice-Do-not-append-line-terminator-to-log.patch +Patch20:0020-Fix-some-minor-buffer-overflows-reading-registry-inf.patch +Patch21:0021-Use-enumeration-types.patch +Patch22:0022-Minimal-message-size-check.patch +Patch23:0023-Use-proper-type-for-_clipboard_owner.patch +Patch24:0024-Reduce-indentation-returning-earlier.patch +Patch25:0025-Minor-overflow-checks-improvements.patch +Patch26:0026-Replace-an-assert-with-proper-handling-code.patch +Patch27:0027-Use-std-unique_ptr-for-_desktop_layout.patch +Patch28:0028-Use-always-TCHAR-to-read-string-from-registry.patch +Patch29:0029-Factor-out-an-utility-function-to-read-strings-from-.patch +Patch30:0030-Allow-one-more-character-reading-strings-from-regist.patch +Patch31:0031-Allocate-_control_event-and-_stop_event-just-once.patch +Patch32:0032-Avoid-declaring-event_thread_id.patch +Patch33:0033-Avoid-declaring-_system_version-member.patch +Patch34:0034-Avoids-to-call-supported_system_version.patch +Patch35:0035-vdlog-Remove-the-lookup-table-for-log-types.patch +Patch36:0036-vdlog-Factor-our-a-logf-function-to-avoid-long-LOG-m.patch +Patch37:0037-vdlog-Use-GetLocalTime-instead-of-multiple-C-functio.patch +Patch38:0038-Use-proper-invalid-value-for-_vio_serial.patch +Patch39:0039-Introduce-an-helper-to-close-VirtIo-device.patch +Patch40:0040-Use-destructor-instead-of-cleanup-function.patch +Patch41:0041-vdagent-Stop-correctly-helper-thread.patch +Patch42:0042-vdagent-Add-a-comment-around-WinSta0_DesktopSwitch-e.patch +Patch43:0043-Use-GetModuleHandle-to-get-some-functions-from-user3.patch + +BuildRequires: mingw32-filesystem >= 23 +BuildRequires: mingw64-filesystem >= 23 +BuildRequires: mingw32-gcc-c++ +BuildRequires: mingw64-gcc-c++ +BuildRequires: mingw32-libpng-static +BuildRequires: mingw64-libpng-static +BuildRequires: mingw32-winpthreads-static +BuildRequires: mingw64-winpthreads-static +BuildRequires: mingw32-zlib-static +BuildRequires: mingw64-zlib-static +BuildRequires: pkgconfig +BuildRequires: mingw32-pkg-config +BuildRequires: mingw64-pkg-config +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: autoconf-archive + +BuildArch: noarch +ExclusiveArch: %{ix86} x86_64 + +%package -n mingw32-spice-vdagent +Summary: MinGW Windows SPICE guest agent + +%package -n mingw64-spice-vdagent +Summary: MinGW Windows SPICE guest agent + +%description +Spice agent for Windows guests offering the following features: + +Features: +* Client mouse mode (no need to grab mouse by client, no mouse lag) + this is handled by the daemon by feeding mouse events into the kernel + via uinput. +* Automatic adjustment of the Windows desktop resolution to the client resolution +* Support of copy and paste (text and images) between the active Windows + session and the client + +%description -n mingw32-spice-vdagent +Spice agent for Windows guests offering the following features: + +Features: +* Client mouse mode (no need to grab mouse by client, no mouse lag) + this is handled by the daemon by feeding mouse events into the kernel + via uinput. +* Automatic adjustment of the Windows desktop resolution to the client resolution +* Support of copy and paste (text and images) between the active Windows + session and the client + +%description -n mingw64-spice-vdagent +Spice agent for Windows guests offering the following features: + +Features: +* Client mouse mode (no need to grab mouse by client, no mouse lag) + this is handled by the daemon by feeding mouse events into the kernel + via uinput. +* Automatic adjustment of the Windows desktop resolution to the client resolution +* Support of copy and paste (text and images) between the active Windows + session and the client + +%{mingw_debug_package} + +%prep +%setup -q -n vdagent-win-%{version}%{?_version_suffix} + +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +#%patch6 -p1 +#%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 +%patch42 -p1 +%patch43 -p1 + +# --- autoreconf --- +# Without autoreconf it fails. +# Update configure.ac with the version and run autoreconf. +# build-aux/git-version-gen is currently not available in the tarball +# so use sed instead. +sed -i "s/^AC_INIT.*/AC_INIT(vdagent-win, [%{version}])/" configure.ac +sed -i "/m4_esyscmd.*build-aux.git-version-gen .tarball-version/d" configure.ac + +autoreconf -fi +# --- autoreconf --- done + +%build + +%mingw_configure --verbose --enable-debug + +%mingw_make %{?_smp_mflags} V=1 + + +%install +%mingw_make_install DESTDIR=$RPM_BUILD_ROOT + +%files -n mingw32-spice-vdagent +%defattr(-,root,root) +%{mingw32_bindir}/vdagent.exe +%{mingw32_bindir}/vdservice.exe + +%files -n mingw64-spice-vdagent +%defattr(-,root,root) +%{mingw64_bindir}/vdagent.exe +%{mingw64_bindir}/vdservice.exe + +%changelog +* Tue Aug 22 2017 Uri Lublin - 0.9.0-3 +- First build for RHEL-8.0 + Related: rhbz#1557012