Compare commits

...

724 Commits

Author SHA1 Message Date
Frediano Ziglio
4d5c60226c ci: Install missing package
Latest Fedora release does not include awk command by default.
Install it manually as required by some script.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2025-05-05 17:22:22 +01:00
Frediano Ziglio
c1b8dbbb9b Minor Python 3 updates
- Remove "u" prefix from strings;
- Raising strings as exception is not valid anymore;
- Convert generators to list where necessary;
- traceback.print_exc accept a limit as first argument, not
  a file (this even for Python 2).

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2025-04-07 19:59:32 +00:00
Qiang Yu
492c22f444 Add gl_scanout2_unix for multi plane support
Signed-off-by: Qiang Yu <yuq825@gmail.com>
2025-03-28 14:12:46 +08:00
Qiang Yu
ebf052d051 marshaller: suport multi fd
For sending multi plane gl scanout.

Signed-off-by: Qiang Yu <yuq825@gmail.com>
2025-03-25 15:58:15 +08:00
Akihiko Odaki
2f5f1d3854 test-marshallers: Define generated_test_messages.h target
Define generated_test_messages.h target; otherwise Make may not be able
to find the file and fail.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
2025-03-01 12:55:56 +00:00
Frediano Ziglio
a791a224e7 Update print syntax to Python 3
Never changed because possibly never hit these lines.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2023-12-16 18:58:37 +00:00
Chris Mayo
8c0319e31d codegen: Use context manager when opening files
Signed-off-by: Chris Mayo <aklhfex@gmail.com>
Acked-by: Frediano Ziglio <freddy77@gmail.com>
2023-12-16 18:45:46 +00:00
Chris Mayo
29dacb5f53 Stop using Python six package
Signed-off-by: Chris Mayo <aklhfex@gmail.com>
Acked-by: Frediano Ziglio <freddy77@gmail.com>
2023-12-16 18:45:43 +00:00
Chris Mayo
91fc091358 Drop Python 2 from m4/spice-deps.m4
Signed-off-by: Chris Mayo <aklhfex@gmail.com>
Acked-by: Frediano Ziglio <freddy77@gmail.com>
2023-12-16 18:45:39 +00:00
Frediano Ziglio
fe4395f3d7 build: Avoid Meson warning
Avoids:

WARNING: You should add the boolean check kwarg to the run_command call.
         It currently defaults to false,
         but it will default to true in future releases of meson.
         See also: https://github.com/mesonbuild/meson/issues/9300

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2023-11-05 15:29:33 +00:00
Vivek Kasireddy
bb8f66983a common: Add a udev helper to identify GPU Vendor
Given that libudev is widely available on many Linux distros, we
can use the relevant APIs to iterate over all the devices associated
with the drm subsystem to figure out if a specific vendor GPU
is available or not.

This capability (identifying GPU Vendor) is useful to determine
whether to launch Gstreamer pipeline using h/w accelerated
plugins. On systems where libudev is not available (Windows,
MacOS, etc) we'd have to make this determination based on the
availability of the relevant plugins in the Gstreamer registry.

Cc: Frediano Ziglio <freddy77@gmail.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Dongwon Kim <dongwon.kim@intel.com>
Cc: Hazwan Arif Mazlan <hazwan.arif.mazlan@intel.com>
Cc: Jin Chung Teng <jin.chung.teng@intel.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Acked-by: Frediano Ziglio <freddy77@gmail.com>
2023-10-17 10:32:27 +01:00
Frediano Ziglio
58d375e5ea Replace EVP_PKEY_cmp with EVP_PKEY_eq
EVP_PKEY_cmp was made obsolete in OpenSSL.
The main reason is that the return value is not coherent with
other *_cmp functions.
So it was replaced by EVP_PKEY_eq, which does the same.
Rename to avoid a deprecation warning on newer OpenSSL releases.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2022-06-29 07:57:53 +01:00
Frediano Ziglio
8a19611049 ci: Set WINEPATH during Windows build
Without it on Fedora 35 Wine is not able to find DLLs installed
on the system.
This will cause failures executing tests but this also helps in
case there are tests during the configuration phase.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2022-01-27 09:16:53 +00:00
Frediano Ziglio
a7b5474bf8 build: Correctly check for Python modules
Currently using Meson the command "python -m <MODULE_NAME>" is
run. However this command instead of trying to import the module
tried to execute it as a script failing for the updated pyparsing
with:

    /usr/bin/python3: No module named pyparsing.__main__; 'pyparsing' is a package and cannot be directly executed

So instead use "python -c 'import <MODULE_NAME>".
Autoconf is already using that command (see m4/ax_python_module.m4).

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2021-10-28 16:46:38 +01:00
Frediano Ziglio
96dd787377 Find Python3 installation correctly on MacOS
This fixes partially https://gitlab.freedesktop.org/spice/spice-gtk/-/issues/144.
Meson requires Python3 so you should be able to detect python3.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2021-08-16 10:00:28 +01:00
Frediano Ziglio
de79bac8e9 build: Update Meson requirement to 0.49
This avoids this warning:

WARNING: Project targeting '>= 0.48.0' but tried to use feature introduced in '0.49.0': / with string arguments.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2021-06-14 06:58:44 +01:00
Frediano Ziglio
bac2aa4e2d codegen: Make input structures for marshaller constant
Add const specifier to passed structure.
Make code a bit more "safe" as compiler can check if code is
trying to change some passed data.
Also allows to declare data passed as constant.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-05-24 08:08:37 +01:00
Frediano Ziglio
18f753c52f meson: Generate missing intermediate target
Tell build system how to generate the intermediate file
generated_test_messages.h.
Otherwise if removed the build will then fail.
This is also probably the reason some build intermittently fail.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2021-05-18 15:01:31 +01:00
Frediano Ziglio
bb0831cc10 canvas_base: Fix missing ntohl for Win32 platform
Win32 requires winsock2.h to be included in order to use ntohl.
To avoid the include use GUINT32_FROM_BE instead, already available.

This problem was reported by Biswapriyo Nath whom also tested the
solution for Win32.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2021-05-07 19:42:38 +01:00
Frediano Ziglio
fcfe9104bd Fix make distcheck
We need to package generated_test_messages.h file

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2021-04-14 17:29:08 +01:00
Marc-André Lureau
c39f4fd002 Fix build as meson subproject
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2021-04-13 23:37:10 +04:00
Marc-André Lureau
91362d045a Fix invalid vdagent buffer access
The caller use the "size" argument in different ways. Either the size of
the data to convert, or the end boundary to be deduced by offset.

Fix it so the the "size" argument means the amount in bytes of data to
convert, that seems simpler and saner. (yay C)

Fixes: spice#53

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2021-04-13 21:30:38 +04:00
Stefan Weil
68188b0c21 Add missing include file string.h
It is required for strcmp. This fixes a compiler warning for mingw-w64.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
Acked-by: Frediano Ziglio <freddy77@gmail.com>
2021-04-08 15:42:20 +01:00
Frediano Ziglio
c48140c493 helper-fuzzer-demarshallers: Check also test demarshallers
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-02-22 09:11:40 +00:00
Frediano Ziglio
6b662331f7 codegen: Handle zero_terminated attribute in demashaller
Make sure the output array is zero terminated to simplify
code using the output structures.

Changed in generated code:

    diff -ru gen/generated_client_demarshallers.c common/generated_client_demarshallers.c
    --- gen/generated_client_demarshallers.c	2021-02-21 15:13:42.004307087 +0000
    +++ common/generated_client_demarshallers.c	2021-02-21 15:13:58.916513426 +0000
    @@ -565,15 +565,24 @@
         return NULL;
     }

    -static uint8_t * parse_array_uint8(uint8_t *message_start, SPICE_GNUC_UNUSED uint8_t *message_end, uint8_t *struct_data, PointerInfo *this_ptr_info)
    +static uint8_t * parse_array_uint8_terminated(uint8_t *message_start, SPICE_GNUC_UNUSED uint8_t *message_end, uint8_t *struct_data, PointerInfo *this_ptr_info)
     {
         uint8_t *in = message_start + this_ptr_info->offset;
         uint8_t *end;

         end = struct_data;
         memcpy(end, in, this_ptr_info->nelements);
    +#if defined(__GNUC__)
    +#pragma GCC diagnostic push
    +#pragma GCC diagnostic ignored "-Wstringop-overflow"
    +#endif
    +    ((char *) (end))[this_ptr_info->nelements] = 0;
    +#if defined(__GNUC__)
    +#pragma GCC diagnostic pop
    +#endif
         in += this_ptr_info->nelements;
         end += this_ptr_info->nelements;
    +    end += 1;
         return end;
     }

    @@ -622,7 +631,8 @@
                 dst_info_host_data__array__nelements = host_size__value;

                 dst_info_host_data__array__nw_size = dst_info_host_data__array__nelements;
    -            dst_info_host_data__array__mem_size = sizeof(uint8_t) * dst_info_host_data__array__nelements;
    +            dst_info_host_data__array__mem_size = sizeof(uint8_t) * dst_info_host_data__array__nelements + sizeof(uint8_t);
    +            dst_info_host_data__array__mem_size = SPICE_ALIGN(dst_info_host_data__array__mem_size, 4);
                 if (SPICE_UNLIKELY(dst_info_host_data__array__nw_size > (uintptr_t) (message_end - message_start - host_data__value))) {
                     goto error;
                 }
    @@ -650,7 +660,8 @@
                 dst_info_cert_subject_data__array__nelements = cert_subject_size__value;

                 dst_info_cert_subject_data__array__nw_size = dst_info_cert_subject_data__array__nelements;
    -            dst_info_cert_subject_data__array__mem_size = sizeof(uint8_t) * dst_info_cert_subject_data__array__nelements;
    +            dst_info_cert_subject_data__array__mem_size = sizeof(uint8_t) * dst_info_cert_subject_data__array__nelements + sizeof(uint8_t);
    +            dst_info_cert_subject_data__array__mem_size = SPICE_ALIGN(dst_info_cert_subject_data__array__mem_size, 4);
                 if (SPICE_UNLIKELY(dst_info_cert_subject_data__array__nw_size > (uintptr_t) (message_end - message_start - cert_subject_data__value))) {
                     goto error;
                 }
    @@ -685,14 +696,14 @@
             out->dst_info.sport = consume_uint16(&in);
             out->dst_info.host_size = consume_uint32(&in);
             ptr_info[n_ptr].offset = consume_uint32(&in);
    -        ptr_info[n_ptr].parse = parse_array_uint8;
    +        ptr_info[n_ptr].parse = parse_array_uint8_terminated;
             ptr_info[n_ptr].dest = (void **)&out->dst_info.host_data;
             host_data__array__nelements = out->dst_info.host_size;
             ptr_info[n_ptr].nelements = host_data__array__nelements;
             n_ptr++;
             out->dst_info.cert_subject_size = consume_uint32(&in);
             ptr_info[n_ptr].offset = consume_uint32(&in);
    -        ptr_info[n_ptr].parse = parse_array_uint8;
    +        ptr_info[n_ptr].parse = parse_array_uint8_terminated;
             ptr_info[n_ptr].dest = (void **)&out->dst_info.cert_subject_data;
             cert_subject_data__array__nelements = out->dst_info.cert_subject_size;
             ptr_info[n_ptr].nelements = cert_subject_data__array__nelements;
    @@ -1050,7 +1061,8 @@
             host_data__array__nelements = host_size__value;

             host_data__array__nw_size = host_data__array__nelements;
    -        host_data__array__mem_size = sizeof(uint8_t) * host_data__array__nelements;
    +        host_data__array__mem_size = sizeof(uint8_t) * host_data__array__nelements + sizeof(uint8_t);
    +        host_data__array__mem_size = SPICE_ALIGN(host_data__array__mem_size, 4);
             if (SPICE_UNLIKELY(host_data__array__nw_size > (uintptr_t) (message_end - message_start - host_data__value))) {
                 goto error;
             }
    @@ -1078,7 +1090,8 @@
             cert_subject_data__array__nelements = cert_subject_size__value;

             cert_subject_data__array__nw_size = cert_subject_data__array__nelements;
    -        cert_subject_data__array__mem_size = sizeof(uint8_t) * cert_subject_data__array__nelements;
    +        cert_subject_data__array__mem_size = sizeof(uint8_t) * cert_subject_data__array__nelements + sizeof(uint8_t);
    +        cert_subject_data__array__mem_size = SPICE_ALIGN(cert_subject_data__array__mem_size, 4);
             if (SPICE_UNLIKELY(cert_subject_data__array__nw_size > (uintptr_t) (message_end - message_start - cert_subject_data__value))) {
                 goto error;
             }
    @@ -1107,13 +1120,13 @@
         out->sport = consume_uint16(&in);
         out->host_size = consume_uint32(&in);
         ptr_info[n_ptr].offset = consume_uint32(&in);
    -    ptr_info[n_ptr].parse = parse_array_uint8;
    +    ptr_info[n_ptr].parse = parse_array_uint8_terminated;
         ptr_info[n_ptr].dest = (void **)&out->host_data;
         ptr_info[n_ptr].nelements = host_data__array__nelements;
         n_ptr++;
         out->cert_subject_size = consume_uint32(&in);
         ptr_info[n_ptr].offset = consume_uint32(&in);
    -    ptr_info[n_ptr].parse = parse_array_uint8;
    +    ptr_info[n_ptr].parse = parse_array_uint8_terminated;
         ptr_info[n_ptr].dest = (void **)&out->cert_subject_data;
         ptr_info[n_ptr].nelements = cert_subject_data__array__nelements;
         n_ptr++;
    @@ -1338,7 +1351,8 @@
                 dst_info_host_data__array__nelements = host_size__value;

                 dst_info_host_data__array__nw_size = dst_info_host_data__array__nelements;
    -            dst_info_host_data__array__mem_size = sizeof(uint8_t) * dst_info_host_data__array__nelements;
    +            dst_info_host_data__array__mem_size = sizeof(uint8_t) * dst_info_host_data__array__nelements + sizeof(uint8_t);
    +            dst_info_host_data__array__mem_size = SPICE_ALIGN(dst_info_host_data__array__mem_size, 4);
                 if (SPICE_UNLIKELY(dst_info_host_data__array__nw_size > (uintptr_t) (message_end - message_start - host_data__value))) {
                     goto error;
                 }
    @@ -1366,7 +1380,8 @@
                 dst_info_cert_subject_data__array__nelements = cert_subject_size__value;

                 dst_info_cert_subject_data__array__nw_size = dst_info_cert_subject_data__array__nelements;
    -            dst_info_cert_subject_data__array__mem_size = sizeof(uint8_t) * dst_info_cert_subject_data__array__nelements;
    +            dst_info_cert_subject_data__array__mem_size = sizeof(uint8_t) * dst_info_cert_subject_data__array__nelements + sizeof(uint8_t);
    +            dst_info_cert_subject_data__array__mem_size = SPICE_ALIGN(dst_info_cert_subject_data__array__mem_size, 4);
                 if (SPICE_UNLIKELY(dst_info_cert_subject_data__array__nw_size > (uintptr_t) (message_end - message_start - cert_subject_data__value))) {
                     goto error;
                 }
    @@ -1401,14 +1416,14 @@
             out->dst_info.sport = consume_uint16(&in);
             out->dst_info.host_size = consume_uint32(&in);
             ptr_info[n_ptr].offset = consume_uint32(&in);
    -        ptr_info[n_ptr].parse = parse_array_uint8;
    +        ptr_info[n_ptr].parse = parse_array_uint8_terminated;
             ptr_info[n_ptr].dest = (void **)&out->dst_info.host_data;
             host_data__array__nelements = out->dst_info.host_size;
             ptr_info[n_ptr].nelements = host_data__array__nelements;
             n_ptr++;
             out->dst_info.cert_subject_size = consume_uint32(&in);
             ptr_info[n_ptr].offset = consume_uint32(&in);
    -        ptr_info[n_ptr].parse = parse_array_uint8;
    +        ptr_info[n_ptr].parse = parse_array_uint8_terminated;
             ptr_info[n_ptr].dest = (void **)&out->dst_info.cert_subject_data;
             cert_subject_data__array__nelements = out->dst_info.cert_subject_size;
             ptr_info[n_ptr].nelements = cert_subject_data__array__nelements;
    @@ -7582,7 +7597,8 @@
             name__array__nelements = name_size__value;

             name__array__nw_size = name__array__nelements;
    -        name__array__mem_size = sizeof(uint8_t) * name__array__nelements;
    +        name__array__mem_size = sizeof(uint8_t) * name__array__nelements + sizeof(uint8_t);
    +        name__array__mem_size = SPICE_ALIGN(name__array__mem_size, 4);
             if (SPICE_UNLIKELY(name__array__nw_size > (uintptr_t) (message_end - message_start - name__value))) {
                 goto error;
             }
    @@ -7609,7 +7625,7 @@

         out->name_size = consume_uint32(&in);
         ptr_info[n_ptr].offset = consume_uint32(&in);
    -    ptr_info[n_ptr].parse = parse_array_uint8;
    +    ptr_info[n_ptr].parse = parse_array_uint8_terminated;
         ptr_info[n_ptr].dest = (void **)&out->name;
         ptr_info[n_ptr].nelements = name__array__nelements;
         n_ptr++;

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-02-22 09:11:35 +00:00
Frediano Ziglio
bd15c96f54 codegen: Propagate zero_terminated attribute
Currently the attribute is not used.
However we would like to make sure when present that the array
is always zero terminated to simplify usages after demarshalling.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-02-22 09:11:33 +00:00
Frediano Ziglio
a627a14af0 codegen: Propagate attributes to element under pointers
Current propagated attributes are propagated only from member to
member type.
But for pointers you probably want to use propagated attribus to
underlying type (like an array for instance).

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-02-22 09:11:30 +00:00
Frediano Ziglio
6838f30079 codegen: Add a check to array type
If the size is not constant the array has to be allocated in some
way in the output and so there must be a specification for the
output (as default is write into the C structure all data).
The only exceptions are when the length is constant (in this case
a constant length array in the C structure is used) or a pointer
(in this case the pointer allocate the array).

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-02-22 09:11:28 +00:00
Frediano Ziglio
e49301ebd1 codegen: Make "output_attrs" variable global
Allows to reuse it.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-02-22 09:11:22 +00:00
Frediano Ziglio
d8fe0cbb84 codegen: Remove bytes array length support
This syntax was only used in protocol 1 which has been removed
time ago.
Beside not being used it's confusing and prone to errors,
array size is specified using 2 identifiers, one reporting
bytes and the other number of items, one used for marshalling,
the other for demarshalling.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2020-10-06 13:09:56 +01:00
Frediano Ziglio
d589542e04 test-quic: Add test cases for quic fuzzer
To use for start for the fuzzer.

Tests have been generated with a patch like:

	diff --git a/tests/test-quic.c b/tests/test-quic.c
	--- a/tests/test-quic.c
	+++ b/tests/test-quic.c
	@@ -372,8 +372,8 @@ static void pixbuf_compare(GdkPixbuf *pixbuf_a, GdkPixbuf *pixbuf_b)
	 static GdkPixbuf *pixbuf_new_random(int alpha)
	 {
	     gboolean has_alpha = alpha >= 0 ? alpha : g_random_boolean();
	-    gint width = g_random_int_range(100, 2000);
	-    gint height = g_random_int_range(100, 500);
	+    gint width = g_random_int_range(10, 100);
	+    gint height = g_random_int_range(10, 100);
	     GdkPixbuf *random_pixbuf;
	     guint i, size;
	     guint8 *pixels;
	@@ -401,6 +401,12 @@ static void test_pixbuf(GdkPixbuf *pixbuf)
	     compressed_data = quic_encode_from_pixbuf(pixbuf, imgbuf);

	     uncompressed_pixbuf = quic_decode_to_pixbuf(compressed_data);
	+    {
	+        static int num = 0;
	+        char fn[256];
	+        sprintf(fn, "test%d.quic", ++num);
	+        g_assert(g_file_set_contents(fn, (void *) compressed_data->data, compressed_data->len, NULL));
	+    }
	     image_buf_free(imgbuf, uncompressed_pixbuf);

	     //g_assert(memcmp(gdk_pixbuf_get_pixels(pixbuf), gdk_pixbuf_get_pixels(uncompressed_pixbuf), gdk_pixbuf_get_byte_length(uncompressed_pixbuf)));

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-09-17 06:46:57 +01:00
Frediano Ziglio
3b81e67979 test-quic: Add fuzzer capabilities to the test
Allows it to be used for fuzzying compressed images.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-09-17 06:46:57 +01:00
Frediano Ziglio
b24fe6b66b quic: Avoid possible buffer overflow in find_bucket
Proved by fuzzing the code.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-09-17 06:46:57 +01:00
Frediano Ziglio
ef1b6ff7b8 quic: Check RLE lengths
Avoid buffer overflows decoding images. On compression we compute
lengths till end of line so it won't cause regressions.
Proved by fuzzing the code.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-09-17 06:46:57 +01:00
Frediano Ziglio
404d74782c quic: Check image size in quic_decode_begin
Avoid some overflow in code due to images too big or
negative numbers.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-09-17 06:46:57 +01:00
Frediano Ziglio
762e0abae3 quic: Check we have some data to start decoding quic image
All paths already pass some data to quic_decode_begin but for the
test check it, it's not that expensive test.
Checking for not 0 is enough, all other words will potentially be
read calling more_io_words but we need one to avoid a potential
initial buffer overflow or deferencing an invalid pointer.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-09-17 06:46:57 +01:00
Marc-André Lureau
fa0c199d33 agent: fix vdagent monitor flag filtering
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2020-09-17 06:46:26 +01:00
Frediano Ziglio
0d7d0d35d8 agent: Extend agent_check_message to support VDAgentMonitorsConfig extension
Add support for VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE flag.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Marc-André Lureau <marcandre.lureau@gmail.com>
2020-09-15 11:55:45 +01:00
Frediano Ziglio
b03c894c21 quic: Fix typo in comment
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2020-09-04 21:05:48 +01:00
Frediano Ziglio
03bde6fdb2 quic: Constify a parameter
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2020-08-31 12:36:15 +01:00
Frediano Ziglio
243c314b3f proto: Add support for side mouse buttons
This is the couterpart of spice-protocol commit

    commit cbe7b2c28543f4c5e57d1db1b753b73a64104162 (HEAD -> master, origin/master, origin/HEAD)
    Author: SimonP <simonp.git@gmail.com>

        protocol: Add support for side mouse buttons

        Side mouse buttons currently do not exist in the protocol, causing them
        to be inexplicably ignored by VMs in virt-manager and such. This lays
        the groundwork for fixing that issue.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Kevin Pouget <kpouget@redhat.com>
2020-08-31 12:33:11 +01:00
Frediano Ziglio
c39cc1b1ef ssl_verify: Do not check IP if we fail to resolve it
There's no point on checking an empty IP address, an IP
address is never empty.
This also solve some compiler warnings trying to possibly
pass a NULL pointer to memcmp or setting a variable without
reading it.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-08-27 18:50:01 +01:00
Frediano Ziglio
7daee890be quic_tmpl: Remove unused bpc parameter
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-08-25 12:26:20 +01:00
Frediano Ziglio
2f045752d5 helper-fuzzer-demarshallers: Provide replacement for ftello for MSVC
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-08-10 09:55:31 +01:00
Frediano Ziglio
b843d02a1b Avoid usage of GCC extension for __VA_ARGS__ where possible
The "##" before __VA_ARGS__ is a GCC extension.
Try to limit its usage where necessary.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-08-10 09:55:27 +01:00
Frediano Ziglio
ca1016eb15 backtrace: Do not attempt to compile if spice_backtrace is empty
In backtrace.h spice_backtrace is defined as:

  #if defined(WIN32) && !defined(__MINGW32__)
  #define spice_backtrace()
  #else
  ..

so don't try to compile if an empty macro is used.
Currently not causing any issue as we use MingW on Windows but
does not hurt is code is more portable.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-08-10 09:55:10 +01:00
Haochen Tong
8e0e13881e marshal: fix clang "missing field initializer" warning on generated files
Signed-off-by: Haochen Tong <i@hexchain.org>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2020-07-11 08:17:20 +01:00
Haochen Tong
bca74fb6c9 pixman_utils: fix clang "unused functions" warning
Signed-off-by: Haochen Tong <i@hexchain.org>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2020-07-11 08:17:18 +01:00
Frediano Ziglio
35be203f42 snd_codec: Use better type for snd_codec_create mode
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Julien Ropé <jrope@gmail.com>
2020-07-07 13:09:38 +01:00
Frediano Ziglio
283d82b0a3 snd_codec: Use better type for function result
Instead of just plain preprocessor macros use an enum.
This is more type safe and could produce better debugging
type information.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Julien Ropé <jrope@gmail.com>
2020-07-07 13:09:36 +01:00
Frediano Ziglio
8d9a79dd7d snd_codec: Use better types for snd_codec_is_capable
mode should be an enumeration value of SpiceAudioDataMode.
Return type is just a boolean.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Julien Ropé <jrope@gmail.com>
2020-07-07 13:09:14 +01:00
Frediano Ziglio
a95ba61d32 build: Remove -Werror from Meson build
In Meson better to use --werror option instead to manually add to
options.
Also this prevents build if spice-protocol deprecate some stuff
or fails the build if any warning occur.
This fixes an issue for
https://gitlab.freedesktop.org/spice/spice/-/issues/44.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Julien Ropé <jrope@gmail.com>
2020-07-03 10:42:14 +01:00
Frediano Ziglio
ba7af04f65 rect: Avoid usage of "small"
Some Windows headers define "small" causing issues.
Use "small_rect" instead. For coherence use "big_rect" instead of
"big".

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-06-25 16:17:39 +01:00
Frediano Ziglio
5d8feeb19a Reuse macros from spice-protocol
Reuse SPICE_GNUC_NORETURN and SPICE_GNUC_PRINTF

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Julien Ropé <jrope@gmail.com>
2020-06-19 14:45:36 +01:00
Frediano Ziglio
a5ee3cbac5 test-quic: Different "more_space" function for decode and encode
The "more_space" callback is used in both decode and encode path to provide
either more space to read or more space to write.
The current implementation was dealing only to provide more space to write
(that is encoding) crashing in case it was used for decoding.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-05-23 10:48:28 +01:00
Frediano Ziglio
8d969b66ed test-quic: Test fixed images
QUIC uses different methods to reduce image size.
One uses RLE on pixels. Using fixed images allows to better
test these paths increase code coverage.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2020-05-06 12:22:09 +01:00
Frediano Ziglio
5b93090e60 test-utils: Add missing include file
In some environment memset was not declared.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-05-06 12:21:10 +01:00
Frediano Ziglio
c00a152e00 build: Remove dependencies to libgthread
libgthread was needed to call g_thread_init.
This was removed by this commit:

    commit 3e116a6c71
    Date:   Wed Feb 6 13:32:09 2019 +0000

        Obsolete Glib cleanup

        We require at least GLib 2.38, remove code and check to
        support earlier versions.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2020-04-29 15:27:20 +01:00
Frediano Ziglio
7a84f60267 build: Remove dependency to gio2 from common and server libraries
The dependency is required only for client part.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
2020-04-26 16:50:00 +01:00
Frediano Ziglio
4c6b360f6b canvas_base: Remove canvas_draw_blend/canvas_draw_copy duplication
The 2 functions are exactly the same.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2020-04-24 17:18:52 +01:00
Frediano Ziglio
3caedf3bc2 canvas_base: Rename blend to copy for canvas_draw_blend argument
SpiceCopy and SpiceBlend are typedefs of the same structure.
This to prove that canvas_draw_blend and canvas_draw_copy do
exactly the same thing.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2020-04-24 17:18:50 +01:00
Frediano Ziglio
a971c59166 canvas_base: Format canvas_draw_blend similarly to canvas_draw_copy
Just minor style changes.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2020-04-24 17:18:45 +01:00
Frediano Ziglio
05c0c26839 agent: Fix incompatibility with Visual Studio compiler
Flexible arrays cannot have other fields following, even
if the fields are from a containing structure.
To fix this use an union and put the additional field inside
other structure in the union.
The final layout is the same but the compiler is not complaining.
This works on both GCC and Visual Studio.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-04-24 09:42:46 +01:00
Frediano Ziglio
bb03ff099b Add helper code for agent messages
Add agent.h and agent.c to deal with some common agent job:
- checking message from network and fixing network order.
- send back file transfer status.

Code based on Linux agent and Windows agent.
AgentXxxx and agent_xxx are used to avoid conflicts with protocol.

See agent.h for more detail on how to use these APIs.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-04-24 09:42:46 +01:00
Frediano Ziglio
8470ef9df2 helper-fuzzer-demarshallers: Add an helper for fuzzy testing demarshallers code
See usage with AFL in the source file initial comment.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-04-09 09:11:04 +01:00
Frediano Ziglio
402bc6b237 build: Allows to request a greater SPICE protocol version
Containing project can request a greater SPICE protocol version.
This will be taken into account while checking our requirements.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2020-04-08 14:28:40 +01:00
Frediano Ziglio
47e149705a proto: Generate correct constants for smartcard support
Of all SPICE_MSGC_SMARTCARD_xxx constants only SPICE_MSGC_SMARTCARD_DATA
is used by both spice-gtk and spice-server.
Generate the right constant, all obsolete ones will not be generated.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2020-04-07 11:07:33 +01:00
Frediano Ziglio
81f0331469 messages: Remove obsolete structure definition
This structure is not used by both spice-gtk and spice-server.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2020-04-07 11:07:23 +01:00
Frediano Ziglio
61ce54ef6c proto: Allows to specify @deprecated option for flags and enums
We want to obsolete from enumeration values, currently CELT.
The removal of check in has_attr is not an issue, as the attributes
are already checked by fix_attributes calls.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2020-04-07 10:22:33 +01:00
Frediano Ziglio
713a3e09fb build: Allow to build disabling code generation
Reduce dependencies if used by agents which do not need
marshallers/demarshallers code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-04-03 14:31:26 +01:00
Kevin Pouget
8f9eb611f8 spice.proto: add quality_indicator messages
These messages are used to exchange Streaming Quality messages between
SPICE client and SPICE server:

- `SPICE_MSGC_MAIN_QUALITY_INDICATOR`: a client->server message on the
  Main channel. This message is used by the client to share streaming
  quality observation with the server and the adaptive streaming
  control center. The format of the string message is not specified
  yet, it will depend of the sender/receiver final implementation.

- `SPICE_MSG_DISPLAY_QUALITY_INDICATOR`: a server->client message on
  the Display channel. This message is used to inform the client about
  adaptive-streaming specific details. The client should use it to
  configure its quality-message generation algorithms. The format of
  the string message is not specified yet, it will depend of the
  sender/receiver final implementation.

As an example, a `SPICE_MSG_DISPLAY_QUALITY_INDICATOR` message can
inform the client about the requested framerate (say, 60 FPS); and the
client will send a `SPICE_MSGC_MAIN_QUALITY_INDICATOR` warning message
when the measured framerate drops below 45 FPS.

Signed-off-by: Kevin Pouget <kpouget@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2020-04-02 13:32:04 +01:00
Frediano Ziglio
911a7aa9c6 ci: Use spice-protocol master for make-win job
All other projects just use master version of spice-protocol.
Do this also on Windows to use the last sources, it could happen
that we need them and not last packaged version.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-03-22 10:32:22 +00:00
Frediano Ziglio
6a64d86d1d test-logging: Do not use G_PASTE to join level
"level" can have value "DEBUG". In some environment "DEBUG" is
used as preprocessor name to enable some debugging code.
Using -DDEBUG option (or similar) cause "DEBUG" to be defined as "1"
so "G_PASTE(G_LOG_LEVEL_, level)" will be expanded to "G_LOG_LEVEL_1"
instead of "G_LOG_LEVEL_DEBUG".
Just concatenate the two literal to avoid "DEBUG" expansion.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2020-03-19 14:47:08 +00:00
Frediano Ziglio
365d7019d5 lz_common: Remove unused commented out define
The DEBUG macro is not used in lz code (or even spice-common).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-03-17 17:08:17 +00:00
Frediano Ziglio
35a9debe93 ci: Fix build of spice-protocol
spice-protocol is not using Autoconf anymore.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2020-03-17 17:07:29 +00:00
Victor Toso
31a14b20d0 sound: remove celt support
Follow up of spice-protocol's deprecation of celt mode.
See: https://gitlab.freedesktop.org/spice/spice-protocol/-/merge_requests/15

Signed-off-by: Victor Toso <victortoso@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2020-03-17 16:38:10 +00:00
Frediano Ziglio
11009d1b64 build: Use warning_level option for Meson
warning_level 2 setting for Meson add the same "-Wall -Wextra"
options to GCC compiler.
This removes a warning using Meson.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2020-03-12 12:48:39 +00:00
Frediano Ziglio
a3ec7c173d test-utils: Add a test for some utils.h functions
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Kevin Pouget <kpouget@redhat.com>
2020-03-05 18:38:12 +00:00
Kevin Pouget
ec4e44200a utils: add set_bitmap/test_bitmap functions
This patch introduces `set_bitmap` and `test_bitmap` + relevant
macros, adapted from `<qemu>/include/qemu/bitops.h`.

These functions differ from `set_bit`/`test_bit` as they can set/test
bits in bit arrays longer than scalar data-types.

Signed-off-by: Kevin Pouget <kpouget@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2020-03-04 16:43:48 +00:00
Frediano Ziglio
b2f919f109 Add missing dependency in Autoconf integration
spice-common depends on Glib2, so automatically add to the
dependency list.
You can define a GLIB2_MIN_VER m4 variable in configure.ac
to raise the default GLib2 required version.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Kevin Pouget <kpouget@redhat.com>
2020-03-04 09:58:42 +00:00
Frediano Ziglio
19ea60416c m4: Make easier to integrate in other projects
Add a common.m4 file to be included directly in other project.
This include will include all needed checks to use spice-common.
Just include directly this file in your configure.ac.
This will define SPICE_COMMON_CFLAGS and SPICE_COMMON_DIR (for
linking .la files) which are needed to use spice-common.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Kevin Pouget <kpouget@redhat.com>
2020-03-02 13:54:12 +00:00
Frediano Ziglio
2cec5f99af test-quic: Run 1 random quic test per color mode
Reduce execution time. No need to run so much tests, coverage
stays more or less the same.
We iterate twice to check RGB mode with alpha, otherwise the
coverage reduce about 10-20%.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <marcandre.lureau@gmail.com>
2020-03-02 09:57:56 +00:00
Frediano Ziglio
27fd63ff72 test-quic: Reduce height of test image
There's no much need for than size to be so big, limit to
reduce execution time, coverage stays more or less the same.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <marcandre.lureau@gmail.com>
2020-03-02 09:57:54 +00:00
Frediano Ziglio
df66d9a151 test-quic: Cache gdk_pixbuf_get_byte_length value
Do not call the function for every iteration

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <marcandre.lureau@gmail.com>
2020-03-02 09:57:50 +00:00
Frediano Ziglio
8e82bf5661 test-quic: Avoid namespace conflict with Gdk API
Avoid possible conflict in the future.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <marcandre.lureau@gmail.com>
2020-03-02 09:57:44 +00:00
Eduardo Lima (Etrunko)
03e1fb94e4 build: Unconditionally link with libm if found
New versions of gcc have implemented __has_builtin which causes meson
to detect functions in libm, such as hypot() and sqrt() as built-ins
during configure time, while they are actually part of libm. This has
been causing build failures in Fedora 32 Rawhide and has been reported
in meson for some time now: https://github.com/mesonbuild/meson/issues/3740

Meson always adds --as-needed to linker arguments so, it does not hurt
to link against libm even though no functions from that library will be
used.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2020-02-27 14:41:20 +00:00
Frediano Ziglio
35f45282d4 snd_codec: Update field names in function documentation
in_data field was renamed to in_ptr.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Julien Rope <jrope@redhat.com>
2020-02-07 17:07:57 +00:00
Frediano Ziglio
b699221f00 codegen: Check unsafe values alone
This rule remove possible integer overflows.
Current code generated is not affected by these integer overflows
as the computations are done using 64 bit but better safe then sorry.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Julien Rope <jrope@redhat.com>
2020-02-07 16:14:53 +00:00
Frediano Ziglio
ea864c70d9 lz_compress: Cleanup unused macros
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 15:27:03 +00:00
Frediano Ziglio
d5d1d5b0bf lz_decompress: Read "ctrl" inside loop
Remove code duplication

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 15:27:00 +00:00
Frediano Ziglio
a446b5b27b lz_decompress: Move variable declaration in nested scope
No need to compute these variable always, only if we have
a reference to a previous sequence.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 15:26:58 +00:00
Frediano Ziglio
08fafdbb33 lz_decompress: Reindented comment
Just space changes

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 15:26:56 +00:00
Frediano Ziglio
6595de58a2 lz_decompress: Simplify loop
The loop is always executed once so use a do {} while construct
to avoid the repetition.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 15:26:53 +00:00
Frediano Ziglio
109f6a4802 lz_decompress: Do not execute nested checks
Boundaries checks already done some lines above, no needs
to repeat for each pixel.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 15:26:51 +00:00
Frediano Ziglio
ac4763bd89 lz_decompress: Constify some variable
Make clear they are not supposed to be changed.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 15:26:34 +00:00
Frediano Ziglio
48944f6f41 marshallers: Avoid some useless pointers in SpiceMarshallerData
"buffers" and "marshallers" are always pointing to the static
buffers inside the same structure.
Use single array fields to avoid having initialize and have them.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Julien Rope <jrope@redhat.com>
2020-02-07 14:52:29 +00:00
Frediano Ziglio
87e2db9798 Reuse new spice_extra_assert macro
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 13:26:00 +00:00
Frediano Ziglio
e761c2d4de log: Add spice_extra_assert
This macro was suggested to simplify hot path expensive checks
which should be disable in production environments.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Francesco Giudici <fgiudici@redhat.com>
2020-02-07 13:24:45 +00:00
Frediano Ziglio
151c23d235 test-quic: Convert image to get more testing (gray, rgb16)
Allows to check QUIC algorithm and code with multiple input/output
formats.
Was limited to just RGB and RGBA.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-02-07 10:59:18 +00:00
Frediano Ziglio
26d3f6e138 build: Clean up some configure checks
Remove some system checks.
Specifically:
- functions in the standard C (memset, memmove);
- functions we use but we assume in the specific implementation
  present (dup2, fork);
- functions we don't use (error_at_line);
- headers in the standard C (stddef.h, stdint.h, string.h);
- headers present in all systems we support if are not checked
  in the source files (malloc.h);
- types we assume being present (XintYY_t, pid_t).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-02-06 19:26:21 +00:00
Frediano Ziglio
f3d6c5f322 snd_codec: Do not include not needed headers
Include headers required for implementation only in the
implementation file.
This remove dependency and avoid the user component having to
check for header flags (in this case HAVE_CELT051 and HAVE_OPUS).
This make easier integration in other components.
This also make compilation faster.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2020-02-06 19:26:21 +00:00
Frediano Ziglio
da6a405f25 snd_codec: Avoid some useless casts declaring struct type
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2019-12-15 21:24:27 +00:00
Frediano Ziglio
2561f62283 quic: Do not include quic_config.h in quic.h
quic_config is used only by the implementation so include it
only from the implementation file.
This remove dependency.
This make easier integration in other components.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2019-12-10 08:22:02 +00:00
Frediano Ziglio
34807c600c quic: Use G_UNLIKELY in some hot paths
The buffers provided should be big enough to avoid to ask
for more space much often.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2019-12-10 08:13:11 +00:00
Frediano Ziglio
5a31a3850d quic: Remove unused include header
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2019-11-26 13:38:07 +00:00
Fabrice Fontaine
785ac8de4f meson: add tests option
Allow the user to disable tests through -Dtests=false

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-11-18 11:07:59 +00:00
Fabrice Fontaine
32beff2ff5 configure.ac: add --enable-tests
Allow the user to disable tests through --disable-tests, this is
especially useful for example to disable gdk-pixbuf dependency

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-11-18 11:07:56 +00:00
Frediano Ziglio
ead7790d47 codegen: Ignore path generating include guards
Make sure that guard do no change building out-of-tree or
with Meson.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2019-11-04 11:08:10 +00:00
Kevin Pouget
f191053a8c build: Introduce the agent-interface as an alternative instrumentation library
The agent-interface is an experimental instrumentation library for
capturing and sharing Spice performance indicators with an external
agent.

    --enable-instrumentation=[recorder/agent/no]
             Enable instrumentation [default=no]

The former configuration option '--enable-recorder' is transformed
into '--enable-instrumentation=recorder'.

Signed-off-by: Kevin Pouget <kpouget@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-10-18 17:04:09 +01:00
Kevin Pouget
3331ad1a04 agent-interface: add configuration functions
agent_interface_start: this function allows launching the agent
interface (ie, its listening socket) on a given port.

agent_interface_set_on_connect_cb: this function allows passing a
callback function that will be triggered when a client (a Local Agent)
connects to the Agent Interface socket.

agent_interface_set_forward_quality_cb: this function allows SPICE to
provide a function that will forward Quality messages received by the
Agent Interface towards SPICE server, for a centralized processing of
the messages.

Signed-off-by: Kevin Pouget <kpouget@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-10-18 17:04:06 +01:00
Kevin Pouget
a16c7027c5 agent-interface: introduce the core of the Agent Interface
When initialized (recorder_initialization), the Agent Interface launch
a GThread (handle_communications) that opens a TCP server socket and
waits for Smart Local Agent connections. When a Local Agent connects
to the sockets, the communication is initialized
(agent_initialize_communication), the communication socket is stored
and the list of Recorders is sent. In return, the local agent
indicates which recorders to enable.

On the SPICE side, the Agent Interface handles the record() calls
(recorder_append*). When a record is received from SPICE, and if the
recorder is enabled, the record entry is sent through the TCP
connection. Otherwise, the record is dropped.

Signed-off-by: Kevin Pouget <kpouget@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-10-18 17:04:03 +01:00
Frediano Ziglio
99f6aa0028 codegen: Document "chunk" attribute
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-10-10 13:01:33 +01:00
Frediano Ziglio
d4248885e8 codegen: Check validity of array members
Check that combination of fields for an array does not
lead to unsafe code.
check_valid method came from generate_c_declaration with
some more check and it's use in demarshaller to validate
the array if the structure is not generated.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-10-10 12:33:42 +01:00
Frediano Ziglio
a5a86a1caf codegen: Add 'chunk' to the output attributes
Output attributes are the attributes that specify how to store
that field in the C structure.
There can be only one output type specified.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-10-10 11:11:36 +01:00
Frediano Ziglio
62b44b3073 proto: Demarshal Smartcard data field
Currently the demarshaler code is not used by spice-server.
Demarshal all the fields of the header message, not only the header.
Using generated code allows to easily check data and support
big endian machines. Generated code will be used by spice-server.

The resulting change is.

   diff -ru gen/generated_client_marshallers.c common/generated_client_marshallers.c
    --- gen/generated_client_marshallers.c      2019-10-05 20:44:54.000000000 +0100
    +++ common/generated_client_marshallers.c   2019-10-05 20:45:33.000000000 +0100
    @@ -283,6 +283,7 @@
         spice_marshaller_add_uint32(m, src->type);
         spice_marshaller_add_uint32(m, src->reader_id);
         spice_marshaller_add_uint32(m, src->length);
    +    /* Don't marshall @nomarshal data */
     }

     #endif /* USE_SMARTCARD */
    diff -ru gen/generated_server_demarshallers.c common/generated_server_demarshallers.c
    --- gen/generated_server_demarshallers.c    2019-10-05 20:44:54.000000000 +0100
    +++ common/generated_server_demarshallers.c 2019-10-05 20:45:33.000000000 +0100
    @@ -1451,10 +1451,25 @@
         uint64_t nw_size;
         uint64_t mem_size;
         uint8_t *in, *end;
    +    uint64_t data__nw_size, data__mem_size;
    +    uint64_t data__nelements;
         VSCMsgHeader *out;

    -    nw_size = 12;
    -    mem_size = sizeof(VSCMsgHeader);
    +    { /* data */
    +        uint32_t length__value;
    +        pos = start + 8;
    +        if (SPICE_UNLIKELY(pos + 4 > message_end)) {
    +            goto error;
    +        }
    +        length__value = read_uint32(pos);
    +        data__nelements = length__value;
    +
    +        data__nw_size = data__nelements;
    +        data__mem_size = sizeof(uint8_t) * data__nelements;
    +    }
    +
    +    nw_size = 12 + data__nw_size;
    +    mem_size = sizeof(VSCMsgHeader) + data__mem_size;

         /* Check if message fits in reported side */
         if (nw_size > (uintptr_t) (message_end - start)) {
    @@ -1474,6 +1489,10 @@
         out->type = consume_uint32(&in);
         out->reader_id = consume_uint32(&in);
         out->length = consume_uint32(&in);
    +    verify(sizeof(out->data) == 0);
    +    memcpy(out->data, in, data__nelements);
    +    in += data__nelements;
    +    end += data__nelements;

         assert(in <= message_end);
         assert(end <= data + mem_size);

The @nomarshal attribute allows to not change the marshaling code
(used by spice-gtk).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-10-08 14:40:32 +01:00
Kevin Pouget
2640ff294a common/recorder.h: do not complain on unused (dummy) recorders
Signed-off-by: Kevin Pouget <kpouget@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-09-11 10:02:44 +01:00
Frediano Ziglio
4727c19d36 meson: Remove "install" argument from configure_file
The argument requires Meson 0.50 however it's already "false"
by default if "install_dir" is not provided so remove it
to keep compatibility with Meson 0.48.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2019-08-29 04:51:48 +01:00
Frediano Ziglio
c392a7fee7 codegen: Add a check for C structure fields
This check make sure that output fields for member with @end (arrays)
are declared as empty arrays in output C structure.
This avoids output fields to be declared as pointer or other
invalid types.
The check is a compile time check so no code in object file
is generated.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2019-08-14 15:49:19 +01:00
Frediano Ziglio
493475e012 protocol: Removed unneeded type specifications
Default type is already uint8_t.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2019-08-14 10:32:08 +01:00
Frediano Ziglio
60e0453698 codegen: Exit with error on error generating C structures
This was some left-over during development of C structure
generations (the single structure generation was skipped).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2019-08-13 18:11:04 +01:00
Frediano Ziglio
7abd2b36d9 codegen: Use has_end_attr instead of has_attr("end")
Just style, they do the same thing, but is more coherent
with the rest of the code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2019-08-13 18:10:56 +01:00
Uri Lublin
01417b7533 test-marshallers.proto: ArrayMessage: make space for name
Do it by adding @end tag.
Without it the allocated memory has no space for 'name'.

Also fix SpiceMsgMainArrayMessage tests/test-marshallers.h,
replacing int8_t* name with int8_t name[0].
This makes name an "in-structure" array with no pre-defined size
instead of a pointer.
The size is defined by the message size.

Signed-off-by: Uri Lublin <uril@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-08-13 18:09:05 +01:00
Uri Lublin
a52a0a0906 ptypes.py: remove useless condition member != None
member = None is set before the if/else condition.
In the else code, when member is set it is checked
and if not-None it breaks out of the loop.
If the code is still in the loop for sure member is None.

Found by covscan.

Signed-off-by: Uri Lublin <uril@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-08-12 17:00:42 +01:00
Frediano Ziglio
ff2e99d893 build: Disable Celt support by default
We started disabling Celt support making the option required.
After 2 releases start making it disabled unless explicitly
enabled.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Snir Sheriber <ssheribe@redhat.com>
2019-06-13 08:51:11 +01:00
Frediano Ziglio
cc109a83b6 recorder: Update
Pull version update and some features.
Version update changed copyright in files to LGPLv2, more
compatible with SPICE.
One of the feature is the support for absolute time.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2019-05-29 14:53:16 +01:00
Frediano Ziglio
3b517a2243 build: Remove unused git-version-gen file
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2019-05-29 14:53:12 +01:00
Frediano Ziglio
4fc4c2db36 Do not check for HAVE_CONFIG_H
This should always be defined and including config.h is a requirement.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-05-02 09:33:05 +01:00
Frediano Ziglio
09fba0677d gitignore: Ignore auto generated generated_messages.h file
git.mk seems to have issues with Makefile rules generating multiple
files so add manually this file.
This avoid SPICE server to generate distribution files with
"-dirty" suffix.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-04-30 11:31:20 +01:00
Uri Lublin
5bcfa711d9 codegen Makefile: add common/ to --include client_marshallers.h
Fixes out-of-tree builds.

For example spice-gtk out-of-tree build fails with:
  ../subprojects/spice-common/common/generated_client_marshallers.h:19:10:
      fatal error: client_marshallers.h: No such file or directory
   #include "client_marshallers.h"
            ^~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Uri Lublin <uril@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-04-23 08:39:34 +01:00
Eduardo Lima (Etrunko)
47ba8e0f25 meson: Make targets list store dictionaries instead of lists
Access the items by names instead of indexes.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-04-04 18:07:32 +01:00
Frediano Ziglio
bfebdc5eb4 meson: Do not build generated files twice
spice-gtk and spice-server will use spice_common_client_dep
and spice_common_server_dep as dependencies.
However they will depend on both spice-common client/server
libraries and their sources causing the sources to be compiled
multiple times and causes linker errors on spice-gtk.
The issue can be observed doing a "find -name \*generated\*.o"
in Meson build directory.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-04-04 18:07:28 +01:00
Frediano Ziglio
f236c1ef94 meson: Fix dependency of generated files
All generated file depends on generated_messages.h which is
generated too.
So add an explicit dependency from all generated file
(except generated_messages.h generator) to generated_messages.h
generator.
This fixes compiling SPICE server where generated_messages.h
was not generated at all.
Add dependency to the include header to make Meson generate the
proper include flag.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-04-04 18:07:24 +01:00
Frediano Ziglio
21edc8611d proto: Fix typo in message name
RecoderChannel::data message is the same as PlaybackChannel::data
one.
This fixed compilation of spice-gtk using updated spice-common.

Before generating the messages automatically the definition was:

  typedef struct SpiceMsgPlaybackPacket {
      uint32_t time;
      uint8_t *data;
      uint32_t data_size;
  } SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;

so both messages were defined as struct SpiceMsgPlaybackPacket with
SpiceMsgcRecordPacket an alias to it.

But spice.proto for RecordChannel::data was changed from
SpiceMsgcRecordPacket (the alias) to SpiceMsgcPlaybackPacket
defining a new structure and breaking the alias.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-04-03 10:00:42 +01:00
Frediano Ziglio
b628730115 build: Add new check for recorder library
Newer version try to use this function if available.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-04-03 09:32:46 +01:00
Christophe Fergeau
4951c71553 log: Let gcc know about the logging macros which abort
This commit adds a SPICE_UNREACHABLE macro (courtesy of Frediano)
so that gcc does not think that code control can go past
spice_return_{val_,}if_fail(), spice_critical() and spice_error()

This avoids this kind of warnings:

fallthrough.c:

 #include "log.h"

int main(int argc, char **argv)
{
    switch(argc) {
        case 1:
            spice_critical("foo");
       default:
            return 0;
    }
}

$ gcc  -c    $(pkg-config --cflags --libs glib-2.0 spice-protocol)
       -I common   -Wimplicit-fallthrough=5 ./fallthrough.c
In file included from ./fallthrough.c:1:
./fallthrough.c: In function 'main':
common/log.h:73:5: warning: this statement may fall through [-Wimplicit-fallthrough=]
   73 |     spice_log(G_LOG_LEVEL_CRITICAL, SPICE_STRLOC, __FUNCTION__, "" format, ## __VA_ARGS__); \
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./fallthrough.c:8:25: note: in expansion of macro 'spice_critical'
    8 |                         spice_critical("foo");
      |                         ^~~~~~~~~~~~~~
./fallthrough.c:9:17: note: here
    9 |                 default:
      |                 ^~~~~~~

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-04-01 17:33:17 +01:00
Frediano Ziglio
bbb5163e61 recorder: Update
Pull some fixes and features.
One of the feature is the support for @output setting to redirect
log output.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2019-03-29 17:58:21 +00:00
Christophe Fergeau
1fbac71c84 quic: Fix QUIC_VERSION definition
QUIC_VERSION_MINOR is never used.. Set QUIC_VERSION_MINOR to the same
version as QUIC_VERSION_MAJOR to avoid breaking backwards compatibility,
and fix the QUIC_VERSION macro.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-03-29 16:58:20 +01:00
Christophe Fergeau
e123f94939 test-marshallers: Fix header guard
test-marshallers.h is missing a #define _H_TEST_MARSHALLERS in order to
prevent multiple #include for the same header.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-03-29 16:58:16 +01:00
Christophe Fergeau
a294cad01c build: Update verify.h to latest version
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-03-29 16:58:14 +01:00
Christophe Fergeau
5ef652b7e3 build: Add missing G_GNUC_PRINTF annotations
They were suggested by gcc when using -Wsuggest-attribute=format

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-03-29 16:58:07 +01:00
Christophe Fergeau
2f64e2edbb lz: Don't try to print uninitialized variable
encoder->type is only going to be set by lz_set_sizes() after the
error() call. We can use 'type' directly which is what encoder->type is
going to be set to.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-03-29 11:29:25 +01:00
Christophe Fergeau
187df0cfdb backtrace: Add missing include
This fixes a warning about missing prototype for backtrace()

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-03-29 11:29:25 +01:00
Christophe Fergeau
79a9fad3a2 canvas_base: Fix variable shadowing warning
canvas_base.c is #included by spice-common users. They currently don't
enable this warning, but if/when they do, we don't want code from
spice-common to trigger it.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-03-29 11:29:25 +01:00
Frediano Ziglio
bd75d3f934 Generate automatically most C message declarations
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-18 13:02:03 +00:00
Frediano Ziglio
5f1f369e41 Allow to generate C declarations for spice.proto
Generate and include C declarations.
Next patch will use this facility.
Since none of the spice.proto types are decorated with @declare,
adding the #include in messages.h won't have any bad consequences.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-18 13:02:01 +00:00
Frediano Ziglio
3cd3886b27 codegen: Allows to generate C declarations automatically
Allows to specify a @declare attribute for messages and structure
that can generate the needed C structures.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-18 13:01:58 +00:00
Frediano Ziglio
dac34baaab codegen: Generate headers while generating code
Python script generates code and header together however allowed
to save only one of them.
Allows to save both of them together to reduce number of time
we call Python script.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-18 13:01:52 +00:00
Frediano Ziglio
af66a4ccad codegen: Factor out a function to write output file
This will be reused to generate C declaration automatically.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-15 15:46:17 +00:00
Frediano Ziglio
81e2092fc7 meson: Remove some useless checks
Do not check for functions not used or available in C89 and earlier.
Autoconf check for them to support archaic systems.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2019-03-15 15:45:57 +00:00
Frediano Ziglio
387d1842d1 test-ssl-verify: Improve subject_to_x509_name coverage
Check that attempting to quote an invalid character result in
a error.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-13 17:22:18 +00:00
Frediano Ziglio
fce4486755 build: Remove snd_codec.h from EXTRA_DIST
The file is already distributed as included in the source list.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-13 10:58:28 +00:00
Frediano Ziglio
1cdc3cc3b0 ci: Remove dependencies from copr build
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Snir Sheriber <ssheribe@redhat.com>
2019-03-12 12:43:38 +00:00
Frediano Ziglio
cb00ccfaab codegen: Rename --prefix parameter to --suffix
The option is used to add a suffix to public functions, not a
prefix.
Currently the option is not used (it was used to generate protocol
1 code).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-08 21:22:58 +00:00
Frediano Ziglio
302e30ff43 codegen: Remove support for --ptrsize
This option was used in protocol 1 to generate 64 bit pointers.
A pointer in the protocol is an offset in the current message.
This allows the possibility to have messages with pointers with more
than 4GB. This feature was removed and not used in protocol 2.
The reason this feature was correctly removed in protocol 2 is that
having 64 bit pointers in the protocol would require messages larger
than 4GB which would cause:
- huge latency as a single message would take more than 4 seconds
  to be send in a 10Gb connection;
- huge memory requirements.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-08 11:09:02 +00:00
Frediano Ziglio
92d5dfd4bf messages: Remove fields not used by the protocol
These fields are not used by the protocol (not in spice.proto, nor
will be used in the generated (de)marshallers).
Avoid spice-gtk and spice-server to use them by mistake.
This can cause memory errors (data_size is not used or is not set
correctly) and useless code (spice-gtk uses the pub_key* fields but
these fields are not sent to the server as the protocol does not have
them).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-03-07 21:07:18 +00:00
Frediano Ziglio
db245ae740 protocol: Add a dummy TunnelChannel
The removal of the channel definition will cause the enumeration
to miss this old channel.
Add a dummy channel (empty) to avoid having to update spice-gtk
and spice-server and possibly breaking other software.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2019-03-05 23:19:53 +00:00
Frediano Ziglio
86136f9a95 proto: Remove obsolete TunnelChannel
No reason to keep it, spice-gtk and spice-server don't
implement it and was removed for security reasons.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <marcandre.lureau@gmail.com>
2019-02-22 12:03:18 +00:00
Marc-André Lureau
c5e7d92dc6 docs: add spice URI scheme
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-21 14:22:18 +00:00
Frediano Ziglio
e8c76358ee log: Remove useless includes
Now the function almost uses GLib function, no reason to include
some system headers.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-21 13:44:07 +00:00
Frediano Ziglio
4ccc20a7f6 mem: Fix compile error if alignment-checks option is used
Domain name argument to spice_log was removed time ago.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-21 13:44:07 +00:00
Frediano Ziglio
60883a0321 codegen: Add a test for attribute combination
Does not make sense to specify the same field to have 2
different C implementation at the same time.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-21 09:05:03 +00:00
Frediano Ziglio
a5de31bc8a codegen: Check wrong attribute
@ptr_array is supposed to change the destination to an array
of pointer to items. This for a raw buffer does not make sense
but check if user specifies this combination.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-20 17:45:29 +00:00
Frediano Ziglio
7462c171e1 codegen: Fix c_type result for TypeAlias
c_type() method is supposed to return the type to use for
C structure field. But the name is not a C type but a
protocol name.
Return the type name of the aliased type (for instance
uint32_t for a uint32 type).
This does not change the generated code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-20 17:42:59 +00:00
Frediano Ziglio
53c0c5a665 codegen: Reduce indentation
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-20 17:42:59 +00:00
Frediano Ziglio
7fa8bda275 codegen: Use a better type for pointer converted to integer
Although on the platform we support size_t and uintptr_t are
the same, on some platform the size_t can (in theory) be smaller
than the necessary integer to store a pointer.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-20 17:42:59 +00:00
Frediano Ziglio
7f6c55790b codegen: Document ptr_array attribute
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-20 17:39:27 +00:00
Eduardo Lima (Etrunko)
02530a80df meson: Bump requirement to 0.48
This version is already required by spice-gtk and is soon to be required
by spice-server as well, so there is no much sense in keeping it for
spice-common.

It is necessary to update the usage of the python module as described in
the documentation:

https://mesonbuild.com/Release-notes-for-0-48-0.html#python3-module-is-deprecated

Which gets rid of the following warning message:

WARNING: Deprecated features used:
 * 0.48.0: {'python3 module'}

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-02-13 14:42:04 -02:00
Eduardo Lima (Etrunko)
811fff0791 meson: switch smartcard option to auto feature
In spice-gtk commit dbdf692909f7a2b272b06a674a38a1aeb4303032, the
smartcard option has been changed from boolean to feature, which
actually broke the option yeld, because the option type is incompatible
between superproject and subproject.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2019-02-13 14:20:03 -02:00
Eduardo Lima (Etrunko)
413da761ec meson: Bump libcacard requirement to 2.5.1
Commit 924f47 did this for autotools, do the same for meson.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-02-11 12:40:02 -02:00
Frediano Ziglio
3e116a6c71 Obsolete Glib cleanup
We require at least GLib 2.38, remove code and check to
support earlier versions.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2019-02-06 14:24:03 +00:00
Frediano Ziglio
e3af47fe9d log: remove deprecated SPICE_DEBUG_LEVEL support
This feature was marked obsolete by efd1d3cb4d more than
three years ago.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-06 13:21:00 +00:00
Frediano Ziglio
ea20b8c013 log: remove deprecated SPICE_ABORT_LEVEL support
This feature was marked obsolete by efd1d3cb4d more than
three years ago.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-02-06 13:19:47 +00:00
Eduardo Lima (Etrunko)
e307130c18 meson: Use underscorify() instead of split()
Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2019-02-01 14:40:47 -02:00
Frediano Ziglio
9ca8914b7c Remove obsolete Autoconf macros
Autoconf 2.63 was released on September 2008.
These simple macros conflict with system ones and can
causes issues with some systems (currently MacOS).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-01-30 13:14:40 +00:00
Frediano Ziglio
2e914f3305 Integrate recorder library
Allow to use recorder library. See https://github.com/c3d/recorder for
details.
The main usage will be to collect statistics while the programs will run.
By default the recorder will be disabled at compile time. The idea of the
usage in SPICE is to collect data while the program run. Using current
SPICE logging facility was discussed but not easy to filter data. Other
solutions (SystemTap, LTTng) were discarded due to not cross platform.
A printf based solution was discussed too but missing the additional tools
which are useful. Currently we don't plan to use as extensively as to be a
problem to be replaced or removed in the future.

Both Autoconf and Meson build systems are supported.
Autoconf requires the addition of SPICE_CHECK_RECORDER call in configure.ac.
Meson requires to add recorder option.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-01-23 14:44:19 +00:00
Marc-André Lureau
0a753b93b5 meson: fix building for big-endian host
autofoo build-sys defines WORDS_BIGENDIAN, and spice-common code uses it.

Later, I think it would make sense to switch to G_BIG_ENDIAN instead.

Fixes:
https://gitlab.freedesktop.org/spice/spice-common/issues/2

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2019-01-17 12:46:23 +04:00
Marc-André Lureau
6c09f943ce quic: fix sign-compare warning
../subprojects/spice-common/common/quic.c: In function 'fill_model_structures':
../subprojects/spice-common/common/quic.c:695:55: error: comparison of integer expressions of different signedness: 'int' and 'unsigned int' [-Werror=sign-compare]
     spice_assert(free_counter - family_stat->counters == nbuckets * ncounters);
                                                       ^~

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Frediano Ziglio <figlio@redhat.com>
2019-01-17 12:45:10 +04:00
Marc-André Lureau
57f2c61712 build-sys: improve asciidoc rules to allow multiple targets
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-01-15 17:35:58 +04:00
Marc-André Lureau
96700c849d Add a .gitpublish
That makes it easier to send patch series for spice-common.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2019-01-15 17:35:51 +04:00
Frediano Ziglio
5173ff871a lz: More checks on image sizes
Extend sizes check also to decoding, actually the source data
decoding images should be less safe than encoding.
This avoids different integer overflows and buffer overflows.
To avoid potential issues images are limited to 1GB.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-01-08 21:27:45 +00:00
Frediano Ziglio
3050b4e1f6 lz: Avoid buffer reading overflow checking for image type
The type of the image is just copied from network without
any check and later used for array indexing.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2019-01-08 21:27:45 +00:00
Frediano Ziglio
16aa8c98d8 test: Add a test for subject_to_x509_name function
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-01-08 21:26:58 +00:00
Frediano Ziglio
3e6dedaa51 marshaller: Provide spice_marshaller_fill_iovec for Windows
An array of WSABUF can be used with WSASend.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-01-08 13:05:20 +00:00
Marc-André Lureau
924f47a653 Bump libcacard requirement to 2.5.1
v2.5.1 was released on 2015-11-24.

According to repology, from the distro we care about, CentOS 6,
openSUSE Leap 42.3 have too old version (0.1.2).

spice-gtk & spice-server will have to be updated to drop
USE_SMARTCARD_012.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Christophe Fergeau <cfergeau@redhat.com>
2019-01-08 13:12:55 +04:00
Frediano Ziglio
6dc745e877 log: Use proper format attribute for spice_log
SPICE_ATTR_PRINTF uses __printf__ format attribute.
spice_log internally uses g_string_append_vprintf which uses
G_GNUC_PRINTF attribute.
G_GNUC_PRINTF can be __printf__ or gnu_printf format which in
some systems (currently Windows) can be different.
GLib 2.58 changed G_GNUC_PRINTF on Windows from using __printf__
attribute to gnu_printf.
To avoid problems in the future uses G_GNUC_PRINTF instead of
SPICE_ATTR_PRINTF for spice_log.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2019-01-02 14:00:23 +00:00
Frediano Ziglio
2d32025f77 Use a single copy of subject string
A full copy can keep both the key and the value instead of allocating
twice the memory.
We are parsing key1=val1,key2=val2,... and in doing that, we currently
store 'key1' in key, and 'val1' in val, and then 'key2', 'val2', and so
on.
After this patch, we store 'key1\0val1\0' in key, which fits and saves
some memory.
Also this removes a warning produced by Coverity that is assuming that
allocating strlen(string_variable) is wrong.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-12-19 11:31:13 +00:00
Frediano Ziglio
7f4da3ff36 ci: Run tests on Windows using wine
As spice-common is used by spice-gtk which should run on Windows
even spice-common should compile and run on Windows so check it
with CI.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-12-17 12:18:48 +00:00
Frediano Ziglio
c01a4a6fc3 test-region: Add missing dependencies
The test uses both GLib and pixman libraries.
This does not seem to affect Linux but make the test fails under Windows.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-12-17 12:18:48 +00:00
Frediano Ziglio
a45f656aac test-marshaller: Make main declaration easier
Declare without argument instead of long declaration.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-12-17 09:54:56 +00:00
Frediano Ziglio
ac8d27104b test-marshaller: Make test_overflow static
Not used outside the test.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-12-17 09:52:29 +00:00
Frediano Ziglio
a4aad511f1 Update --enable-celt051 help string
Use AS_HELP_STRING in order to fix indentation of configure --help.
Default is now auto, as the "[enable_celt051="auto"]" parameter.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-12-12 16:27:18 +00:00
Jonathon Jongsma
bb55f06a51 Fix some additional typos
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-11-28 07:57:31 +00:00
Frediano Ziglio
125cfa7fb2 Unify headers guard names
Always use H_SPICE_COMMON_ prefix with uppercase filename (without
extension).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com
2018-11-26 11:20:57 +00:00
Christophe Fergeau
6077523a5f utils: Add genum -> string helpers
This makes it easier to convert enums registered with glib type system
to string in order to print them at runtime.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-11-23 10:25:01 +00:00
Frediano Ziglio
aee2b91fe2 docs: Document to_ptr protocol attribute
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Snir Sheriber <ssheribe@redhat.com>
2018-11-21 17:28:30 +00:00
Frediano Ziglio
5b6878e72c docs: Fix typos and grammar
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Snir Sheriber <ssheribe@redhat.com>
2018-11-21 17:27:54 +00:00
Frediano Ziglio
2060672e81 Create common header for demarshallers declarations
Code generated for demarshallers define and declare some types and
functions.
However these types and functions are also declared separately in other
headers (currently spice-common/client_demarshallers.h and
spice/server/demarshallers.h) resulting in potential ABI mismatch if the
different declarations do not match.
Using a common header shared between generated code and code using
these functions prevent potentially multiple different declarations.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-10-15 13:31:16 +01:00
Frediano Ziglio
87493929b4 client_demarshallers: Remove SPICE protocol 1 declaration
spice_get_server_channel_parser1 function was removed.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-10-15 10:58:38 +01:00
Frediano Ziglio
ddfb8807c6 codegen: Remove minor attribute
The idea in version 1 of the protocol was to extend it using the minor
version. However this was replaced by the usage of capabilities and the
minor attribute (which was not much used in version 1) was abandoned in
version 2.
This patch create a big difference in the code generated but only because
the minor version was passed between all possible functions as argument.
Note that exported functions retain the minor argument for compatibility
reasons.
The demarshaller code export directly spice_get_client_channel_parser or
spice_get_server_channel_parser functions which returns internal module
functions which parse message of specific channels.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-10-15 10:58:38 +01:00
Frediano Ziglio
8a68e67afa codegen: Remove fixedsize attribute
This attribute was used only in SPICE version 1.
The intention was use fixed size for switch type in the protocol.
However this does not bring any improvement, just increase network
bytes used.
Generated code does not change.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-10-15 10:58:38 +01:00
Frediano Ziglio
979717350d codegen: Remove bytes_count attribute
This attribute was used only in SPICE version 1.
Its usage was confusing, and was replaced by the simple usage of
array size.
Generated code does not change.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-10-15 10:58:38 +01:00
Christophe Fergeau
b9dca950fb Remove config.h from header files
This should only be included from c files.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-10-08 17:18:12 +02:00
Frediano Ziglio
7d16536672 proto: Remove support for SPICE version 1
SPICE version 2 was introduced more than 8 years ago.
RHEL 6 already removed support for version 1 in the server.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2018-09-28 09:00:03 +01:00
Frediano Ziglio
90f95c2f8c quic: Prevent side effects calling C macros
In some architectures GLib macros to change endianness use the
argument multiple times causing possible side effects.

This happens for instance using Debian SID and MIPS.

This fixes https://gitlab.freedesktop.org/spice/spice-common/issues/1.

Reported-by: Laurent Bigonville <bigon@debian.org>
Tested-by: Laurent Bigonville <bigon@debian.org>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2018-09-10 12:44:17 +02:00
Eduardo Lima (Etrunko)
6b93b3fce8 meson: Make use of compiler.get_supported_arguments()
This avoids adding an extra build flag which may not be supported by the
compiler.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-09-03 08:53:01 +01:00
Frediano Ziglio
bb15d4815a Fix flexible array buffer overflow
This is kind of a DoS, possibly flexible array in the protocol
causes the network size check to be ignored due to integer overflows.

The size of flexible array is computed as (message_end - position),
then this size is added to the number of bytes before the array and
this number is used to check if we overflow initial message.

An example is:

    message {
        uint32 dummy[2];
        uint8 data[] @end;
    } LenMessage;

which generated this (simplified remove useless code) code:

    { /* data */
        data__nelements = message_end - (start + 8);

        data__nw_size = data__nelements;
    }

    nw_size = 8 + data__nw_size;

    /* Check if message fits in reported side */
    if (nw_size > (uintptr_t) (message_end - start)) {
        return NULL;
    }

Following code:
- data__nelements == message_end - (start + 8)
- data__nw_size == data__nelements == message_end - (start + 8)
- nw_size == 8 + data__nw_size == 8 + message_end - (start + 8) ==
  8 + message_end - start - 8 == message_end -start
- the check for overflow is (nw_size > (message_end - start)) but
  nw_size == message_end - start so the check is doing
  ((message_end - start) > (message_end - start)) which is always false.

If message_end - start < 8 then data__nelements (number of element
on the array above) computation generate an integer underflow that
later create a buffer overflow.

Add a check to make sure that the array starts before the message ends
to avoid the overflow.

Difference is:
    diff -u save/generated_client_demarshallers1.c common/generated_client_demarshallers1.c
    --- save/generated_client_demarshallers1.c	2018-06-22 22:13:48.626793919 +0100
    +++ common/generated_client_demarshallers1.c	2018-06-22 22:14:03.408163291 +0100
    @@ -225,6 +225,9 @@
         uint64_t data__nelements;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 0) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 0);

             data__nw_size = data__nelements;
    @@ -243,6 +246,9 @@
         *free_message = nofree;
         return data;

    +   error:
    +    free(data);
    +    return NULL;
     }

     static uint8_t * parse_msg_set_ack(uint8_t *message_start, uint8_t *message_end, SPICE_GNUC_UNUSED int minor, size_t *size, message_destructor_t *free_message)
    @@ -301,6 +307,9 @@
         SpiceMsgPing *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 12) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 12);

             data__nw_size = data__nelements;
    @@ -5226,6 +5235,9 @@
             uint64_t cursor_data__nw_size;
             uint64_t cursor_data__nelements;
             { /* data */
    +            if (SPICE_UNLIKELY((start2 + 22) > message_end)) {
    +                goto error;
    +            }
                 cursor_data__nelements = message_end - (start2 + 22);

                 cursor_data__nw_size = cursor_data__nelements;
    @@ -5305,6 +5317,9 @@
             uint64_t cursor_data__nw_size;
             uint64_t cursor_data__nelements;
             { /* data */
    +            if (SPICE_UNLIKELY((start2 + 22) > message_end)) {
    +                goto error;
    +            }
                 cursor_data__nelements = message_end - (start2 + 22);

                 cursor_data__nw_size = cursor_data__nelements;
    @@ -5540,6 +5555,9 @@
         SpiceMsgPlaybackPacket *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 4) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 4);

             data__nw_size = data__nelements;
    @@ -5594,6 +5612,9 @@
         SpiceMsgPlaybackMode *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 8) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 8);

             data__nw_size = data__nelements;
    diff -u save/generated_client_demarshallers.c common/generated_client_demarshallers.c
    --- save/generated_client_demarshallers.c	2018-06-22 22:13:48.626793919 +0100
    +++ common/generated_client_demarshallers.c	2018-06-22 22:14:03.004153195 +0100
    @@ -225,6 +225,9 @@
         uint64_t data__nelements;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 0) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 0);

             data__nw_size = data__nelements;
    @@ -243,6 +246,9 @@
         *free_message = nofree;
         return data;

    +   error:
    +    free(data);
    +    return NULL;
     }

     static uint8_t * parse_msg_set_ack(uint8_t *message_start, uint8_t *message_end, SPICE_GNUC_UNUSED int minor, size_t *size, message_destructor_t *free_message)
    @@ -301,6 +307,9 @@
         SpiceMsgPing *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 12) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 12);

             data__nw_size = data__nelements;
    @@ -6574,6 +6583,9 @@
             }

             { /* data */
    +            if (SPICE_UNLIKELY((start2 + 2 + cursor_u__nw_size) > message_end)) {
    +                goto error;
    +            }
                 cursor_data__nelements = message_end - (start2 + 2 + cursor_u__nw_size);

                 cursor_data__nw_size = cursor_data__nelements;
    @@ -6670,6 +6682,9 @@
             }

             { /* data */
    +            if (SPICE_UNLIKELY((start2 + 2 + cursor_u__nw_size) > message_end)) {
    +                goto error;
    +            }
                 cursor_data__nelements = message_end - (start2 + 2 + cursor_u__nw_size);

                 cursor_data__nw_size = cursor_data__nelements;
    @@ -6907,6 +6922,9 @@
         SpiceMsgPlaybackPacket *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 4) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 4);

             data__nw_size = data__nelements;
    @@ -6961,6 +6979,9 @@
         SpiceMsgPlaybackMode *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 6) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 6);

             data__nw_size = data__nelements;
    @@ -7559,6 +7580,9 @@
         SpiceMsgTunnelSocketData *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 2) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 2);

             data__nw_size = data__nelements;
    @@ -7840,6 +7864,9 @@
         }

         { /* compressed_data */
    +        if (SPICE_UNLIKELY((start + 1 + u__nw_size) > message_end)) {
    +            goto error;
    +        }
             compressed_data__nelements = message_end - (start + 1 + u__nw_size);

             compressed_data__nw_size = compressed_data__nelements;
    diff -u save/generated_server_demarshallers.c common/generated_server_demarshallers.c
    --- save/generated_server_demarshallers.c	2018-06-22 22:13:48.627793944 +0100
    +++ common/generated_server_demarshallers.c	2018-06-22 22:14:05.231208847 +0100
    @@ -306,6 +306,9 @@
         uint64_t data__nelements;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 0) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 0);

             data__nw_size = data__nelements;
    @@ -324,6 +327,9 @@
         *free_message = nofree;
         return data;

    +   error:
    +    free(data);
    +    return NULL;
     }

     static uint8_t * parse_msgc_disconnecting(uint8_t *message_start, uint8_t *message_end, SPICE_GNUC_UNUSED int minor, size_t *size, message_destructor_t *free_message)
    @@ -1259,6 +1265,9 @@
         SpiceMsgcRecordPacket *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 4) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 4);

             data__nw_size = data__nelements;
    @@ -1313,6 +1322,9 @@
         SpiceMsgcRecordMode *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 6) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 6);

             data__nw_size = data__nelements;
    @@ -1841,6 +1853,9 @@
         SpiceMsgcTunnelSocketData *out;

         { /* data */
    +        if (SPICE_UNLIKELY((start + 2) > message_end)) {
    +            goto error;
    +        }
             data__nelements = message_end - (start + 2);

             data__nw_size = data__nelements;
    @@ -2057,6 +2072,9 @@
         }

         { /* compressed_data */
    +        if (SPICE_UNLIKELY((start + 1 + u__nw_size) > message_end)) {
    +            goto error;
    +        }
             compressed_data__nelements = message_end - (start + 1 + u__nw_size);

             compressed_data__nw_size = compressed_data__nelements;

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-08-16 15:02:24 +01:00
Frediano Ziglio
5dd0c2f70a ci: Fix Meson feature option
feature can be enabled, disabled or auto, not true/false

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-07-27 12:30:21 +01:00
Eduardo Lima (Etrunko)
d6c05fb046 Meson: Make use of 'feature' option type introduced in version 0.47
This built-in type is used instead of the tri-state string combo
(auto/true/false), simplifying the dependency checks.

http://mesonbuild.com/Build-options.html#features

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-27 10:31:53 +01:00
Eduardo Lima (Etrunko)
12af62316d Meson: Make use of dictionary type introduced in version 0.47
Easier to iterate and improves readability of the code by replacing the
use of nested lists.

http://mesonbuild.com/Reference-manual.html#dictionary-object

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-27 10:29:16 +01:00
Eduardo Lima (Etrunko)
25c00ef146 meson: Fix checking for python
When running with -Dpython-checks=false, the build fails. To fix this,
we move the python variable declaration outside of the get_option()
block as it will be used for calling the generators. Also removes the
unnecessary check for python3-devel.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-25 06:13:06 +01:00
Eduardo Lima (Etrunko)
e2fad781ec meson: Make options accessible through parent project
When building either spice-server or spice-gtk, spice-common should
inherit the command line options from the parent project. This is done
by adding the 'yield' keyword for the opus and celt051 options.

It is also required to add a smartcard option so that we can bypass the
checks if the user wants to.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-23 18:43:42 +01:00
Eduardo Lima (Etrunko)
9b2c989dd9 ci: Fix typo: celt501 -> celt051
Fixes the following warning message while running meson:

WARNING: Unknown command line options: "celt501"
This will become a hard error in a future Meson release.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-07-20 08:19:57 +01:00
Lukáš Hrázký
83e1229417 spice*.proto: Replace tabs with the appropriate number of spaces
Plus a few other indentation fixes.

Signed-off-by: Lukáš Hrázký <lhrazky@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-19 13:16:19 +02:00
Lukáš Hrázký
f82a6c5349 Rename SpiceHead::id to monitor_id
The id is called 'monitor_id' throughout the rest of the code, rename
for clarity and consistency.

Signed-off-by: Lukáš Hrázký <lhrazky@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-18 07:21:48 +01:00
Frediano Ziglio
f4a0fec5e9 tests: Join test-overflow and test-marshallers
test-overflow was doing a specific test on demarshalling code.
Joining the 2 tests also allows to remove the dependency from the main
protocol allowing to run the test independently from generation setting.
Using Meson when building either SPICE server or spice-gtk, we only
generate the specific marshallers/demarshallers for that given case.
With this commit the test is built in any case.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-07-12 05:50:50 +01:00
Frediano Ziglio
82c2e2315c canvas_base: Change spice_warning to g_warning
The 2 APIs are equivalent.
Some minor coherence changes:
- remove line terminator, already added;
- start message with lower case;
- LZ4, not Lz4.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-12 05:48:12 +01:00
Frediano Ziglio
e8314732a7 canvas_base: Check for overflows decoding LZ4
Check that we have enough data before reading.
This could lead to read buffer overflows being undetected.
This is not a security issue, read happens only in the client not causing
any information leakage, maximum can generate a crash or some garbage on
the screen.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-12 05:48:12 +01:00
Frediano Ziglio
f636ef42a0 quic: Remove duplicate file
Now that the 2 template files are the same (except for whitespace differences),
we can use a single file.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:34:57 +01:00
Frediano Ziglio
3618db77b5 quic: Unify rgb/non-rgb macro declarations
This commit adds a common block of macro declarations at the top of
quic_tmpl.c and quic_rgb_tmpl.c. This block is identical between the 2
files, and is one big step towards making the 2 files identical.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:34:57 +01:00
Frediano Ziglio
79a6ca2a51 quic: Reorder macro declarations
This commit reorders the macro declarations at the beginning of
quic_tmpl.c and quic_rgb_tmpl.c so that they follow a similar order.
This does the same for the #undef at the end of both file.
This commit is only code movement, and should not add/remove anything
which was not there before. The next commit will unify the macro
declarations and #undef.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:34:57 +01:00
Frediano Ziglio
291475318f quic: Introduce COPY_PIXEL macro
Define and reuse a COPY_PIXEL macro to copy a pixel.
This will help in making quic_tmpl.c and quic_rgb_tmpl.c identical.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:34:57 +01:00
Frediano Ziglio
c0cc563e10 quic: Add DECLARE_*_VARIABLES macros
They will help unify quic_rgb_tmpl.c and quic_tmpl.c

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:34:57 +01:00
Frediano Ziglio
8b21fc5ea1 quic: Move all golomb decoding macros in a single place
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:34:57 +01:00
Christophe Fergeau
0046ee5e81 quic: Wrap declaration/call of quic method in macros
This allows to pass an additional 'channel' argument when needed, and
should eventually let us unify quic_tmpl.c and quic_rgb_tmpl.c

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-10 10:34:57 +01:00
Frediano Ziglio
a2d32a1fdd quic: Add APPLY_ALL_COMP macro to iterate over channels
Use a APPLY_ALL_COMP macro to unify single/multiple channel processing.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
e3609f06a3 quic: Add CORRELATE*/DECORRELATE* macros
This will help to unify quic_tmpl.c and quic_rgb_tmpl.c

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
394b5d31c0 quic: Call directly encode_state_run from templates.
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
7a535a6141 quic: Add missing #undef SET_a/GET_a
These macros were added to quic_tmpl.c in 815223861 but without the
corresponding #undef. This commit adds them for consistency.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
7a6980def8 quic: Make {UN, }COMPRESS_xx macros closer
Define COMPRESS_xx/UNCOMPRESS_xx macros in a more similar way between
quic_tmpl.c and quic_rgb_tmpl.c using channel suffixes. Instead of
having #define COMPRESS(channel) do_something(channel), we'll now have
 #define COMPRESS(channel) do_something(channel_##channel), and call it
with COMPRESS(a)

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
1ca7e2d765 quic: Add SAME_PIXEL macro
This helps making the code in quic_tmpl.c and quic_rgb_tmpl.c more
similar.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
499b10e494 quic: Rework PIXEL_A/PIXEL_B macros
This makes them identical to their counterparts in quic_rgb_tmpl.c

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
946d3dda22 quic: Add UPDATE_MODEL_COMP macro to iterate over channels
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 10:33:28 +01:00
Frediano Ziglio
6ea60433de meson: Remove -std=c99
This flag disable some compiler feature which is used by some system header
potentially introducing some limitations.
Autotools won't add any flag to limit compiler features to C99, instead it
currently only add flags to support C99 when needed.
For instance some Posix limitations changes (like _POSIX_OPEN_MAX).
As compiler feature for instance _Static_assert is not used.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-10 09:54:19 +01:00
Christophe Fergeau
9bf4c32288 build: Define GLIB_VERSION_MIN_REQUIRED/GLIB_VERSION_MAX_ALLOWED
This is defined for the meson build, but not the autotools build. This
commit makes them consistent.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-06 18:12:16 +02:00
Christophe Fergeau
204ff1ae2e pixman: Use g_error() rather than g_abort()
g_abort() was only added in glib 2.50, which causes meson build failures
since this defines GLIB_VERSION_MIN_REQUIRED/GLIB_VERSION_MAX_ALLOWED

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-06 18:11:54 +02:00
Christophe Fergeau
b4e07c31cf build: Remove spice_common.h
Most users of spice_common.h don't need it, or only need log.h. It only
has a few users outside of spice-common. It's not very well defined
which headers it should contain. This commit removes spice_common.h in
favour of direct inclusion of the needed headers.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-06 06:46:15 +01:00
Christophe Fergeau
8069bf498d common: Remove spice_abort()
There are only 2 users in spice-common, and none in spice-gtk/spice

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-06 06:46:13 +01:00
Christophe Fergeau
31d4622687 log: Remove SPICE_DISABLE_ABORT
spice-gtk was the last user, and stopped using it on Jun 14th 2017
in 040090ccba34 "build-sys: remove -DSPICE_DISABLE_ABORT"

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-06 06:46:05 +01:00
Frediano Ziglio
bb8d75bf31 canvas_base: Avoid misaligned access decoding LZ4 data
Make code faster on platforms not supporting unaligned access by
default.
SPICE_UNALIGNED_CAST is just silencing possible alignment warning and,
if enabled, produces some logs, however in this case we know that the
pointer can be misaligned.
Use packed structures to tell compiler to generate best code possible.
For more details see comment on commit 74e50b57ae ("Make the
compiler work out better way to write unaligned memory").

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-05 09:38:30 +01:00
Christophe Fergeau
6496437e80 meson: Remove '(default: xxx)' from option description
'meson configure' will show the current value of an option, specifying
the default value in the option description does not add much to that
output.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-07-05 10:37:35 +02:00
Frediano Ziglio
e98e08594c canvas_base: Fix minor indentation issues
This patch just changes some spaces fixing some possible misleading
indentation.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2018-07-05 09:23:14 +01:00
Christophe Fergeau
3def5a8448 swcanvas: Remove canvas_create()
Nothing calls it in spice-gtk or spice-server

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-04 10:04:02 +02:00
Frediano Ziglio
cd932df7a2 quic: Call encode from golomb_coding
golomb_coding is always followed by a encode call.
Simplify code calling directly it, no reason to pass back output
using pointers.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-07-03 19:37:39 +01:00
Eduardo Lima (Etrunko)
75863fb69f test-region: Decrease loop count by a factor of 10
This test was timing out when running in gitlab-ci, so decreasing the
loop count in order to make it run faster. Example:

https://gitlab.freedesktop.org/etrunko/spice-common/-/jobs/6546

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-03 11:43:24 -03:00
Eduardo Lima (Etrunko)
246f3a02b4 Update gitlab-ci to use meson
Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-07-03 11:30:55 -03:00
Frediano Ziglio
2b5cadcd8a test-marshallers: Check for "zero" attribute
Check the previous fix for "zero" attribute works correctly
(commit bc9df58162, "marshal: Fix a bug
with zero attribute").

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-07-03 12:25:31 +01:00
Eduardo Lima (Etrunko)
7050511d9e meson: Cleanup optional dependency checks
We can follow the same practice as in headers and function checks above,
by using the dependency name itself to set the configuration data.

Also, if a combo is used, the first value is used as default if none is
specified. Thus, we can remove the default value for opus from
meson_options.txt.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-29 16:25:14 -03:00
Eduardo Lima (Etrunko)
1eff0d1207 meson: Enable '-std=c99' build flag
The only file preventing this flag was bitops.h which has been removed
since the following commit:

commit 992ebac6b5
Author: Christophe Fergeau <cfergeau@redhat.com>
Date:   Tue Jun 5 11:27:01 2018 +0200

    build: Remove bitops.h

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-29 16:22:18 -03:00
Frediano Ziglio
4b0c25823f log: Remove spice_printerr macro
All usages of this macro were removed.
A library should not log to standard error but use log facilities
so remove this macro to avoid possible future usage.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-29 19:02:21 +01:00
Frediano Ziglio
0385a67ef8 build: Reindent macros
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-28 13:34:14 +01:00
Frediano Ziglio
da4926bd26 build: Reuse TEST_MARSHALLERS macro
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-28 13:34:14 +01:00
Christophe Fergeau
f90ab1f19b snd: Replace spice_printerr() use with g_warning
This allows users of the library to redirect where these messages go
through use of g_log_set_default_handler() rather than unconditionally
printing on stderr.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-28 13:39:52 +02:00
Frediano Ziglio
252d1b61ed ptypes: Improve some attribute documentation
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-06-27 21:51:42 +01:00
Frediano Ziglio
bc9df58162 marshal: Fix a bug with zero attribute
If this attribute was specified during marshaller the field was
marshalled twice.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-06-27 21:44:19 +01:00
Frediano Ziglio
1378d5cfc4 canvas_base: Make sure top_down is a boolean
Should be a 0/1 but just in case make sure.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-06-27 21:44:17 +01:00
Frediano Ziglio
16deca6f1c marshaller: Fix a possible leak
The possible file descriptor associated to the message (currently
can be only the DRM descriptor from Virgl) is not freed in case
the marshaller is reset/destroyed.
This can happen connecting/disconnecting client.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-06-27 21:44:05 +01:00
Christophe Fergeau
5110dbcbb7 test-region: Add g_assert() checks
At the moment, test success/failure is only printed to stdout. This
commit adds some g_assert() so that test failures can be automatically
detected.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-27 13:17:55 +01:00
Christophe Fergeau
cfbae20c48 test-region: Replace spice_assert() with g_assert_true()
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-27 13:17:53 +01:00
Christophe Fergeau
968ce158f0 test-region: Remove unneeded printf
__FUNCTION__ will always be rect_is_valid, and there is a g_assert to
check the region is valid, so we will get notified anyway if the
validity check fails.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-27 13:17:51 +01:00
Christophe Fergeau
30ff9c3807 test-region: Don't call region_dump() by default
This prints to stdout, which is not desirable in an automated test.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-27 13:17:48 +01:00
Christophe Fergeau
3a6a84e172 test-region: Replace direct printf with g_debug() calls
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-27 13:17:45 +01:00
Christophe Fergeau
e13c1d66b7 test-region: Use GTest API
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-27 13:17:43 +01:00
Frediano Ziglio
0ac8e55ddf test-region: Create proper test for region from source code
region.c contained code to test the module.
Separate test code into a proper test.
Test is copied verbatim from the original code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-27 13:17:41 +01:00
Frediano Ziglio
8e8476d932 ssl_verify: Fix build for newer LibreSSL
LibreSSL 2.7 defines ASN1_STRING_get0_data, like OpenSSL 1.1.
This fixes https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=229044.
Original patch from Piotr Kubaj.

Reported-by: Jack L. <xxjack12xx@gmail.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-26 18:30:58 +01:00
Frediano Ziglio
3f04e2649d Revert "ssl_verify: Fix build for newer LibreSSL"
This reverts commit 638c77f3e6.
Commit had a misleading comment.
2018-06-26 18:30:58 +01:00
Frediano Ziglio
638c77f3e6 ssl_verify: Fix build for newer LibreSSL
LibreSSL 2.7 does not define ASN1_STRING_get0_data, like OpenSSL 1.1.
This fixes https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=229044.
Original patch from Piotr Kubaj.

Reported-by: Jack L. <xxjack12xx@gmail.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-26 17:58:44 +01:00
Frediano Ziglio
345557f044 test-quic: Increase test timeout using Meson
This test can take quite some amount of time to run.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-26 17:57:02 +01:00
Frediano Ziglio
818b820644 canvas_base: Rework DUMP_JPEG debugging
The DUMP_JPEG compile time flag is used to dump all jpeg images
to files.
The code was saving garbage instead of proper data.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Reported-by: 谢 昆明 <KunMing.Xie@hotmail.com>
Tested-by: 谢 昆明 <KunMing.Xie@hotmail.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-26 17:55:04 +01:00
Frediano Ziglio
656106b304 test-quic: Allows to specify multiple images to test
Make easier to test an entire set of files

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-26 10:45:46 +01:00
Christophe de Dinechin
258123318d Add SPICE_ATTR_NORETURN on prototype of error functions
The error functions are supposed to not return.  Using the attribute
documents that in the interface, and is better for the compiler
because most noreturn-related optimizations and spurious warning
eliminations happen at the call site.

Signed-off-by: Christophe de Dinechin <dinechin@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-26 10:25:42 +01:00
Christophe Fergeau
0fc3d4209f test-logging: Improve debug level tests
These tests were checking that the expected messages were output, but
they were not checking that the messages we don't want are not output.
This commit adds this to make sure our log implementation does not
output unwanted debug messages.

Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-21 07:03:25 +01:00
Christophe Fergeau
82a5f19d99 log: Only install glib log handler if SPICE_DEBUG_LEVEL is set
Calling g_log_set_handler() is problematic as this means applications
using spice-server won't be able to use g_log_set_default_handler to
manage spice logging output themselves. Since this call is only needed
for backwards compatibility (so that calling g_log together with
SPICE_DEBUG_LEVEL set has the expected behaviour), we can install it
only when SPICE_DEBUG_LEVEL is set.
Then we should deprecate SPICE_DEBUG_LEVEL once and for all.

Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-20 17:35:43 +01:00
Snir Sheriber
a3598f62aa protocol: Add support for h265 video codec
Signed-off-by: Snir Sheriber <ssheribe@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-19 15:29:27 +01:00
Christophe Fergeau
32e2ed57b5 build: Add __pycache__/*.pyc to DISTCLEANFILES
Python 3 puts its .pyc files in a __pycache__ subdirectory, This commit
adds these to DISTCLEANFILES. My main motivation for doing this is so
that git.mk can then properly add them to .gitignore.

Acked-by: Victor Toso <victortoso@redhat.com>
2018-06-18 14:08:10 +01:00
Christophe Fergeau
a526fea413 build: Remove docs/.gitignore
It was added together with the meson build, but it's currently being
managed by git.mk, so it should not be in git

Acked-by: Victor Toso <victortoso@redhat.com>
2018-06-18 14:08:07 +01:00
Christophe Fergeau
26dce6fede build: Update git.mk to latest version
https://raw.githubusercontent.com/behdad/git.mk/master/git.mk has a
newer version than what we are using now.

Acked-by: Victor Toso <victortoso@redhat.com>
2018-06-18 14:08:03 +01:00
Eduardo Lima (Etrunko)
95743f40a2 Add .gitlab-ci.yml file
Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-06-06 13:41:47 +01:00
Christophe Fergeau
a84f868e48 meson: Remove check for vfork
Nothing in spice-common calls vfork. The autotools-based build can
fallback to vfork if fork is not available/working through the
AC_FUNC_FORK macro, but the meson build is not implementing this magic.
However, fork() is only called once in backtrace.h, and this part of the
code is optional (it's not compiled in on Windows for example), and
anyway, I doubt anyone is going to try to compile SPICE code on a
platform without fork, so we can remove this check, it's always possible
to readd it when we have a clear bug report about what is
missing/needed.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-06 12:16:31 +01:00
Christophe Fergeau
e95f05452a meson: Support auto/true/false for optional dependencies
At the moment, missing optional dependencies will be silently ignored
when the corresponding configuration flag is 'true', and won't be tested
for when the flag is 'false'.
In the autotools build, this corresponds respectively to
--enable-foo=auto and --disable-foo.
Having a way to get an error when the package is enabled but missing is
quite desirable. f52247384 has some half-baked attempt at that, but this
was supposed to be removed from the series. This causes errors when
processing meson.build, breaking the meson build.
This commit adds 'true'/'false'/'auto' in a proper way.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-06 12:16:31 +01:00
Frediano Ziglio
1dcdefa8b3 quic: Use __builtin_clz if available
Different processors has specific instructions to count leading
zero bits. This includes: x86. x64, arm, ppc.
For portability reason the behaviour of __builtin_clz is not
defined if the value is zero so test for it.
Currently the function is not called with the value or 0.
This increase performance decoding of about 4-5% on a x64 machine
(code size decreases a little too, but about 0.1%).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-05 14:58:02 +01:00
Christophe Fergeau
b208389334 build: Move client sources to libspice_common_client_la_SOURCES
These sources are only used by the client, so they do not belong in
libspice_common_la_SOURCES.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-05 14:10:29 +01:00
Christophe Fergeau
992ebac6b5 build: Remove bitops.h
Nothing uses it since the GL backend was removed in 384698a

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-05 14:10:22 +01:00
Christophe Fergeau
f7d3a57ce4 build: Remove checks for functions which are never called
Grepping for 'pow', 'sqrt' or 'inet_ntoa' returns no results in
spice-common code base.
inet_ntoa use was removed in 9749e7e 'ssl-verify: Changed IPv4 hostname
to IPv6' and pow/sqrt use in 384698a 'Remove GL support'

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-05 14:10:14 +01:00
Christophe Fergeau
42795a6d00 build: Use AM_COND_IF
AM_COND_IF can be replaced in constructs like:

    AM_CONDITIONAL([HAVE_OPUS], [test "x$have_opus" = "xyes"])
    if test "x$have_opus" = "xyes" ; then
      AC_DEFINE([HAVE_OPUS], [1], [Define if we have OPUS])
    fi

which becomes:

    AM_CONDITIONAL([HAVE_OPUS], [test "x$have_opus" = "xyes"])
    AM_COND_IF([HAVE_OPUS], AC_DEFINE([HAVE_OPUS], [1], [Define if we have OPUS]))

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-05 14:10:07 +01:00
Christophe Fergeau
f522473842 build: By default, error out if Opus is missing
Following the commit disabling celt by default, it's quite easy to have
a build without both celt and opus. After this commit, Opus will have to
be installed for a successful build unless one passes --disable-opus.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-05 14:10:02 +01:00
Christophe Fergeau
72b0d603e1 build: Disable celt 0.5.1 by default
This version of the CELT codec has long been obsolete, and Opus support
has been added nearly 5 years ago. It's time we move on and try to stop
using Celt ;)
This commit disables CELT by default, but since this could be an
unexpected change for packagers, if CELT 0.5.1 development headers are
installed, it will error out unless --enable-celt051/--disable-celt051
has been explicitly specified.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-05 14:09:55 +01:00
Christophe Fergeau
e98f8a430f build: Ensure we link with -lm if needed
lines.c uses hypot(), which is found in libm on some systems. This means
we are currently relying on getting -lm indirectly through some other
means, as otherwise linking any binary with spice-common would fail.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-06-05 14:09:50 +01:00
Frediano Ziglio
349a74d7c2 quic: Fix endianness encoding
The image is going to network and network protocol is little endian
so the numbers has to be little endian. Note that this is already done
during decoding.
Tested on a ppc64 machine.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-06-04 16:05:20 +01:00
Eduardo Lima (Etrunko)
55070333f6 Add support for building with meson/ninja
In a comparison with current autotools build system, meson/ninja
provides a huge improvement in build speed, while keeping the same
functionalities currently available and being considered more user
friendly.

The new system coexists within the same repository with the current one,
so we can do more extensive testing of its functionality before deciding
if the old system can be removed, or for some reason, has to stay for
good.

- Meson: https://mesonbuild.com

  This is the equivalent of autogen/configure step in autotools. It
  generates the files that will be used by ninja to actually build the
  source code.

  The project has received lots of traction recently, with many GNOME
  projects willing to move to this new build system. The following wiki
  page has more details of the status of the many projects being ported:

    https://wiki.gnome.org/Initiatives/GnomeGoals/MesonPorting

  Meson has a python-like syntax, easy to read, and the documentation
  on the project is very complete, with a dedicated page on how to port
  from autotools, explaining how most common use cases can be
  implemented using meson.

    http://mesonbuild.com/Porting-from-autotools.html

  Other important sources of information:

    http://mesonbuild.com/howtox.html
    http://mesonbuild.com/Syntax.html
    http://mesonbuild.com/Reference-manual.html

- Ninja: https://ninja-build.org

  Ninja is the equivalent of make in an autotools setup, which actually
  builds the source code. It has being used by large and complex
  projects such as Google Chrome, Android and LLVM. There is not much to
  say about ninja (other than it is much faster than make) because we
  won't interact directly with it as much, as meson does the middle man
  job here. The reasoning for creating ninja in the first place is
  explained on the following post:

    http://neugierig.org/software/chromium/notes/2011/02/ninja.html

  Also its manual provides more in-depth information about the design
  principles:

    https://ninja-build.org/manual.html

- Basic workflow:

  Meson package is available for most if not all distros, so, taking
  Fedora as an example, we only need to run:

    # dnf -y install meson ninja-build.

  With Meson, building in-tree is not possible at all, so we need to
  pass a directory as argument to meson where we want the build to be
  done. This has the advantage of creating builds with different options
  under the same parent directory, e.g.:

    $ meson ./build --prefix=/usr
    $ meson ./build-extra -Dextra-checks=true -Dalignment-checks=true

  After configuration is done, we call ninja to actually do the build.

    $ ninja -C ./build
    $ ninja -C ./build install

  Ninja defaults to parallel builds, and this can be changed with the -j
  flag.

    $ ninja -j 10 -C ./build

- Hacking:

  * meson.build: Mandatory for the project root and usually found under
                 each directory you want something to be built.

  * meson_options.txt: Options that can interfere with the result of the
                       build.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-06-01 21:27:04 +01:00
Eduardo Lima (Etrunko)
836bbd0e41 test-quic: Fix -Wsign-compare warning
../tests/test-quic.c: In function ‘gdk_pixbuf_new_random’:
../tests/test-quic.c:205:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     for (i = 0; i < gdk_pixbuf_get_byte_length(random_pixbuf); i++) {
                   ^

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-31 17:46:24 -03:00
Frediano Ziglio
68c0f93889 quic: Remove some too strict asserts in hot paths
Some assert in the code are doing some paranoid test and in code
paths quite hot.
The encoding time is reduced by 30-50% while the decoding time
is reduced by a 20-30%.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2018-05-31 07:34:17 +01:00
Frediano Ziglio
160232f8f6 quic: Remove 'no-inline' hack
The quic code goes through a function pointer in two places in order to
try to prevent the compiler from inlining code.
Doing performance measurements this trick does not work anymore
and just make code less readable.

This patch and message was based on a previous work of
Christophe Fergeau.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2018-05-28 11:27:01 +01:00
Christophe Fergeau
d58a5b6a5a quic: Add test case for compression/decompression
This only adds a basic test relying on gdk-pixbuf.
The main limitation is that gdk-pixbuf does not handle 16bpp images,
nor 32bpp/no alpha images. I should have picked something else instead ;)

This allows at least to exercise the QUIC_IMAGE_TYPE_RGB24 and
QUIC_IMAGE_TYPE_RGBA codepaths.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-25 17:04:23 +01:00
Frediano Ziglio
5312ea3f35 lz: Inline GET_{r,g,b} macros
With last changes are just used once and are straight forward.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: jonathon Jongsma <jjongsma@redhat.com>
2018-05-25 11:54:18 +01:00
Frediano Ziglio
70aa6d39b6 lz: Optimise SAME_PIXEL for RGB16
Do not extract all components and compare one by one, can be easily
compared together.
Performance measurements on a set of 16 bit images shown an improve of
about 10%.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-05-25 11:54:18 +01:00
Christophe Fergeau
a1f6f42a33 quic: Use channel->correlate_row in macros
This avoids the need for a local variable with the right name (which
was decorrelate_drow in some cases in quic_tmpl.c...)

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 17:20:38 +01:00
Christophe Fergeau
0e550416f1 quic: Remove unused argument in uncompress_row{0, }
'correlation_row' is always set to channel->colleration_row, and we
already pass 'channel' as an argument.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 12:18:49 +01:00
Christophe Fergeau
8152238618 quic: Add macros to make quic_tmpl.c much closer to quic_rgb_tmpl.c
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 12:18:44 +01:00
Christophe Fergeau
423518768e quic: s/decorrelate_drow/correlate_row
The naming is odd as this is just an alias for channel->correlate_row.
This will also help in subsequent commits to make things more
consistent with quic_rgb_tmpl.c

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 12:18:40 +01:00
Christophe Fergeau
4690e7239d quic: Introduce CommonState *state variable in templates
Most functions in quic_tmpl.c/quic_rgb_tmpl.c have only superficial
differences. One of them is using channel->state or encoder->rgb_state.

This commit adds a local CommonState *state in all template methods
which will be used instead of channel->state or encoder->rgb_state.
This makes it easier to spot the common code between the 2 template
files...

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 12:18:37 +01:00
Christophe Fergeau
b9dd7ed8f1 quic: Factor common code
We don't need 2 different implementations when the only difference is
the CommonState which is being used.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 12:18:33 +01:00
Christophe Fergeau
d240af18a4 quic: Get rid of RLE #define
It's always set, no need to have conditional compilation based on it.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 11:01:31 +01:00
Christophe Fergeau
fce119be44 quic: Get rid of RLE_STAT #define
It's always set, no need to have conditional compilation based on it.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 11:01:28 +01:00
Christophe Fergeau
7b2c2e620e quic: Get rid of QUIC_RGB #define
It's always set, no need to have conditional compilation based on it.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 11:01:25 +01:00
Christophe Fergeau
763735d636 quic: Remove configurable PRED
It's hardcoded at compile-time, and I don't think it was changed in
years...

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 11:01:22 +01:00
Christophe Fergeau
0629153699 quic: Remove configurable RLE_PRED
It's hardcoded at compile-time, and I don't think it was changed in
years...

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 11:01:15 +01:00
Eduardo Lima (Etrunko)
d1d6210547 Bump glib requirements to 2.38
test-logging makes use of functions only available from this version

../tests/test-logging.c: In function ‘test_spice_abort_level’:
../tests/test-logging.c:50:5: error: ‘g_test_subprocess’ is deprecated: Not available before 2.38 [-Werror=deprecated-declarations]
     if (g_test_subprocess()) {
     ^~
In file included from /usr/include/glib-2.0/glib.h:82:0,
                 from ../tests/test-logging.c:23:
/usr/include/glib-2.0/glib/gtestutils.h:151:10: note: declared here
 gboolean g_test_subprocess (void);
          ^~~~~~~~~~~~~~~~~

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-24 09:32:26 +01:00
Frediano Ziglio
b17894e764 Check for messages with duplicate values inside a channel
Make sure there are not 2 messages with the same value in the
same channel.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-05-23 10:33:05 +01:00
Frediano Ziglio
e2f7a9235f Check for messages with duplicate names inside a channel
Make sure there are not 2 messages with the same name in the
same channel.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-05-23 10:31:30 +01:00
Frediano Ziglio
abdef4fd2a codegen: Remove duplicate client and server code from ChannelType::resolve
Code that handled client and server messages check was the same, just
changed some variable names.
Instead use a class to store same information and reuse the code.
This allows easier extension of the 2 path of code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Lukáš Hrázký <lhrazky@redhat.com>
2018-05-23 10:30:44 +01:00
Frediano Ziglio
78a17ba00a marshaller: Remove initial underscore from static function
This is the only function starting with an underscore, looks
out of style.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-05-21 13:34:58 +01:00
Eduardo Lima (Etrunko)
8816d30e67 Fix cast to spice_marshaller_item_free_func function
Building with gcc 8.0.1 from Fedora 28 gives the following error:

FAILED: common/common@@spice-common@sta/marshaller.c.o
../common/marshaller.c: In function 'spice_marshaller_reserve_space':
../common/marshaller.c:311:27: error: cast between incompatible function types from 'void (*)(void *)' to 'void (*)(uint8_t *, void *)' {aka 'void (*)(unsigned char *, void *)'} [-Werror=cast-function-type]
         item->free_data = (spice_marshaller_item_free_func)free;
                           ^
cc1: all warnings being treated as errors

Which can be easily fixed by creating a new function with the correct
signature and calling free() from it.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-05-18 00:07:08 -03:00
Eduardo Lima (Etrunko)
d84f5a5e63 Fix field names for Smartcard protocol structures
Rename struct VSCMsgReaderAdd field 'reader_name' to 'name', and struct
VSCMsgATR field 'data' to 'atr' to match their definitions in file
vscard_common.h.

The error log follows:

generated_server_demarshallers.c:1985:30: note: each undeclared identifier is reported only once for each function it appears in
generated_server_demarshallers.c:1994:15: error: ‘VSCMsgReaderAdd {aka struct VSCMsgReaderAdd}’ has no member named ‘reader_name’
     memcpy(out->reader_name, in, reader_name__nelements);
               ^~

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-17 21:03:01 +01:00
Eduardo Lima (Etrunko)
20bda4dba9 Fix demarshaller code generator
Even though commit df4ec5c318 commented
out most of smartcard code which triggered this error, it still might
happen if a new message is added with an array member.

The reason is a missing declaration of mem_size, which is fixed simply
by checking if the attribute 'nocopy' is present.

The error log follows:

generated_server_demarshallers.c: In function ‘parse_msgc_smartcard_reader_add’:
generated_server_demarshallers.c:1985:30: error: ‘mem_size’ undeclared (first use in this function); did you mean ‘nw_size’?
     data = (uint8_t *)malloc(mem_size);
                              ^~~~~~~~
                              nw_size

This patch also updates test-marshallers so that this bug is triggered.

The diff between generated demarshallers with the patch applied follows:

--- tests/generated_test_demarshallers.c.old    2018-05-17 14:35:29.234056487 -0300
+++ tests/generated_test_demarshallers.c        2018-05-17 14:35:40.554031295 -0300
@@ -286,6 +286,7 @@ static uint8_t * parse_msg_main_ArrayMes
     uint8_t *start = message_start;
     uint8_t *data = NULL;
     uint64_t nw_size;
+    uint64_t mem_size;
     uint8_t *in, *end;
     uint64_t name__nw_size;
     uint64_t name__nelements;
@@ -298,6 +299,7 @@ static uint8_t * parse_msg_main_ArrayMes
     }

     nw_size = 0 + name__nw_size;
+    mem_size = sizeof(SpiceMsgMainArrayMessage);

     /* Check if message fits in reported side */
     if (nw_size > (uintptr_t) (message_end - start)) {

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-17 21:02:58 +01:00
Frediano Ziglio
129bd04766 test-overflow: Remove a leak in the test
This causes errors if Valgrind or sanitizer or similar memory
leak checkers are used.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-05-17 15:16:28 +01:00
Eduardo Lima (Etrunko)
f97c9c3900 build: Remove FIXME_SERVER_SMARTCARD hack
This hack is now made obsolete by the previous commit. We can safely
remove those defines and the code now builds fine for both spice server
and spice-gtk.

commit df4ec5c318
Author: Frediano Ziglio <fziglio@redhat.com>
Date:   Fri May 11 16:59:46 2018 +0100

    Fix generation of Smartcard channel

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-17 15:11:37 +01:00
Frediano Ziglio
df4ec5c318 Fix generation of Smartcard channel
The Smartcard channel definition has been always broken.
Multiple client messages with the same ID are defined in the channel.
This cause on server demarshaller to only have last message defined,
while on the client marshaller code all message marshallers are
defined but client uses only header message.

Following the difference of the generated code.

  diff -rup old/generated_client_marshallers.c common/generated_client_marshallers.c
  --- old/generated_client_marshallers.c	2018-05-14 22:49:07.641778414 +0100
  +++ common/generated_client_marshallers.c	2018-05-14 22:49:22.266329296 +0100
  @@ -389,27 +389,6 @@ static void spice_marshall_msgc_tunnel_s
   }

   #ifdef USE_SMARTCARD
  -static void spice_marshall_msgc_smartcard_data(SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED SpiceMsgcSmartcard *msg, SpiceMarshaller **reader_name_out)
  -{
  -    SPICE_GNUC_UNUSED SpiceMarshaller *m2;
  -    SpiceMsgcSmartcard *src;
  -    *reader_name_out = NULL;
  -    src = (SpiceMsgcSmartcard *)msg;
  -
  -    /* header */ {
  -        spice_marshaller_add_uint32(m, src->header.type);
  -        spice_marshaller_add_uint32(m, src->header.reader_id);
  -        spice_marshaller_add_uint32(m, src->header.length);
  -    }
  -    if (src->header.type == SPICE_VSC_MESSAGE_TYPE_ReaderAdd) {
  -        /* Don't marshall @nomarshal reader_name */
  -    } else if (src->header.type == SPICE_VSC_MESSAGE_TYPE_ATR || src->header.type == SPICE_VSC_MESSAGE_TYPE_APDU) {
  -        /* Remaining data must be appended manually */
  -    } else if (src->header.type == SPICE_VSC_MESSAGE_TYPE_Error) {
  -        spice_marshaller_add_uint32(m, src->error.code);
  -    }
  -}
  -
   static void spice_marshall_msgc_smartcard_header(SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED VSCMsgHeader *msg)
   {
       SPICE_GNUC_UNUSED SpiceMarshaller *m2;
  @@ -421,25 +400,6 @@ static void spice_marshall_msgc_smartcar
       spice_marshaller_add_uint32(m, src->length);
   }

  -static void spice_marshall_msgc_smartcard_error(SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED VSCMsgError *msg)
  -{
  -    SPICE_GNUC_UNUSED SpiceMarshaller *m2;
  -    VSCMsgError *src;
  -    src = (VSCMsgError *)msg;
  -
  -    spice_marshaller_add_uint32(m, src->code);
  -}
  -
  -static void spice_marshall_msgc_smartcard_atr(SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED VSCMsgATR *msg)
  -{
  -    SPICE_GNUC_UNUSED SpiceMarshaller *m2;
  -}
  -
  -static void spice_marshall_msgc_smartcard_reader_add(SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED VSCMsgReaderAdd *msg)
  -{
  -    SPICE_GNUC_UNUSED SpiceMarshaller *m2;
  -}
  -
   #endif /* USE_SMARTCARD */
   static void spice_marshall_SpiceMsgCompressedData(SPICE_GNUC_UNUSED SpiceMarshaller *m, SPICE_GNUC_UNUSED SpiceMsgCompressedData *msg)
   {
  @@ -496,20 +456,8 @@ SpiceMessageMarshallers * spice_message_
       marshallers.msgc_record_mode = spice_marshall_msgc_record_mode;
       marshallers.msgc_record_start_mark = spice_marshall_msgc_record_start_mark;
   #ifdef USE_SMARTCARD
  -    marshallers.msgc_smartcard_atr = spice_marshall_msgc_smartcard_atr;
  -#endif /* USE_SMARTCARD */
  -#ifdef USE_SMARTCARD
  -    marshallers.msgc_smartcard_data = spice_marshall_msgc_smartcard_data;
  -#endif /* USE_SMARTCARD */
  -#ifdef USE_SMARTCARD
  -    marshallers.msgc_smartcard_error = spice_marshall_msgc_smartcard_error;
  -#endif /* USE_SMARTCARD */
  -#ifdef USE_SMARTCARD
       marshallers.msgc_smartcard_header = spice_marshall_msgc_smartcard_header;
   #endif /* USE_SMARTCARD */
  -#ifdef USE_SMARTCARD
  -    marshallers.msgc_smartcard_reader_add = spice_marshall_msgc_smartcard_reader_add;
  -#endif /* USE_SMARTCARD */
       marshallers.msgc_tunnel_service_add = spice_marshall_msgc_tunnel_service_add;
       marshallers.msgc_tunnel_service_remove = spice_marshall_msgc_tunnel_service_remove;
       marshallers.msgc_tunnel_socket_closed = spice_marshall_msgc_tunnel_socket_closed;
  diff -rup old/generated_client_marshallers.h common/generated_client_marshallers.h
  --- old/generated_client_marshallers.h	2018-05-14 22:49:07.641778414 +0100
  +++ common/generated_client_marshallers.h	2018-05-14 22:49:22.739358627 +0100
  @@ -61,11 +61,7 @@ typedef struct {
       void (*msgc_tunnel_socket_data)(SpiceMarshaller *m, SpiceMsgcTunnelSocketData *msg);
       void (*msgc_tunnel_socket_token)(SpiceMarshaller *m, SpiceMsgcTunnelSocketTokens *msg);
   #ifdef USE_SMARTCARD
  -    void (*msgc_smartcard_data)(SpiceMarshaller *m, SpiceMsgcSmartcard *msg, SpiceMarshaller **reader_name_out);
       void (*msgc_smartcard_header)(SpiceMarshaller *m, VSCMsgHeader *msg);
  -    void (*msgc_smartcard_error)(SpiceMarshaller *m, VSCMsgError *msg);
  -    void (*msgc_smartcard_atr)(SpiceMarshaller *m, VSCMsgATR *msg);
  -    void (*msgc_smartcard_reader_add)(SpiceMarshaller *m, VSCMsgReaderAdd *msg);
   #endif /* USE_SMARTCARD */
       void (*msg_SpiceMsgCompressedData)(SpiceMarshaller *m, SpiceMsgCompressedData *msg);
       void (*msgc_port_event)(SpiceMarshaller *m, SpiceMsgcPortEvent *msg);
  Only in common/: generated_client_marshallers.lo
  diff -rup old/generated_server_demarshallers.c common/generated_server_demarshallers.c
  --- old/generated_server_demarshallers.c	2018-05-14 22:49:07.641778414 +0100
  +++ common/generated_server_demarshallers.c	2018-05-14 22:49:23.498405695 +0100
  @@ -1957,24 +1957,18 @@ static uint8_t * parse_TunnelChannel_msg

   #ifdef USE_SMARTCARD

  -static uint8_t * parse_msgc_smartcard_reader_add(uint8_t *message_start, uint8_t *message_end, SPICE_GNUC_UNUSED int minor, size_t *size, message_destructor_t *free_message)
  +static uint8_t * parse_msgc_smartcard_header(uint8_t *message_start, uint8_t *message_end, SPICE_GNUC_UNUSED int minor, size_t *size, message_destructor_t *free_message)
   {
       SPICE_GNUC_UNUSED uint8_t *pos;
       uint8_t *start = message_start;
       uint8_t *data = NULL;
       uint64_t nw_size;
  +    uint64_t mem_size;
       uint8_t *in, *end;
  -    uint64_t reader_name__nw_size;
  -    uint64_t reader_name__nelements;
  -    VSCMsgReaderAdd *out;
  +    VSCMsgHeader *out;

  -    { /* reader_name */
  -        reader_name__nelements = message_end - (start + 0);
  -
  -        reader_name__nw_size = reader_name__nelements;
  -    }
  -
  -    nw_size = 0 + reader_name__nw_size;
  +    nw_size = 12;
  +    mem_size = sizeof(VSCMsgHeader);

       /* Check if message fits in reported side */
       if (nw_size > (uintptr_t) (message_end - start)) {
  @@ -1986,13 +1980,14 @@ static uint8_t * parse_msgc_smartcard_re
       if (SPICE_UNLIKELY(data == NULL)) {
           goto error;
       }
  -    end = data + sizeof(VSCMsgReaderAdd);
  +    end = data + sizeof(VSCMsgHeader);
       in = start;

  -    out = (VSCMsgReaderAdd *)data;
  +    out = (VSCMsgHeader *)data;

  -    memcpy(out->reader_name, in, reader_name__nelements);
  -    in += reader_name__nelements;
  +    out->type = consume_uint32(&in);
  +    out->reader_id = consume_uint32(&in);
  +    out->length = consume_uint32(&in);

       assert(in <= message_end);
       assert(end <= data + mem_size);
  @@ -2017,7 +2012,7 @@ static uint8_t * parse_SmartcardChannel_
           parse_msgc_disconnecting
       };
       static parse_msg_func_t funcs2[1] =  {
  -        parse_msgc_smartcard_reader_add
  +        parse_msgc_smartcard_header
       };
       if (message_type >= 1 && message_type < 7) {
           return funcs1[message_type-1](message_start, message_end, minor, size_out, free_message);

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-05-17 12:25:42 +01:00
Frediano Ziglio
617be0f74b Avoid integer overflow computing image sizes
Use always 64, sizes can be 32x32.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-05-11 17:00:26 +01:00
Frediano Ziglio
420a15b776 Write a small test to test possible crash
This small test prove a that current generated demarshaller code
is not safe to integer overflows leading to buffer overflows.
Actually from a quick look at the protocol it seems that client
can't cause these overflows but server can quite easily at
demonstrated by this test.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-05-11 17:00:26 +01:00
Frediano Ziglio
a69fb1ec34 Fix integer overflows computing sizes
Make code safe using both 32 and 64 bit machine.
Consider that this code can be compiled for machines with 32 bit.
There are some arrays length which are 32 bit.

If size_t this can cause easily an overflow. For instance message_len
sending SPICE_MSG_NOTIFY messages are 32 bit and code add a small
constant (currently 24) before doing the test for size. Now passing
(uint32_t) -20 as message_len would lead to a size of 4 after the
addition. This overflow does not happen on 64 bit machine as the length
is converted to size_t.

There are also some array length where some item are bigger than 1 byte.
For instance SPICE_MAIN_CHANNELS_LIST message have a number of channels
and each channel is composed by 2 bytes. Now the code generated try to do
length * 2 where length is still a 32 bit so if we put a value like
0x80000002u we get 4 as length. This will cause an overflow as code will
allocate very few bytes but try to fill with a huge number of elements.
This overflow happen in both 32 and 64 bit machine.

To avoid all these possible overflows this patch use only 64 bit for
nelements (number of elements), nw_size (network size) and mem_size
(memory size needed) checking the sizes to avoid other overflows
(like pointers conversions under 32 bit machines).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe de Dinechin <dinechin@redhat.com>
2018-05-11 08:41:36 +01:00
Frediano Ziglio
75d9842e7d lz: Move ENCODE_PIXEL for RGB24 and RGB32 to a common place
The macro for both depth is the same, reuse the definition.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-05-10 19:50:50 +01:00
Frediano Ziglio
b98f19b168 protocol: Use a typedef to specify stream_id type
This change does not affect generated code but make source more
readable. Also document in a single location the range of this
type.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-05-10 19:49:03 +01:00
Jonathon Jongsma
fc46379b37 miLineArc(): initialize edge1, edge2
When compiling spice-common with meson/ninja under "release" mode, I get
several compiler warnings about possibly-uninitialized members. For
example:

    ../subprojects/spice-common/common/lines.c: In function ‘miLineArc’:
    ../subprojects/spice-common/common/lines.c:2167:17: error: ‘edge2.dx’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
             edge->e += edge->dx; \
                     ^~
    ../subprojects/spice-common/common/lines.c:2426:24: note: ‘edge2.dx’ was declared here
         PolyEdgeRec edge1, edge2;
                            ^~~~~

Initializing these structures to zero silences the warnings.

Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-10 10:05:41 -05:00
Frediano Ziglio
754cd54e1a codegen: Removed unused get_type methods
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Lukáš Hrázký <lhrazky@redhat.com>
2018-05-09 11:59:33 +01:00
Frediano Ziglio
46fa9d5efb codegen: Add some comments
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Lukáš Hrázký <lhrazky@redhat.com>
2018-05-09 11:59:33 +01:00
Victor Toso
5729664523 messages: document limitation of id in StreamCreate
Note that the ID limitation always existed but now we have the
limitation in the protocol itself with SPICE_MAX_NUM_STREAMS

Signed-off-by: Victor Toso <victortoso@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-05-05 13:00:56 +01:00
Jonathon Jongsma
885b1a6bb9 Remove extra self parameter from member function
When testing out some experimental protocol changes, I managed to
trigger the following error:

  GEN      generated_client_demarshallers.c
Traceback (most recent call last):
  File "../../../spice-common/spice_codegen.py", line 267, in <module>
    demarshal.write_protocol_parser(writer, proto, True)
  File "/home/jjongsma/work/spice/spice-common/python_modules/demarshal.py", line 1270, in write_protocol_parser
    parsers[channel.value] = (channel.channel_type, write_channel_parser(writer, channel.channel_type, is_server))
  File "/home/jjongsma/work/spice/spice-common/python_modules/demarshal.py", line 1163, in write_channel_parser
    func = write_msg_parser(helpers, ids[i].message_type)
  File "/home/jjongsma/work/spice/spice-common/python_modules/demarshal.py", line 1061, in write_msg_parser
    num_pointers = message.get_num_pointers()
  File "/home/jjongsma/work/spice/spice-common/python_modules/ptypes.py", line 855, in get_num_pointers
    count = count + m.get_num_pointers()
  File "/home/jjongsma/work/spice/spice-common/python_modules/ptypes.py", line 662, in get_num_pointers
    return self.member_type.get_num_pointers()
  File "/home/jjongsma/work/spice/spice-common/python_modules/ptypes.py", line 507, in get_num_pointers
    if self.is_constant_length(self):
TypeError: is_constant_length() takes exactly 1 argument (2 given)

Calling a member function will implicitly pass 'self' as the first
argument, but we were also explicitly passing it as an argument
(self.is_constant_length(self)). This resulted in the above error.

Acked-by: Lukáš Hrázký <lhrazky@redhat.com>
2018-04-17 14:14:22 +01:00
Frediano Ziglio
4c2d0e9772 Add --enable-extra-checks option
Allow to enable code to do additional or expensive checks.
The option should be used by higher level libraries.
By default the option is disabled.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2018-03-19 14:47:21 +00:00
Frediano Ziglio
2eaef9c16d protocol: Add some documentation for inval_all_pixmaps message
This message is not straight forward to grasp.
Not clear by the name why we need to wait other channels messages
before resetting the image cache.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2018-03-18 09:14:29 +00:00
Frediano Ziglio
8096b1206b canvas: Use SPICE_UNALIGNED_CAST to avoid -Wcast-align warnings
This solves https://bugs.freedesktop.org/show_bug.cgi?id=104521.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2018-01-31 15:10:35 +00:00
Frediano Ziglio
fd0aba2750 canvas: Fix some semi transparent drawing
This is reproducible using desktop icons on Windows XP.

These drawing are sent for the icons on the desktop.
To get an extends.x1 >= 32 you have to move an icon out of the
screen on the left side. Set the icon size to 72 as the icon has
to be out of the screen quite a lot.
Disable the grid alignment on the desktop and move an icon out of
the screen. Select and unselect the icon.
Using "/ 32" the icon will have a white background instead of a
transparent one.
Using a "/ 8" the icon is rendered correctly.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe de Dinechin <cdupontd@redhat.com>
2018-01-25 22:27:34 +00:00
Frediano Ziglio
f3478aa4b6 canvas: Prevent some error compiling spice-gtk
Due to different warning setting some GCC reports:

In file included from ../spice-common/common/sw_canvas.c:27:0,
                 from client_sw_canvas.c:20:
../spice-common/common/canvas_base.c: In function ‘canvas_get_lz’:
../spice-common/common/canvas_base.c:768:13: error: ‘palette’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
             free(palette);
             ^~~~~~~~~~~~~
../spice-common/common/canvas_base.c:764:9: error: variable ‘free_palette’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered]
     int free_palette = FALSE;
         ^~~~~~~~~~~~
cc1: all warnings being treated as errors

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Snir Sheriber <ssheribe@redhat.com>
2018-01-24 10:41:02 +00:00
Paweł Pękala
122be3d1f7 Fix build with LibreSSL
Some FreeBSD configurations can use LibreSSL instead of OpenSSL.
The two libraries are really similar but need some minimal adjustment.

Signed-off-by: Paweł Pękala <pawelbsd@gmail.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2018-01-23 10:23:43 +00:00
Frediano Ziglio
41c7ea6611 canvas: Remove unused include header
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:34:26 +00:00
Frediano Ziglio
0dda6fbf55 canvas: Unify __surface_create_stride and surface_create_stride
They are now just the same function with same parameters,
just one calls the other.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:34:24 +00:00
Frediano Ziglio
3bf6e7b899 canvas: Remove dc fields from CanvasBase and LzDecodeUsrData
Now always NULL.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:34:22 +00:00
Frediano Ziglio
b0f1d31dd1 canvas: Remove dc parameter from SwCanvas::put_image
Not used anymore.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:34:19 +00:00
Frediano Ziglio
6ce1a61577 canvas: Remove unused dc parameter from surface_create
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:34:16 +00:00
Frediano Ziglio
00d1cda4ce canvas: Remove Windows bitmap allocation
There's no reason to use a DIB section if we are going to use just the
memory in it assigned to a pixman surface, use normal path and memory.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:34:14 +00:00
Frediano Ziglio
cd88d0294c canvas: Remove mutex field from PixmanData
The field is only assigned but never used.
This was used in the GDI canvas which has now been removed.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:34:12 +00:00
Frediano Ziglio
fea48544a8 canvas: Move PixmanData to C file
This structure is used only in canvas_utils.c

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-18 14:33:44 +00:00
Frediano Ziglio
27e32fa8a6 lz: Remove unused encode_level and only assigned io_start
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-01-18 10:08:46 +00:00
Frediano Ziglio
5fda05740f lz: Simplify code
Remove some conditional code always defining CAST_PLT_DISTANCE
macro.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-01-18 10:08:43 +00:00
Frediano Ziglio
552e842a16 lz: Avoid temporary variable
Use a break to exit the loop instead of using a variable.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-01-18 10:08:41 +00:00
Frediano Ziglio
29eff61cf8 canvas: Remove possible leak on LZ decompression failure
longjmp can happen in different places, even after the palette
is allocated so we need to free it if it got allocated.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-01-18 10:08:39 +00:00
Frediano Ziglio
d11df6b66b canvas: Simplify code using spice_memdup
Instead of using spice_malloc+memcpy use spice_memdup which is
doing the same.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2018-01-18 10:08:26 +00:00
Pavel Grunt
a3a2bb9ea7 Remove GDI canvas
Only spicec was using it - removed by spice server commit:
1876971442ef808b5dcdaa5dc12df617f2179cb5

Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2018-01-17 09:31:32 +00:00
Frediano Ziglio
637621a9b9 canvas-base: Fix width computation for palette images
Palette images have padding at the end of each line, so their stride
can't be inferred from their width as is currently done. This causes a
wrong calculation of stride_encoded value which causes a wrong stride
adjustment.

Before commit 5603961ff "fix 16 bpp LZ image decompression", the output
stride was always computed as "stride = (n_comp_pixels / height) * 4"
that is assuming 4 bytes for pixel which was wrong for some output
however computing starting from width was wrong for palette images.

This commit was added to spice-gtk in v0.32~58, which nicely matches the
"client regression when upgrading from spice-gtk v0.31 to spice-gtk
v0.33".

This fix bug https://bugzilla.redhat.com/show_bug.cgi?id=1508847.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Tested-by: Philip J. Turmel <philip@turmel.org>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-12-22 18:19:54 +00:00
Frediano Ziglio
53f6d1269a protocol: Allow to specify a surface will be streamed
This flag will allow the client to perform some optimisations
on output and buffering processing.
Old clients will ignore this additional flag.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2017-12-01 15:48:56 +00:00
Frediano Ziglio
94898df6b4 proto: Add some documentation to stream_report message
Most of the documentation is extracted from notes in spice-server
code and comments.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-11-29 11:50:54 +00:00
Frediano Ziglio
45e2844845 canvas_base: Allow to specify constant operations
There's no need for the canvas operations to be changed.
This allows without casts to have the operation structures
constants in the code.
This potentially allows to reduce attack surface having some
more data constant instead or read/write.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe de Dinechin <dinechin@redhat.com>
2017-11-07 13:11:19 +00:00
Frediano Ziglio
72ae9b2971 ring: Remove short living temporary variable
Just a style change, the variable does not help readability.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe de Dinechin <dinechin@redhat.com>
2017-11-07 13:11:19 +00:00
Frediano Ziglio
c208ca85cd ring: Remove __ring_remove function
Is just used by ring_remove, no reason to have it.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe de Dinechin <dinechin@redhat.com>
2017-11-07 13:11:19 +00:00
Frediano Ziglio
c2f2096d90 test-marshallers: Test demarshalling
Generate demarshallers code and check it too.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-09-25 16:13:27 +01:00
Frediano Ziglio
c25c75b552 test-marshallers: Use unaligned structure
Allows to test for bad performance on some systems.
For instance on ARMv6/ARMv7 which does not support by default
64 bit unaligned read/write this can be checked on Linux
using /proc/cpu/alignment file.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-09-25 16:13:18 +01:00
Frediano Ziglio
74e50b57ae Make the compiler work out better way to write unaligned memory
Instead of assuming that the system can safely do unaligned access
to memory use packed structures to allow the compiler generate
best code possible.
A packed structure tells the compiler to not leave padding inside it
and that the structure can be unaligned so any field can be unaligned
having to generate proper access code based on architecture.
For instance ARM7 can use unaligned access but not for 64 bit
numbers (currently these accesses are emulated by Linux kernel
with obvious performance consequences).

This changes the current methods from:

#ifdef WORDS_BIGENDIAN
#define read_uint32(ptr) ((uint32_t)SPICE_BYTESWAP32(*((uint32_t *)(ptr))))
#define write_uint32(ptr, val) *(uint32_t *)(ptr) = SPICE_BYTESWAP32((uint32_t)val)
#else
#define read_uint32(ptr) (*((uint32_t *)(ptr)))
#define write_uint32(ptr, val) (*((uint32_t *)(ptr))) = val
#endif

to:

#include <spice/start-packed.h>
typedef struct SPICE_ATTR_PACKED {
    uint32_t v;
} uint32_unaligned_t;
#include <spice/end-packed.h>

#ifdef WORDS_BIGENDIAN
#define read_uint32(ptr) ((uint32_t)SPICE_BYTESWAP32(((uint32_unaligned_t *)(ptr))->v))
#define write_uint32(ptr, val) ((uint32_unaligned_t *)(ptr))->v = SPICE_BYTESWAP32((uint32_t)val)
#else
#define read_uint32(ptr) (((uint32_unaligned_t *)(ptr))->v)
#define write_uint32(ptr, val) (((uint32_unaligned_t *)(ptr))->v) = val
#endif

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-09-25 16:12:45 +01:00
Frediano Ziglio
70d4739ce2 quic: avoid crash on specific images
encodes_ones is called to encode a long sequence of 1 bits.
In some conditions (I manage to reproduce with a 85000x4 pixel
image fill with a single color) encodes_ones is called with a
"n" value >= 32.
This cause encode to be called with a "len" value of 32 which
trigger this assert:

   spice_assert(len > 0 && len < 32);

causing a crash. Instead of calling encode with a constant
"len" as 32 call encode_32 which is supposed to encode
exactly 32 bit.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-08-23 22:47:08 +01:00
Frediano Ziglio
429ad96537 quic: turn back some commented out checks as compile time
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-08-09 07:07:36 +01:00
Frediano Ziglio
a6d6e8435a quic: use 32 bit for bppmask
In most occurrences bppmask is converted to 32 bit anyway.
In the left one a possible more bigger precision is not needed.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-08-09 07:07:34 +01:00
Frediano Ziglio
6a882282f1 quic: remove Channel::encoder
This field is easily accessible from Encoder structure.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-08-09 07:07:32 +01:00
Frediano Ziglio
3306492247 quic: remove only assigned CommonState::encoder
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-08-09 07:07:29 +01:00
Frediano Ziglio
65ba949fb0 quic: remove only assigned num_channels field
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-08-09 07:07:13 +01:00
Frediano Ziglio
9f6a671294 quic: fix typo golomb_deoding -> golomb_decoding
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-03 13:33:00 +01:00
Frediano Ziglio
b64ee40a60 quic: fix typo corelate -> correlate
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-03 13:32:45 +01:00
Christophe Fergeau
c39f2da17e quic: Use i == 0 rather than !i
This helps to make quic_rgb_tmpl.c and quic_tmpl.c more consistent.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-01 15:53:59 +02:00
Christophe Fergeau
8dd7374a1d quic: Fix "corelate" typo
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-01 15:53:47 +02:00
Christophe Fergeau
9574246403 quic: Use SPICE_VERIFY for static check
DEFevol is known at compile-time, so we can use SPICE_VERIFY to check
its value.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-01 15:53:44 +02:00
Christophe Fergeau
5684ed10be quic: Use DEFwmimax constant rather than wmimax variable
We never change its value, so we basically have 2 constants for the
same thing, DEFwmimax and wmimax. This commit removes the latter.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-01 15:53:42 +02:00
Christophe Fergeau
f122d3dadc quic: Use DEFwminext constant rather than wminext variable
We never change its value, so we basically have 2 constants for the
same thing, DEFwminext and wminext. This commit removes the latter

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-01 15:53:38 +02:00
Christophe Fergeau
db5bff3728 quic: Use DEFevol constant rather than evol variable
We never change 'evol' value, and this is currently causing issues with
gcc 7.1.1: quic.c is checking at compile-time that 'evol' is 1, 3 or 5.
This is a constant, so a static check should be good, but the compiler (gcc
7.1.1) is unable to know 'evol' value at compile-time. Since the removal
of spice_static_assert in favour of SPICE_VERIFY, this causes a
compile-time failure.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-08-01 15:53:34 +02:00
Christophe Fergeau
a25ebbac56 canvas: Don't try to unref NULL pixman_image_t
pixman_image_unref() does not ignore NULL pointers, it tries to
dereference it which causes a crash. When trying to decode invalid QUIC
data, we could end up in a situation where 'surface' would still be
NULL when reaching the setjmp block.

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2017-07-20 17:13:35 +02:00
Christophe Fergeau
fffe755d9c log: Define G_LOG_DOMAIN as early as possible
"log: Forbid the usage of obsolete SPICE_LOG_DOMAIN" introduced a small
regression, if G_LOG_DOMAIN is not set when glib.h is included, the
header will set it to a default value. Redefining it later in log.c is
going to cause a compile-time warning.
This commit adds the definition to SPICE_COMMON_CFLAGS so that it's
defined before any inclusion of glib.h is possible. This is similar to
what is done in spice/configure.ac.

This avoids this warning:
CC       log.lo
log.c:44:0: warning: "G_LOG_DOMAIN" redefined
 #define G_LOG_DOMAIN "Spice"

In file included from /usr/include/glib-2.0/glib.h:62:0,
                 from log.c:22:
/usr/include/glib-2.0/glib/gmessages.h:280:0: note: this is the location of the previous definition
 #define G_LOG_DOMAIN    ((gchar*) 0)

Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2017-07-07 17:04:36 +02:00
Frediano Ziglio
eeab433539 log: Force format in log macro to be a string
Make sure format is a string and not a pointer.
This prevents usages like:

  spice_debug(NULL);

This forbids computed format strings, but on the other hand, forcing
the use of string constants allows the compiler to always check
argument types against the format string. Moreover, there is no
occurrences of computed format strings in the current codebase.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-07-05 09:53:10 +01:00
Frediano Ziglio
518c57db20 log: Forbid the usage of obsolete SPICE_LOG_DOMAIN
As we decided to not use multiple GLib domains, the SPICE_LOG_DOMAIN
macro is not really useful. This commit removes it.
Will be replaced by some different categorization.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-07-05 09:53:02 +01:00
Frediano Ziglio
14c595b609 quic: Fix typo in function names
reste -> reset

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-07-04 10:06:09 +01:00
Frediano Ziglio
dde1fe3533 log: remove spice_static_assert macro
The macro was misused and not doing static check.
Spice have other working static check macros to use.
The macro is used only by spice-common so removing it
does not cause issues to other depending projects.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2017-06-22 11:34:19 +01:00
Frediano Ziglio
2ff5c77fff quic: constantify some variable
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2017-06-22 11:34:19 +01:00
Frediano Ziglio
f80b229e07 canvas-base: Do not attempt useless cast on stride adjustment
memmove already deal with any alignment so there's no
reason to have row byte pointer cast to uint32_t.
This also remove the confusing "dest" terminology used. The image
is aligned in place so the image bits are used for both destination
and source.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-06-21 12:57:52 +01:00
Christophe de Dinechin
858a0bfae9 Avoid clang warnings on casts with stricter alignment requirements
For example, something like this:
    uint8_t  *p8;
    uint32_t *p32 = (uint32_t *) p8;

generates a warning like this:
  spice-channel.c:1350:10: error: cast from 'uint8_t *' (aka 'unsigned char *') to
      'uint32_t *' (aka 'unsigned int *') increases required alignment from 1 to
      4 [-Werror,-Wcast-align]

The warning indicates that we end up with a pointer to data that
should be 4-byte aligned, but its value may be misaligned. On x86,
this does not make much of a difference, except a relatively minor
performance penalty. However, on platforms such as older ARM, misaligned
accesses are emulated by the kernel, and support for them is optional.
So we may end up with a fault.

The intent of the fix here is to make it easy to identify and rework
places where actual mis-alignment occurs. Wherever casts raise the warning,
they are replaced with a macro:

- SPICE_ALIGNED_CAST(type, value) casts value to type, and indicates that
  we believe the resulting pointer is aligned. If it is not, a runtime
  warning will be issued. This check is disabled unless
  --enable-alignment-checks is passed at configure time

- SPICE_UNALIGNED_CAST(type, value) casts value to type, and indicates that
  we believe the resulting pointer is not always aligned.

Any code using SPICE_UNALIGNED_CAST may need to be revisited in order
to improve performance, e.g. by using memcpy.

There are normally no warnings for SPICE_UNALIGNED_CAST, but it is possible
to emit debug messages for mis-alignment in SPICE_UNALIGNED_CAST
by configuring with CFLAGS=-DSPICE_DEBUG_ALIGNMENT.

Signed-off-by: Christophe de Dinechin <dinechin@redhat.com>
2017-06-20 11:33:45 +02:00
Frediano Ziglio
765652da1d Use SPICE_ATTR_PACKED instead of custom ATTR_PACKED
Reuse {start,end}-packed headers to specify packed structure.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2017-06-15 12:47:36 +01:00
Christophe de Dinechin
30a33922d8 Use space and not colon to separate log domains
According to https://developer.gnome.org/glib/stable/glib-running.html,
G_MESSAGES_DEBUG is a space-separated list of log domains for which
informational and debug messages should be printed

Note that the equivalent code in spice-util.c gets it right.

Signed-off-by: Christophe de Dinechin <dinechin@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-06-09 09:56:29 +01:00
Frediano Ziglio
1d7acdcf57 log: Use GLib logging levels directly
As we moved toward GLib logging instead of having to convert
every time the log level from the old system to GLib use
directly GLib constants.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-06-09 09:46:35 +01:00
Frediano Ziglio
31ebe7c6d5 fix indentation on previous patch
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2017-06-01 10:12:34 +01:00
Frediano Ziglio
564635e3c1 log: Check log level from spice_logv
This was suggested by Christophe de Dinechin as an optimisation.
Most of the messages won't be processed for formatting.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-05-31 10:20:58 +01:00
Frediano Ziglio
a607077883 log: Optimise glib_debug_level check
Use INT_MAX for invalid value to remove a test in code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-05-31 10:20:56 +01:00
Frediano Ziglio
f4a4d52702 log: Do not check impossible function return
spice_log_level_to_glib never returns 0 so don't check
for this value.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-05-31 10:20:50 +01:00
Frediano Ziglio
36fd7325e5 codegen: Fix license name
License reported for MIT was indeed a BSD 3-Clause license,
not a MIT one (https://opensource.org/licenses/BSD-3-Clause).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
2017-05-18 16:40:36 +01:00
Christophe de Dinechin
5faba1e860 Style adjustment - Making code match surrounding style
Signed-off-by: Christophe de Dinechin <dinechin@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2017-05-18 16:37:21 +01:00
Frediano Ziglio
1d527e21d5 codegen: Allows to specify license of generated files
Some headers for spice are distributed using MIT licenses.
Allows to generate such headers if needed.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2017-05-08 09:54:10 +01:00
Christophe Fergeau
af682b1b06 log: Follow spice style guidelines for #include in log.h
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-03-31 12:14:02 +02:00
Christophe Fergeau
0996c33d6d log: Add missing stdio.h include
This is needed because spice_printerr uses fprintf/stderr

Acked-by: Frediano Ziglio <fziglio@redhat.com>
2017-03-31 10:37:28 +01:00
Marc-André Lureau
1fd73d0a98 build-sys: don't dist spice-protocol.html
The HTML file is not built by default.
This fixes make distcheck in spice-gtk.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2017-03-28 14:57:50 +02:00
Frediano Ziglio
4423ea5d2a region: Avoid possible memory corruption
pixman_region32_copy assume that destination (first argument)
is initialized and can use a pointer inside based on different
conditions.
As intersection is not initialized this can cause different
memory problems.
This resulted in memory leak detection from address sanitizer.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2017-02-28 15:26:54 +00:00
Sebastian Andrzej Siewior
ab7cae45bc ssl: Use ASN1_STRING_get0_data instead of ASN1_STRING_data
The latter is deprecated, so might be removed at  some point in the
future. This also adds a compatibility wrapper for OpenSSL < 1.1.0.

Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2017-02-16 16:40:52 +01:00
Jonathon Jongsma
c9ecd0e29e Document REGION_TEST_* bitmasks
Acked-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
2017-02-03 11:07:32 -06:00
Frediano Ziglio
30e8237934 protocol: Add support for VP9 video codec
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2017-01-31 08:51:33 +00:00
Victor Toso
6439bec0de protocol: add preferred video codec message
Client might want to choose a preferred video codec for streaming for
different reasons which having hardware decoder support being the most
interest one.

This message allows the client to send an array of video codecs in
order of preference.

Signed-off-by: Victor Toso <victortoso@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2017-01-06 12:20:47 +00:00
Frediano Ziglio
86dcd22d33 marshaller: Remove deprecated replacement functions
spice-common has no stable ABI/API.
Also these function caused linking problems as these functions
were defined multiple times.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-12-08 13:49:13 +00:00
Jonathon Jongsma
adb36c6185 Marshaller: rename _add_ref() to _add_by_ref()
The spice_marshaller_add_ref() family of functions is confusing since it
sounds like you're incrementing a reference on the marshaller. What it
is actually doing is adding a data buffer to the marshaller by reference
rather than by value. Changing the function names to _add_by_ref() makes
this clearer.

The old functions are deprecated and are simply inline functions that
call the new functions.

Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-12-06 11:21:55 -06:00
Victor Toso
a5871c80a9 sw-canvas: remove unused defines
Including CANVAS_SINGLE_INSTANCE that was bounded to CanvasBase user
data which was removed in previous commit

Signed-off-by: Victor Toso <victortoso@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-11-30 15:36:29 +01:00
Victor Toso
580ca81536 canvas-base: remove user data from CanvasBase
Neither Spice nor spice-gtk are using this since the
following commit in Spice "server: remove OpenGL"
c5c176a5c7718177f23b07981556b5d460627498

Signed-off-by: Victor Toso <victortoso@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-11-30 15:36:29 +01:00
Pavel Grunt
5f241e655b spice-deps: Set python version based on modules availability
Building spice or spice-gtk from git requires python modules pyparsing
and six. Search for them in the both Python versions and set
the Python version accordingly.
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-11-29 11:43:25 +01:00
Frediano Ziglio
6b409c4a79 Detect LZ4_compress_fast_continue function
Newer lz4 headers give deprecated warning using LZ4_compress_continue
instead of LZ_compress_fast_continue so detect this function
to allow usage and avoid the warning.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-11-28 18:36:21 +00:00
Pavel Grunt
48da2c6654 spice-deps: Make LZ4 check depending on function
LZ4 changed versioning scheme from r131 to v1.7.3 making our configure
fail with (1.7.3 < 129).

Switch from version checking to checking that the necessary function
is available.

Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-11-25 14:01:04 +00:00
Pavel Grunt
de1dee75c2 spice-deps: Fix accidently deleted comment
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-11-24 15:54:09 +00:00
Victor Toso
edaafa187d canvas-base: group ifdef and defined together
Signed-off-by: Victor Toso <victortoso@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-11-24 15:51:05 +00:00
Victor Toso
2c34cf49b5 canvas-base: use helper to get surface
Moving out a big switch statement that sole purpose is to retrieve the
surface (pixma_image_t)

Signed-off-by: Victor Toso <victortoso@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-11-24 15:51:01 +00:00
Frediano Ziglio
31819a2424 Define a new SPICE_VERIFY macro
The verify macro used currently has some problem
as it raise a warning in RHEL6.
As suggested in verify.h use verify_expr macro
to avoid the warning.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-11-14 17:19:18 +00:00
Pavel Grunt
63e575d5fc silence -Wunused-parameter 2016-11-01 15:26:43 +01:00
Victor Toso
215b7571d4 Fix gitignore with new docs folder
The generated spice_protocol.html file and the Makefile were not
included in gitignore. This patch fixes it.

Signed-off-by: Victor Toso <victortoso@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2016-10-27 18:05:12 +02:00
Frediano Ziglio
e5a03766ec Add protocol documentation for "channel" and "protocol"
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-10-18 14:57:13 +01:00
Frediano Ziglio
ced5c55925 Fix BNF notation in documentation
Definition names have no angular brackets.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-10-18 14:57:13 +01:00
Frediano Ziglio
4673a61cce More work on attribute protocol documentation
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-10-17 11:43:49 +01:00
Frediano Ziglio
7773c0d59b Extended protocol documentation
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-10-17 11:43:47 +01:00
Frediano Ziglio
89426e491e Start writing some documentation on protocol
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-10-17 11:43:45 +01:00
Frediano Ziglio
3983097ed5 Start adding protocol file documentation
The protocol file is not documented and people have to read code to
understand the specification.
This can lead to unexpected or not optimal results so it's better
to have it documented.
The m4/spice_manual.m4 came from spice server and is meant to be
reused.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-10-17 11:43:26 +01:00
Victor Toso
642308ecec build-sys: requires liblz4 129 or newer
LZ4 data compression on spicevmc channel uses LZ4_compress_default()
API introduced in 129 release (see commit bellow)

[0] https://github.com/Cyan4973/lz4/commit/1b17bf2ab8cf66dd2b740e

Acked-by: Pavel Grunt <pgrunt@redhat.com>
Reported-by: Fabio Fantoni <fantonifabio@tiscali.it>
2016-08-09 16:40:00 +02:00
Francois Gouget
38047fb46f codegen: Fix compatibility with Python 2.6
Python 2.6 does not have a flags parameter.
This is needed for RHEL 6.8.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-07-30 08:57:05 +01:00
Pavel Grunt
22f8dd18f0 codegen: Do not generate extra null check
Spotted by coverity

Acked-by: Fabiano Fidêncio <fidencio@redhat.com>
2016-07-26 10:16:31 +01:00
Eduardo Lima (Etrunko)
62f3024f42 Use explicit path for inclusion
As client_marshallers.h is included outisde of spice-common, we need to
specify the path for generated_marsharllers.h so that builds out of the
tree don't fail.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2016-07-13 15:03:34 -03:00
Christophe Fergeau
073d064b86 codegen: Autogenerate client_marshallers.h
This commit adds autogeneration of a generated_client_marshallers.h
header, which is then included in client_marshallers.h

This allows to remove the SpiceMessageMarshallers struct from this file,
which has to match what the generated code expects.

Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-06-24 10:02:58 +01:00
Frediano Ziglio
0eb567e6fb codegen: Improve header guard generation
Until now, the same header guard was used for all generated .h files.
Now the header guard name is based on the name of the file being
generated so that it's different for each .h file.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-06-24 10:02:06 +01:00
Christophe Fergeau
806d3273fa codegen: Use "" rather than <> for cmdline includes
Includes specified on the command line are currently #included with <>
rather than "". However, they are usually spice-common headers, so it
makes more sense to include them using ""

Acked-by: Pavel Grunt <pgrunt@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-06-24 09:36:49 +01:00
Christophe Fergeau
3029eae630 codegen: Fix 'registred' typo
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-06-24 07:47:41 +01:00
Frediano Ziglio
15b8f28c14 Use a macro to simplify ring_get_length
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-06-21 12:52:27 +01:00
Frediano Ziglio
57570953dc extend a comment for type attributes
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-06-21 12:52:25 +01:00
Frediano Ziglio
c5a61aaa30 add a check for negate cases on enumerations
Not supported by code so trigger an error to avoid invalid usages

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-06-21 12:52:18 +01:00
Christophe Fergeau
1d47225a8e Adjust verify.h licence
verify.h can be licensed as LGPLv2+ rather than GPLv3, see
http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=modules/verify;h=5216ce890dac58e596a27341e31258e5d6c0d702;hb=HEAD

A verify.h file with the appropriate licence can be generated from a
gnulib clone using:
gnulib-tool --lgpl=2 --import verify

This will fail if the 'verify' module is not licensed under a compatible
license.
2016-06-21 12:26:38 +02:00
Christophe Fergeau
8f722db28e codegen: Remove unused write_message_marshaller argument
"is_server" is not used in this method
2016-06-20 15:05:34 +02:00
Christophe Fergeau
62b996ffb0 Update verify.h to latest version 2016-06-20 15:03:44 +02:00
Eduardo Lima (Etrunko)
5359304713 Make LZ4 dependency check more robust
Add a new 'HAVE_LZ4' automake conditional to really tell if we have the
dependency installed on the system. It will later be used in Makefile to
decide whether or not the specific files related to LZ4 should be built.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2016-06-16 10:36:48 -03:00
snir sheriber
4284011bdc Add LZ4 data compression and use it in spicevmc channel
Compressed message type is CompressedData which contains compression
type (1 byte) followed by the uncompressed data size (4 bytes-exists
only if data was compressed) followed by the compressed data

Update the required protocol to 0.12.12:

Signed-off-by: Snir Sheriber <ssheribe@redhat.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-06-13 23:00:28 +01:00
Frediano Ziglio
d0139f824e Remove a warning compiling under Windows
On Windows long is always 32 bit so under x64 the cast from pointer to
"unsigned long" cause a warning.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-06-13 18:38:25 +01:00
Frediano Ziglio
bbd8f9a5e2 Remove deprecated init functions
No need to keep API compatibility in spice-common.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <mlureau@redhat.com>
2016-06-13 11:28:58 +01:00
Frediano Ziglio
73282208f0 simplify #ifdef code
Reduce conditional code

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-06-02 10:01:48 +01:00
Frediano Ziglio
d3dd8bcea3 fix wrong assert check
The assert were never triggered as always True

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-06-02 08:34:19 +01:00
Frediano Ziglio
1c97fea956 Explicitly specify size of SpiceMsgSmartcardData
Without this, the demarshalling code does not know we expect exactly
SpiceMsgSmartcardData::length bytes, and has to guess it from the
amount of data which was sent

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-05-13 13:32:10 +01:00
Pavel Grunt
384698af37 Remove GL support
It is not needed since spice-server commit
c5c176a5c7718177f23b07981556b5d460627498

Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-05-11 16:54:23 +01:00
Pavel Grunt
ad862c4d4b test-logging: Include stdlib.h for _Exit()
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-05-09 10:20:32 +02:00
Fabiano Fidêncio
74439e8e6e Use g_getenv() instead of getenv()
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-04-25 09:09:17 +02:00
Fabiano Fidêncio
a8f756eabf coverity: remove structurally dead code
The loop (for (;;)) will be executed only once, so, no reason for
keeping it.

Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-04-25 09:09:17 +02:00
Fabiano Fidêncio
83b84428ec coverity: remove unused value
len is overwritten in the match label with the value from
"ip - anchor".

Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-04-25 09:09:17 +02:00
Fabiano Fidêncio
657e1c5291 coverity: avoid division or modulo by zero
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-04-25 09:09:17 +02:00
Fabiano Fidêncio
3312a0f70b coverity: avoid dereference after null check
All decompress functions used after this check take into account that
encoder->palette is not NULL. So, if we already detected that the
palette is NULL, let's just return early.

Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-04-25 09:09:17 +02:00
Fabiano Fidêncio
89b902789b coverity: avoid resource leak
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-04-25 08:34:54 +02:00
Fabiano Fidêncio
bc73df4e47 coverity: avoid use after free
Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-04-25 08:34:14 +02:00
Pavel Grunt
739a859d79 Define canvas_fix_alignment when is used
It is used in canvas_get_lz4() which is guarded by USE_LZ4, and
in canvas_get_lz() which is guarded by SW_CANVAS_CACHE.
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-04-19 13:49:50 +02:00
Lin Ma
2eaf7c9572 build-sys: Define opengl GL_LIBS and GL_CFLAGS in generated Makefile.in
SPICE_COMMON_{CFLAGS,LIBS} references '$(GL_{CFLAGS,LIBS)', so these
variables are going to be expanded at 'make' time rather than at
'configure' time.
The linker flag and the compiler flag won't be substituted in the
generated Makefile without AC_SUBST.
It causes spice-gtk building failure with --enable-opengl option.

The patch fixes this issue.

Signed-off-by: Lin Ma <lma@suse.com>
2016-04-18 10:59:07 +02:00
Frediano Ziglio
5603961ffa fix 16 bpp LZ image decompression
LZ image decompression was broken for 16 bpp:
- stride was computed not computed correctly (as width*4). This caused
  also a buffer underflow;
- stride in pixman is always multiple of 4 bytes (so for 16 bpp is
  ALIGN(width*2, 4)) so image decompressed by lz_decode as some missing
  bytes to be fixed.

The alignment code is reused from LZ4 function.

This fix also https://bugzilla.redhat.com/show_bug.cgi?id=1285469.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-04-15 14:25:58 +01:00
Christophe Fergeau
2a4bf49edd log: Make sure glib threading is initialized
While testing spice-server on EL6, I was getting random crashes in the
glib logging code because g_logv was called recursively even though this
was not visible in a backtrace.

It turns out on older glib versions (EL6 has 2.28), g_logv is not
thread-safe unless g_thread_init() is called first. If g_thread_init()
is not called, the GMutex/GPrivate calls g_logv makes are turned into
no-ops, which is going to cause the recursion issue I was seeing.

This commit adds a call to g_thread_init() for these older glib
versions.

(gdb) bt
    0x7fff9f9fb110 "item.type: 114", unused_data=0x0) at gmessages.c:863
    format=0x7ffff50e72ac "item.type: %d", args1=0x7fff9f9fb640) at gmessages.c:517
    SPICE_LOG_LEVEL_DEBUG, strloc=0x7ffff50e72ba "dcc.c:1652", function=
    0x7ffff50e7320 "release_item_before_push", format=0x7ffff50e72ac "item.type: %d", args=
    0x7fff9f9fb640) at log.c:163
    SPICE_LOG_LEVEL_DEBUG, strloc=0x7ffff50e72ba "dcc.c:1652", function=
    0x7ffff50e7320 "release_item_before_push", format=0x7ffff50e72ac "item.type: %d") at log.c:195
    at dcc.c:1652
    at dcc.c:1719
    at dcc-send.c:2450
    at red-channel.c:578
    at red-channel.c:1587
    at event-loop.c:122
    0x7ffff4fb2ef2 <watch_func>, user_data=0x7fff980244e0) at giounix.c:166
    0x7ffff86ec770) at gmain.c:3092
2016-04-05 15:38:18 +02:00
Christophe Fergeau
8473d0ae71 log: Use SPICE_CONSTRUCTOR_FUNC
This was done through a GOnce called every time spice_log() is called,
now it will always be called at spice-server startup.

This means the unit test needs to be updated as SPICE_DEBUG/ABORT_LEVEL
must now be set before the process starts up rather than before the
first spice_log call, and the deprecation warning these environment
variables trigger cannot be caught using g_test_expect_message() as
they are output before g_test_init() is called.
2016-04-05 15:38:17 +02:00
Christophe Fergeau
6a65f470d1 log: Clamp SPICE_DEBUG_LEVEL if it's too high
This matches how SPICE_DEBUG_LEVEL behaved before switching to glib
logging.
2016-04-05 15:38:16 +02:00
Christophe Fergeau
6c7552d543 tests: Fix glib version check
The glib version checks were using #ifdef GLIB_CHECK_VERSION() rather
than  #if GLIB_CHECK_VERSION()
2016-03-31 13:34:43 +02:00
Eduardo Lima (Etrunko)
55ec596798 2/2] Add check for openssl
It is required to compile ssl-verify.[ch].

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2016-03-31 11:25:49 +02:00
Eduardo Lima (Etrunko)
51df6f775a Fix build in systems with Glib version older than 2.38
Tests now include functions only available in glib 2.38. To avoid
setting the dependency bar too high, we simply put them between #ifdef
guards.

Signed-off-by: Eduardo Lima (Etrunko) <etrunko@redhat.com>
2016-03-31 11:25:02 +02:00
Frediano Ziglio
5b6be16b37 use macro to define constructor function
Avoid having to call function at runtime to inialize static.
Old functions are defined as deprecated for compatibility.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Pavel Grunt <pgrunt@redhat.com>
2016-03-23 15:06:08 +00:00
Frediano Ziglio
2505f9ac96 define SPICE_CONSTRUCTOR_FUNC and SPICE_DESTRUCTOR_FUNC macros
Allow to define functions executed at program/shared object initialization
or close.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-03-17 17:16:30 +00:00
Frediano Ziglio
0f45924f4c tests: exit on SIGABRT
Fatal error exit usually with abort() causing SIGABRT to be triggered
which can have problems with core dump generation depending on system
settings. Capturing and exiting on this signal solve the problem.
This is a workaround to some system configurations which could cause
test to fail.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2016-03-16 08:14:02 +00:00
Frediano Ziglio
53ee80bd7d Cap logging level to the valid bounds
Avoid overflows using its values.
The patch was originally written by Christophe Fergeau

Acked-by: Victor Toso <victortoso@redhat.com>
2016-03-11 10:16:22 +00:00
Christophe Fergeau
8af947e7b2 Remove 2 unused vfuncs from client_marshallers.h
The AudioVolume and AudioMute messages are not sent by the client, so
they do not need to appear in SpiceMessageMarshallers in
client_marshallers.h
2016-03-11 09:55:09 +01:00
Francois Gouget
00db440878 protocol: Add support for the VP8 and h264 video codecs
Clients that support multiple codecs must advertise the
SPICE_DISPLAY_CAP_MULTI_CODEC capability and one
SPICE_DISPLAY_CAP_CODEC_XXX per supported codec.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>

(cherry picked from spice-protocol commit 7937915d67702a5c4b5147b277c432f5555e3852)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:59:18 +01:00
Marc-Andre Lureau
279be89836 protocol: add unix GL scanout messages
Add 2 new messages to the display channel to stream pre-rendered GL
images of the display. This is only possible when the client supports
SPICE_DISPLAY_CAP_GL_SCANOUT capability.

The first message, SPICE_MSG_DISPLAY_GL_SCANOUT_UNIX, sends a gl image
file handle via socket ancillary data, and can be imported in a GL
context with the help of eglCreateImageKHR() (as with the 2d canvas, the
SPICE_MSG_DISPLAY_MONITORS_CONFIG will give the monitors
coordinates (x/y/w/h) within the image). There can be only one scanount
per display channel.

A SPICE_MSG_DISPLAY_GL_DRAW message is sent with the coordinate of the
region within the scanount to (re)draw on the client display. For each
draw, once the client is done with the rendering, it must acknowldge it
by sending a SPICE_MSGC_DISPLAY_GL_DRAW_DONE message, in order to
release the context (it is expected to improve this in the future with a
cross-process GL fence).

The relation with the existing display channel messages is that all
other messages are unchanged: the last drawing command received must be
displayed. However the scanout display is all or nothing. Consequently,
if a 2d canvas draw is received, the display must be switched to the
drawn canvas. In other words, if the last message received is a GL draw
the display should switch to the GL display, if it's a 2d draw message
the display should be switched to the client 2d canvas.

(there will probably be a stipped-down "gl-only" channel in the future,
or support for other streaming methods, but this protocol change should
be enough for basic virgl or other gpu-accelerated support)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>

(cherry picked from spice-protocol commit 3fc2221e965623c5a7e50d95f1623269a067c2d3)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:01:46 +01:00
Christophe Fergeau
0853b579df proto: Use proper type for preferred_compression field
No need to use an uint8 typed member, we can directly use the
appropriate enum8 type here, which makes everything more explicit.

(cherry picked from spice-protocol commit 8a3def14e35039753097094ba356e85e8fc2d128)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:01:46 +01:00
Christophe Fergeau
2ccf106920 proto: Rename image_compress to image_compression
Re-using the SPICE_IMAGE_COMPRESS_ prefix in newer spice-protocol
releases is going to cause issues as there will be clashing enum members
in older spice-server releases. Using SPICE_IMAGE_COMPRESSION_ as a
prefix sidesteps these backward compability issues.

(cherry picked from spice-protocol commit e857cd9a378cdf56805b64284491a12af93a7cbf)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:01:46 +01:00
Marc-André Lureau
487f914a5d codegen: simplify FdType
This patch is a left-over from the fd passing commit 267391c8fd as
suggested by Frediano Ziglio during review.

Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>

(cherry picked from spice-protocol commit 47076559628d71c128e14e11147ce36b92677885)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:01:42 +01:00
Marc-Andre Lureau
c5ed374a32 protocol: learn to describe fd passing in messages
Add a new type, "unix_fd", used to describe file descriptor sharing via
socket ancillary data (these messages are local only).

The marshaller/demarshaller can't serialize this in memory (consume_fd
implementation is empty), so it is the responsability of the marshaller
user to handle sending and receiving the handles, which are appended at
the end of the message with an extra stream byte (because some Unix
requires sending at least a byte with ancillary data).

Even if there is no fd to send (or if the fd is invalid etc), the
receiver side expects an extra byte anyway.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>

(cherry-picked from spice-protocol commit 267391c8fd7c90c067b3e4845ff0227a2580e2e2)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:01:42 +01:00
Marc-André Lureau
1cd26b87c1 Revert "Remove files moved to spice-protocol"
This reverts commit 7665dcf1bb.

Also revert the related build-sys changes to fix the build.

codegen generated code depends on spice-common code (marshaller,
messages etc), it makes more sense to keep the generator along
this. Otherwise a newer protocol release will fail to build older
projects.

*.proto files are required as well, since it generates code that parent
modules depend on unconditionnaly.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2016-03-10 16:01:36 +01:00
Marc-André Lureau
f06f699d78 test-logging: unset G_MESSAGES_DEBUG
This test is sensitive to G_MESSAGES_DEBUG variable. Make it insensitive
by unsetting the environment variable.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-03-10 14:47:39 +00:00
Frediano Ziglio
fd9ba72f1a marshaller: fix uninitialized field usage
has_fd was not initialized.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Marc-André Lureau <mlureau@redhat.com>
2016-02-03 11:48:43 +00:00
Marc-Andre Lureau
472e563591 marshaller: track if add_fd() was given -1
In some cases, it might be worth to be able to send a message with a -1
fd, has the protocol permits. Change add_fd/get_fd in order to track
if the caller wanted to send -1.

Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-02-02 12:38:54 +00:00
Pavel Grunt
6424c0baee Use lz4 if possible
Change the default option to "auto"

Acked-by: Victor Toso <victortoso@redhat.com>
2016-01-28 14:16:10 +01:00
Frediano Ziglio
75cb2701d3 Use code to compute a bit mask
Code is in the slow path, this reduce space needed for data+code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-27 18:39:06 +00:00
Frediano Ziglio
580adf7c36 Avoid to call ceil_log_2 twice with same value
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-27 18:39:04 +00:00
Frediano Ziglio
6e04b94751 Constification
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-27 18:39:02 +00:00
Frediano Ziglio
daf406a179 zeroLUT has same content of lzeroes
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-27 18:39:01 +00:00
Frediano Ziglio
07b3150cb1 common: constify some declarations
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-27 18:38:43 +00:00
Frediano Ziglio
7790dacfd3 small spice_strdup optimization
avoid to compute the string length twice and use memcpy instead of
strcpy which is faster not having to check for terminator.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-26 17:17:08 +00:00
Frediano Ziglio
5376f1d88c remove wrong statement terminator from preprocessor macro
Actually not causing problems as when used is always followed by another
terminator but better to fix the definition.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-26 16:45:32 +00:00
Christophe Fergeau
0a6580d2e6 log: Kill spice_warn_if
It's redundant with spice_warn_if_fail(), and can even be confusing.

Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-26 15:58:43 +01:00
Christophe Fergeau
df56d585cb log: Add test case for logging code
This gives us a baseline of how the SPICE/glib integration is supposed
to behave.

Everything goes through glib logging facilities, and is impacted by
G_MESSAGES_DEBUG/G_DEBUG=fatal-{warnings,criticals}

Messages in the SPICE_LOG_DOMAIN log domain (output either through
spice_log() or g_log()) will also consider the legacy SPICE_DEBUG_LEVEL
and SPICE_ABORT_LEVEL environment variables. Messages in other domains
will not be impacted by these legacy environment variables.

If spice-common is built without SPICE_DISABLE_ABORT,
spice_return_if_fail()/spice_critical() will abort the program.
g_return_if_fail()/g_critical() will not abort the program.
2016-01-26 15:58:43 +01:00
Christophe Fergeau
417dbedc0b tests: Always build tests
The next commit will introduce a test for log messages. As
libspice-common.la behaviour varies depending on whether
SPICE_DISABLE_ASSERT was defined at compile-time, this test will also
take into account this preprocessor define.
We are more likely to get a consistent build (SPICE_DISABLE_ASSERT being
the same when building libspice-common.la and the test) if both are
built at the same time.

This commit changes that, tests are now built (but not run) at 'make'
time rather than 'make check' time.
2016-01-26 15:58:43 +01:00
Christophe Fergeau
efd1d3cb4d log: Use glib for logging
spice-common has been duplicating glib logging methods for a long while.
Now that spice-common is depending on glib, it's more consistent to use
glib logging too. However, the code base is still using spice logging
functions.
This commit aims to make spice logging go through glib logging system,
while keeping the same behaviour for the SPICE_ABORT_LEVEL and
SPICE_DEBUG_LEVEL environment variables. They are deprecated however in
favour of the glib alternatives (G_DEBUG and G_MESSAGES_DEBUG).

Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-26 15:58:43 +01:00
Christophe Fergeau
2ff25b7567 log: Remove unneeded #ifdef/#endif
If header guards are working as expected, there should not be multiple
definitions of these macros. If they are redefined somewhere else, this
is a bug we want to fix.

Acked-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-26 11:49:14 +01:00
Christophe Fergeau
838596a257 log: Use more glib macros
No need to have our own SPICE_STMT_BEGIN/END and SPICE_STRINGIFY

Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-21 11:10:39 +01:00
Pavel Grunt
93cd2f6836 draw: Add spice_image_descriptor_is_lossy
It will be used in the server code

Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-01-20 15:56:00 +00:00
Marc-Andre Lureau
b61f43f228 Add GL scanout structures
See related protocol changes.

Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-01-14 11:49:25 +00:00
Marc-Andre Lureau
a18bed136f marshaller: learn to describe fd passing in messages
The marshaller can't serialize fd in memory stream. Instead, append the
fd to the marshaller structure. The marshaller user is responsible for
sending the fd when the message is sent. The fd to send can be retrieved
with spice_marshaller_get_fd().

Note: only a single fd is supported with this API, supporting multiple
fd is left for the future if it becomes necessary.

Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
2016-01-14 11:46:58 +00:00
Frediano Ziglio
80cc3f680a ring: use NULL instead of 0 for null pointers
This is consistent with the rest of the code making clear
fields are pointers.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Uri Lublin <uril@redhat.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2016-01-07 16:46:19 +00:00
Victor Toso
397eb47816 Remove headers that are included in spice_common.h
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
2016-01-07 12:46:42 +01:00
Pavel Grunt
c3f2d217af m4: Add macro for --with-sasl
It is not used by spice-common, but both server and client can use it.
Compared to current checks in spice-gtk and spice server this macro only
supports libsasl2.

Acked-by: Christophe Fergeau <cfergeau@redhat.com>
2015-12-18 13:57:58 +01:00
Lukas Venhoda
a78da942a7 Remove trailing whitespace 2015-12-18 11:41:15 +01:00
Lukas Venhoda
1118712c59 ppc: Fix alpha state checking on BE machines
The surface before conversion can be either LE or BE on a BE machine.
Check against both BE and LE color order on BE machine.
2015-12-17 16:03:22 +01:00
Lukas Venhoda
2493c60ff7 ppc: Fix colors on ppc when using jpeg
Fixes color order on PowerPC when using jpeg compression.
2015-12-17 16:03:20 +01:00
Lukas Venhoda
98f9097c49 ppc: Fix colors on ppc when using LZ4
Fixes color order on PowerPC when using LZ4 image compression.
2015-12-17 16:03:20 +01:00
Lukas Venhoda
d7719d3e60 ppc: Fix colors on ppc when using LZ
Fixes color order on PowerPC when using LZ image compression.
2015-12-17 16:03:20 +01:00
Lukas Venhoda
bdc9951049 ppc: Fix colors on ppc when using QUIC
Fixes color order on PowerPC when using QUIC image compression.
2015-12-17 16:03:19 +01:00
Lukas Venhoda
76a0c2fae8 ppc: Add support for bigendian color byte order
On LE machine, color order when creating surface will always be A/XRGB.
On BE machines the color order will sometimes be ARGB and sometimes BGRA/X.

This is because we actually create the surface two times on BE machines.
Once with BE order, and then again with LE order. Copying data inbetween
theese two surfaces will byteswap the colors automatically.

This change introduces cases for BGRA/X color byte orders on BE machines.
2015-12-17 16:03:19 +01:00
Lukas Venhoda
fc1f511bb8 pixman_utils: Use PIXMAN_LE_ constants in spice_bitmap_try_as_pixman()
After the previous commit, spice_bitmap_try_as_pixman() can be
simplified as its #ifdef WORDS_BIGENDIAN exactly match what the
PIXMAN_LE_ constants do.
2015-12-17 16:03:19 +01:00
Lukas Venhoda
2ee5cb522e pixman_utils: Add macros for color byte ordering
When using image compression on PowerPC architecture, colors are in
wrong order ARGB -> BGRA.

This commit introduces macros, that will change the color order
according to machine endianness.

Theese macros are similar to QEMU macros in qemu-pixman.h
2015-12-17 16:03:19 +01:00
Christophe Fergeau
02c82b468c test: Use _LDADD rather than _LDFLAGS
This allows libtool/automake to correctly add a dependency from
libspice-common.la to test_marshallers. With _LDFLAGS, the binary won't
automatically get rebuilt/relinked when the lib changes.
2015-12-16 15:03:53 +01:00
Christophe Fergeau
d13fdd7fa9 m4: Fix SPICE_WARNING on el6
autogen.sh fails on el6 unless the second argument to
AC_DEFUN([SPICE_WARNING]) is enclosed in []
2015-12-14 15:30:41 +01:00
Christophe Fergeau
47122befcd ssl-verify: Don't leak GInetAddress
GInetAddress is a GObject, so we must unref anything we create with
g_inet_address_new_*
2015-11-27 17:50:02 +01:00
Christophe Fergeau
9057e0aef3 ssl-verify: Handle NULL return from g_inet_address_new_from_string()
It will return NULL if the string we pass it cannot be parsed.
2015-11-27 17:50:02 +01:00
Marc-André Lureau
f8db887eb0 Use new libcacard.h if possible
libcacard.h requires 2.5.1. Keep compatibility for older versions until
the transition in distros to the standalone version is done.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
[ Christophe: add < 2.5.1 fallback ]
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
2015-11-25 15:16:35 +01:00
Marc-André Lureau
56a0cf2dad Fix make distcheck
Fix make distcheck both with standalone spice-common and with spice
server.

Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
2015-11-25 14:05:42 +01:00
Lukas Venhoda
401801b5ba canvas_base: Remove redundant switch case block 2015-11-24 08:29:28 +01:00
Francois Gouget
f471022453 build-sys: Add SPICE_CHECK_GSTREAMER_ELEMENTS()
This makes it possible to warn the developer that the GStreamer elements
needed at runtime are missing and give him a hint on how to fix the
issue.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
2015-11-16 16:31:06 +01:00
Francois Gouget
437b817f49 build-sys: Add SPICE_CHECK_GSTREAMER()
This simplifies checking for GStreamer modules by setting all the
variables we normally need.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
2015-11-04 10:34:19 +01:00
Francois Gouget
899a7c75e3 build-sys: Add the SPICE_WARNING() and SPICE_PRINT_MESSAGES m4 macros
A call to SPICE_WARNING() anywhere in the configure file results in the
warning being printed at the end of the configure run where it will be
be visible. This makes it possible to keep the SPICE_WARNING() calls
together with the related feature checks instead of having to put a
separate AC_MSG_WARN() call near the end.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
2015-11-04 10:34:19 +01:00
Christophe Fergeau
304a16fdad build-sys: Add missing # to comment
SPICE_CHECK_SMARTCARD documentation ends with a '-------' comment, but
the # to start the comment is missing, causing a warning message when
running configure.
2015-11-02 12:30:09 +01:00
Christophe Fergeau
d8c3568a31 build-sys: Rename SUPPORT_GL to HAVE_GL
The other conditionals are using the HAVE_ prefix, using HAVE_GL rather
than SUPPORT_GL improves consistency.
2015-10-23 14:05:39 +02:00
Christophe Fergeau
f77805773f build-sys: Set automake conditional in SPICE_CHECK_SMARTCARD
spice-server will use this.
2015-10-23 14:05:39 +02:00
Christophe Fergeau
986ad88c28 build-sys: Fix error in SPICE_CHECK_LZ4 description
This macro does not define a SUPPORT_LZ4 automake conditional.
2015-10-23 14:05:23 +02:00
Christophe Fergeau
04ed3b8cbe build-sys: Add gio-2.0 to SPICE_CHECK_GLIB2
GInetAddress is defined in gio, not glib. Not checking for gio-2.0 in
SPICE_CHECK_GLIB2 means gio won't be in GLIB2_LIBS, which causes link
errors when trying to build spice-server.
2015-10-23 14:05:23 +02:00
Lukas Venhoda
9749e7ed14 ssl-verify: Changed IPv4 hostname to IPv6
Change inet_aton function to glib functions.

inet_aton only supported IPv4 addresses, and wasn't available on windows
machines. GInetAddress functions support IPv6 natively, and requires less
boilerplate code then IPv6 gettaddrinfo().
2015-10-23 11:07:58 +02:00
Lukas Venhoda
9b74e47ed3 m4: Require glib version >= 2.22
This is required by the GInetAddress functions.
2015-10-23 11:07:58 +02:00
Lukas Venhoda
fb6904f528 ssl-verify: Only check addr length when using IP addr
Only check for address length, when connecting through IP address.
It is not used, when connecting through DNS hostname.
2015-10-23 11:07:45 +02:00
Christophe Fergeau
f7ec855af3 build-sys: Rework SPICE_CHECK_* m4 macros
These macros were automatically appending the needed CFLAGS/LIBS to
variables passed as arguments. This is how spice-common uses them, but
now how spice-gtk/spice want to use them, and is making the macros more
complicated than they could (in particular this makes them use
AS_VAR_APPEND).
This  is also not flexible enough as spice-gtk uses libcacard libraries,
while spice-common does not need them. If SPICE_CHECK_SMARTCARD
unconditionnally libcacard libraries to the variable spice-common passes
it as an argument, we'll end up linking with an unneeded library.

This commit removes this automatic appending from the SPICE_CHECK_*
macros and moves it to spice-common as it's the only one which needs it.
2015-10-13 11:26:01 +02:00
Christophe Fergeau
26a533d6eb build-sys: Use ${PKG_CONFIG} rather than pkg-config
In mingw builds, this will be set to mingw-pkg-config rather than the
host system one. This is fixing a build failure on mingw when
spice-protocol is only installed in the mingw prefix and not
system-wide.
2015-10-07 18:01:17 +02:00
Christophe Fergeau
523875d8c5 Add marshaller test case
This allows to test the spice_marshaller_linearize() fix which was sent
recently.
2015-09-15 17:48:59 +02:00
Javier Celaya
7b146745ee Fix linearization of several marshallers with one item
The linearization optimization that avoids copying only one item must
check that there are no further marshallers in the chain.

Just to be clear, we are trying to marshall a message like this:

message {
    uint32 data_size;
    uint64 *data[data_size] @marshall;
} SomeData;

Where the data field points to an array in dynamic memory. Marshalling
and demarshalling functions look good. The marshalling function creates
a submarshaller for the data field and links it to the root marshaller.
But when it comes to sending the data through the wire, only the
data_size field gets sent. We have observed that, in
spice_marshaller_linearize, execution enters into the optimization that
avoids copying the data when the root marshaller only has one item, but
it ignores the following marshallers in the list. Checking if there are
more marshallers fixes the problem.
2015-09-15 17:38:12 +02:00
Frediano Ziglio
449c5da90f common: Fix typo in comment
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-08-14 19:19:24 +01:00
Christophe Fergeau
dd63a3b656 build-sys: Remove code generation files from EXTRA_DIST
This breaks make distcheck otherwise since commit
7665dcf1 removed these files.
2015-08-14 15:54:14 +02:00
Frediano Ziglio
7665dcf1bb Remove files moved to spice-protocol
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-08-11 10:26:06 +02:00
Christophe Fergeau
f88a7b7bec Use installed spice-protocol for code generation
Now that spice-protocol ships the needed .proto files as well as the
corresponding python scripts, spice-common can use these in order to
generate the C code for the SPICE (de)marshallers.
2015-08-11 10:26:06 +02:00
Christophe Fergeau
c48b0a0672 Remove spice-protocol submodule
spice-protocol is a separate project which is having releases, so there
is no need to have a private spice-protocol copy in each spice-common
user, especially as after installation, the system-wide spice-protocol
copy will be used instead of the private one the module was built
against.
2015-08-11 10:26:06 +02:00
Uri Lublin
53f7f543f9 codegen: ptypes.py: keep attribute names in sets
This patch changes the type of 'valid_attributes' and
'attributes_with_arguments'.
Both of them are list of different strings and are kept in sets.

This was the intention of the original code, but this patch
use a specific set([ strings ]) format, instead of { strings }.

This fixes the build for me on RHEL-6 (python-2.6.6).
Build error is:

File "/home/ulublin/git/spice/spice-common/python_modules/ptypes.py",
line 67
      'end',
           ^
SyntaxError: invalid syntax
2015-08-04 20:10:22 +03:00
Christophe Fergeau
f2ed9a35a2 Update spice-protocol submodule
Christophe Fergeau (3):
      Prepare for spice-protocol 0.12.8 release
      Post-release version bump
      Rename SpiceImageCompress constants

Sandy Stutsman (1):
      Add QXL_ESCAPE_MONITOR_CONFIG enum
2015-07-29 17:30:09 +02:00
Frediano Ziglio
a1d1d396cd codegen: Allow to specify C type for index variable
This is to prepare to generate the wireshark dissector which uses
glib types instead of the newer C ones (for compatibility with some
compilers).

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:22:11 +02:00
Frediano Ziglio
f717273002 codegen: Check we don't pop too many indexes 2015-07-23 11:22:11 +02:00
Frediano Ziglio
f0f578abee codegen: Remove old ptr32 attribute
This attribute is not used in code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:22:11 +02:00
Frediano Ziglio
eff8b1a0e4 codegen: Do some checks on attributes
Verify that the attribute is known. This could help for instance to
avoid some future typo mistakes.
We also now have a list of attributes that we can comment for
documentation purpose.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:20:19 +02:00
Frediano Ziglio
179928fceb codegen: Reuse code to fix attribute from prototype file
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:11:47 +02:00
Frediano Ziglio
365866c4c9 codegen: Remove duplicate variable initialization
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:11:44 +02:00
Frediano Ziglio
0130e8dc39 codegen: Optimize code indentation and avoid a loop
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:11:18 +02:00
Frediano Ziglio
184feb541a codegen: Fix typo in variable name
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:11:16 +02:00
Frediano Ziglio
aa43c0d61e codegen: Simplify if/else blocks
Blocks were mainly the same, this reduces the amount of code.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:11:03 +02:00
Frediano Ziglio
86b0568055 codegen: Import six module before first use
The module is used in the initial try/except so make sure it is
already imported.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
2015-07-23 11:10:57 +02:00
Christophe Fergeau
f4c729aad3 codegen: Fix enums.h generation with python3
Trying to generate enums.h with python3 results in
Traceback (most recent call last):
  File "./spice_codegen.py", line 217, in <module>
    write_enums(writer, options.generate_dissector)
  File "./spice_codegen.py", line 99, in write_enums
    write_channel_enums(writer, c, False, False)
  File "./spice_codegen.py", line 17, in write_channel_enums
    if len(messages) == 0:
TypeError: object of type 'filter' has no len()

filter() returns an enumerator object in python3 while it used to return
a list in python2. Using list(filter()) instead fixes that error.
I've checked that the generated enums.h is identical with python2 and
python3.
2015-07-23 10:29:10 +02:00
Christophe Fergeau
5720971c45 proto: Remove space before tab
There are 3 lines in spice.proto/spice1.proto which start with spaces
and then contain a tab. This commit removes the spaces and only keep the
tab.
2015-07-20 20:55:47 +02:00
Christophe Fergeau
2d054e0e69 m4: Add compat AS_VAR_APPEND for older autoconf
This causes failures on EL6 otherwise as autoconf is too old there.
2015-07-02 17:02:21 +02:00
Lukas Venhoda
6183bbde24 ppc: Fix quic magic endianess
Runtime conversion from a string to uint32 is storing the magic with the same
endianness on both LE and BE machines. This requires aditional byte swap
when sending magic between LE/BE machines.

Changing quic magic to a constant will ensure, that it will be always stored in
native endianness, and the second byte swap won't be needed.
2015-07-02 13:31:28 +02:00
Lukas Venhoda
5a7e5876e6 ppc: Fix lz magic endianess
Commit d39dfbfe changes lz magic to be always treated as LE when encoded.

Runtime conversion from a string to uint32 is storing the magic with the same
endianness on both LE and BE machines. This requires aditional byte swap
when sending magic between LE/BE machines.

Changing lz magic to a constant will ensure, that it will be always stored in
native endianness, and the second byte swap won't be needed.

This commit reverts d39dfbfe changes in lz.c while keeping the rest.
They will be needed in future commit for quic.c
2015-07-02 13:31:28 +02:00
Lukas Venhoda
c04d4d55bc ppc: Fix quic decode endianess
Converts all decoded words in quic from little endian to local
machine endianness.
2015-07-02 13:31:28 +02:00
Christophe Fergeau
dcebede0ca Update spice-protocol
Christophe Fergeau (1):
      Post-release version bump

Javier Celaya (2):
      Update enums.h for preferred compression message
      Add a preferred compression capability
2015-06-22 20:04:21 +02:00
Javier Celaya
127a76a3b8 Proto: Add preferred compression message and constants.
When accessing a virtual desktop from different devices, some may have
different image compression requirements, e.g. slow devices may prefer
the faster LZ4 over GLZ. This message instructs the server to switch the
image compression algorithm. This patch also promotes the
SPICE_IMAGE_COMPRESS_* constants so that they are available from both
the server and the client.
2015-06-22 19:54:30 +02:00
Christophe Fergeau
1b5edbe49e m4: Add macro for --enable-lz4
It's not directly used by spice-common, but this way spice-gtk and
spice-server can share the same implementation.
2015-06-17 19:25:05 +02:00
Victor Toso
fec803156b Update spice-protocol submodule
This includes volume synchronization protocol;
2015-04-24 17:17:59 +02:00
Christophe Fergeau
b216f66f10 codegen: Use six.PY3 rather than six.PY2
Older versions of python-six (at least 1.3.0) defined six.PY3 but not
six.PY2. six.PY2 is only used twice in straightforward tests so it's
easy to use six.PY3 instead.
2015-04-14 16:08:43 +02:00
Christophe Fergeau
838ec7d87b configure.ac: Check for needed python modules for git builds
After the patch adding support for python 3 to the code generator,
python-six is required when building from git. Since I got 2 different
reports of SPICE build failures right after introducing it, it's
probably better to check for the needed python modules from configure,
and exit with an error if they are missing.
This commit adds a --enable-python-checks configure flag for that
though, since we only want to do that when building from git. It assumes
that people running from git will be running autogen.sh, while people
building from tarballs will run configure.
2015-04-13 13:08:11 +02:00
Erlon Cruz
c6e6dacb30 ppc: build-sys: Add big-endian support
A few files (the generated marshalling code and pixman-related utils)
make use of WORDS_BIGENDIAN in order to do the right thing depending on
endianness. configure.ac must call AC_C_BIGENDIAN for it to be defined.

Signed-off-by: Erlon R. Cruz <erlon.cruz@br.flextronics.com>
Signed-off-by: Rafael F. Santos <fonsecasantos.rafael@gmail.com>
Signed-off-by: Fabiano Fidêncio <Fabiano.Fidêncio@fit-tecnologia.org.br>
2015-04-10 20:20:49 +02:00
Erlon Cruz
d39dfbfef9 ppc: Fix lz magic endianness
Signed-off-by: Erlon R. Cruz <erlon.cruz@br.flextronics.com>
Signed-off-by: Rafael F. Santos <fonsecasantos.rafael@gmail.com>
Signed-off-by: Fabiano Fidêncio <Fabiano.Fidêncio@fit-tecnologia.org.br>
2015-04-10 20:20:49 +02:00
Alexander Wauck
ba52c4cae2 Make spice_codegen.py work on both Python 2 and 3
This is a new version of my previous patch that does not include six.py.
It's still kind of big, but at least it's all spice-common changes now.
There are also a few other fixes that Christophe brought to my attention.
Note that six now needs to be installed on the system (python-six on
Fedora and Debian, six on PyPI).

This *should* be enough to make spice_codegen.py work on both Python 2
and Python 3.  The major changes are as follows:

 * cStringIO.StringIO -> io.StringIO
 * str vs. unicode updates (io.StringIO doesn't like str)
 * integer division
 * foo.has_key(bar) -> bar in foo
 * import internal_thing -> from . import internal_thing
 * removed from __future__ import with_statement
   (might break Python 2.5?)
 * changed some lambdas to list comprehensions (done by 2to3)
 * cast some_dict.keys() to list where needed (e.g. for sorting)
 * use normal type names with isinstance instead of types.WhateverType

Signed-off-by: Alexander Wauck <awauck@codeweavers.com>
2015-04-01 13:39:03 +02:00
Christophe Fergeau
14218d7d6b ssl_verify: Move wincrypt.h related #ifdef closer to the include
Both wincrypt.h and openssl try to define X509_NAME. The wincrypt.h one
is not useful for us, so we currently #undef it if this was set.
However, it's done very late, right before including x509v3.h which
defines the X509_NAME type. Any header included in between may try to
 #include x509v3.h so it's better to undefine X509_NAME right after
including wincrypt.h.
2015-03-26 10:15:04 +01:00
Christophe Fergeau
edac1b36b5 Get rid of SW_CANVAS_IMAGE_CACHE
Every time it's used, it's in constructs similar to:

 #ifdef SW_CANVAS_CACHE
                             , SpiceImageCache *bits_cache
                             , SpicePaletteCache *palette_cache
 #elif defined(SW_CANVAS_IMAGE_CACHE)
                             , SpiceImageCache *bits_cache
 #endif

This can be rewritten as:

                             , SpiceImageCache *bits_cache
 #ifdef SW_CANVAS_CACHE
                             , SpicePaletteCache *palette_cache
 #endif

allowing to get rid of SW_CANVAS_IMAGE_CACHE.
2015-03-26 10:15:04 +01:00
Christophe Fergeau
d2ee99e15f Remove another redundant (SW_CANVAS_CACHE) || (SW_CANVAS_IMAGE_CACHE) #ifdef 2015-03-26 10:15:04 +01:00
Fabiano Fidêncio
37325b4e88 Fix typo in pixman_image_get_stride() function
pixman_image_surface_get_stride -> pixman_image_get_stride
2015-02-25 17:25:03 +01:00
Javier Celaya
3aad79d9c6 LZ4: Do not include arpa/inet.h in Windows builds 2015-02-03 13:28:54 +01:00
Javier Celaya
9287e53b6c LZ4: Add support for 24bit pixman surfaces 2015-02-03 10:46:34 +01:00
Javier Celaya
d167e2ead8 LZ4: Fix the row alignment when it is not on a 32bit boundary
Fix the row alignment for 16/24 bpp images when it is not in a 32bit
boundary. This is needed for 16bpp images when the width is an odd
number, and for the future support of 24bpp images.
2015-02-03 10:46:34 +01:00
Javier Celaya
f76fc28fc5 LZ4: Decode the image format from the stream 2015-02-03 10:43:31 +01:00
Javier Celaya
83c0d642ed LZ4: Adjust reading the top_down flag
Adjust the way the top_down flag is read to the corresponding change in
the wire protocol.
2015-02-03 10:43:31 +01:00
Javier Celaya
6049db492f LZ4: Fix output buffer size 2015-02-03 10:43:31 +01:00
Christophe Fergeau
ac26fd7acb Remove redundant #if defined(SW_CANVAS_CACHE) || defined(SW_CANVAS_IMAGE_CACHE)
SW_CANVAS_CACHE is always defined when building spice-gtk,
SW_CANVAS_IMAGE_CACHE is always defined when building spice-server, and
they are the only 2 users of spice-common. Moreover, build when none of
these is defined is broken.
2015-01-23 16:24:04 +01:00
Christophe Fergeau
062bf67442 Remove unused 'invers' arg from canvas_get_*
All canvas_get_{quic,jpeg,lz4,jpeg_alpha,lz} methods have an 'invers'
argument, but are always called with that argument being 0, so we can
drop it from the argument list, and remove the code triggerring when
it's true.
2015-01-23 16:24:03 +01:00
Victor Toso
619b99511d common: fix build with mingw 2015-01-06 18:02:50 +01:00
Christophe Fergeau
862b9b1a9e build-sys: Move pixman check to m4 macro 2014-12-09 16:40:25 +01:00
Christophe Fergeau
137b1a549e build-sys: Move opengl check to m4 macro 2014-12-09 16:40:25 +01:00
Christophe Fergeau
f9e0a644ae build-sys: Move opus check to m4 macro 2014-12-09 16:40:25 +01:00
Christophe Fergeau
dd57d05a52 build-sys: Move celt check to m4 macro 2014-12-09 16:40:25 +01:00
Christophe Fergeau
fb3fe2272c build-sys: Move smartcard check to m4 macro 2014-12-09 16:38:03 +01:00
Christophe Fergeau
df74a17238 build-sys: Move posix checks to a separate m4 macro 2014-12-09 16:37:21 +01:00
Christophe Fergeau
2f1ba3b77f build-sys: Add fallback for AS_VAR_APPEND
This macro is not available with RHEL6 autoconf.
2014-12-09 16:37:21 +01:00
Christophe Fergeau
2195369372 build-sys: Small cleanup of AM_CPPFLAGS
Commit 4fafa210 added WARN_CFLAGS, VISIBILITY_HIDDEN_CFLAGS and
-std=gnu99 to AM_CFLAGS in common/Makefile.am, but these are not
needed. WARN_CFLAGS and VISIBILITY_HIDDEN_CFLAGS are not defined
anywhere in spice-common, and spice-common compiles fine without
-std=gnu99 on my f21 box.
2014-12-09 16:37:18 +01:00
Christophe Fergeau
ed873a9eb5 build-sys: Remove unused WITH_SMARTCARD conditional 2014-12-08 18:26:39 +01:00
Christophe Fergeau
2da14b6cc8 build-sys: Remove unused win32 check 2014-12-08 18:24:59 +01:00
Christophe Fergeau
5bfa9cadb3 build-sys: Remove unused X check
AC_PATH_X sets a bunch of variables (x_includes, x_libraries, no_x)
after finding/not finding X. Since none of them are used afterwards,
having this check is not useful.
2014-12-08 18:24:59 +01:00
Christophe Fergeau
268d3e3d2f Remove unused header file
Nothing uses the definition it contains (I've tested spice-gtk and
spice)
2014-12-04 16:34:56 +01:00
Javier Celaya
5b3cdad921 Add LZ4 image compression support.
- Add a new LZ4 image type to spice.proto.
- Add canvas_get_lz4() to common_canvas_base, to get a pixmap from an
  lz4 image.
- Add an enable-lz4 switch to the configure script, disabled by default.
2014-12-02 19:23:53 +01:00
Christophe Fergeau
8639bbdc9d glc: Fix "warning: unused variable 'recreate'" 2014-11-24 11:24:49 +01:00
天外银龙
a74209a9c3 gdi: fix path segments drawing
Fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=64698
2014-11-10 11:38:22 +01:00
Victor Toso
c22fbffbc7 common: Fix -Wunused-variable
Fix a few warnings from unused variables when compiling spice-common
without OPUS or celt051.
2014-10-23 14:54:48 +02:00
Fabiano Fidêncio
fbdd4e41c0 common: Fix -Wmissing-field-initializers 2014-09-18 13:15:35 +02:00
Fabiano Fidêncio
6f3918ce7c common: Fix -Wsign-compare 2014-09-18 13:15:34 +02:00
Fabiano Fidêncio
c8b4c5ec49 common: Fix -Wunused-parameter 2014-09-18 13:15:29 +02:00
Fabiano Fidêncio
dde1c62a91 common: Remove dead code 2014-09-18 13:15:26 +02:00
Fabiano Fidêncio
840bcfe7a2 python: Fix -Wsign-compare
The return of the get_array_size() is used as a limit in a loop,
being compared with an unsigned index (indexes are always unsigned).
To avoid the -Wsign-compare warning, let's cast the return of the
get_array_size() to unsigned and make GCC happier.
2014-09-18 13:13:30 +02:00
Fabiano Fidêncio
9385db6875 python: Fix -Wunused-parameter
Although the most part of the parameters marked as unused are actually
being used for a few functions, a bunch of warnings can be seen when
the code is compiled with "-Wall -Wextra". As adding the unused attribute
means that the variable/parameter is meant to be *possibly* unused, we're
safe adding it in the generated code, even for used variables/parameters.
2014-09-18 13:13:27 +02:00
Fabiano Fidêncio
d45b3e2765 quic_family_tmpl: Fix "FORWARD_NULL" caught by coverity
Ensure the received bucket is non NULL
2014-07-23 17:20:30 +02:00
Fabiano Fidêncio
7e4cfbe305 quic: Fix "UNINIT" caught by coverity
In case of the model evolution mode has a obsolete or non-valid value,
just return, avoiding then the usage of non initalized variables.
2014-07-23 17:20:30 +02:00
Fabiano Fidêncio
2c5041c3f8 quic: Fix melcstate "OVERRUN" caught by coverity
Check for MELCSTATES - 1 to get inside the branch, otherwise
(...)->rgb_state.melcstate may be up to MELCSTATES after the
pre-incrementing, which would result in an access to a position
that is out bounds of the array size MELCSTATES.
2014-07-14 19:26:33 +03:00
Marc-André Lureau
dd4a446f5d demarshal: prefix variable name with parent names
Avoid naming clash if parent structures have the same name

https://bugzilla.redhat.com/show_bug.cgi?id=1021995
2014-05-15 14:21:48 +02:00
Christophe Fergeau
60046b309d Mark sw_canvas.[ch] as automake source files
These 2 files are not build as part of spice-common
build system, but modules using spice-common will build
them with the appropriate options. We need to let automake
know that these are source files so that it can properly
track these files dependencies.

Without this change, when eg spice-gtk switches to use 'subdir-objects'
to build sw_canvas.c as recommended by automake 1.14, the build
will fail because $(top_srcdir)/spice-common/common/.deps/sw_canvas.Plo
will not have been generated.
2014-05-07 13:01:12 +02:00
Christophe Fergeau
b3a00f4411 marshaller: Use #include <> for headers in $srcdir/common
Since the (de)marshallers are now generated in $builddir and not in
$srcdir, when these generated files include a file located in
$srcdir/common, the compiler will find them thanks to a -I directive, so it
makes more sense to use <> rather than "" when including them.
2014-04-16 16:47:55 +02:00
Christophe Fergeau
90a1240f27 Use #include "common/..." in (de)marshallers
Now that they are created in $builddir, their includes will need to refer
to files in $srcdir, which can be different. It's cleaner to add
-I $(top_srcdir)/spice-common/ to modules using spice-common rather than
having -I $(top_srcdir)/spice-common/common which would could create header
collisions.
2014-04-16 16:47:55 +02:00
Christophe Fergeau
7ea1cc54b1 Fix generation of marshallers in VPATH builds
The rules to generate the .c/.h (de)marshalling files have targets based in
$builddir, but the CLIENT_MARSHALLERS/SERVER_MARSHALLERS list refer to
files in $srcdir.
When using a $srcdir != $builddir, these $srcdir files will not exist, and
it will not be possible to generate them, which causes the build to fail.

When using $srcdir == $builddir from git or from tarballs, this will not
make a difference. When building from git, if $srcdir and $builddir are the
same, then the files will be found regardless of if we look for them in
$srcdir or $builddir as they are the same.
In tarballs, the files will be shipped with the tarball and thus available
in $srcdir. As $builddir is the same as $srcdir, the files will already
exist and not be regenerated.

The only change of behaviour will be when using a tarball and doing a
$srcdir != $builddir build. In this case, the files will need to be
regenerated, so the tools needed for that must be installed on the
machine doing the build.
2014-04-16 16:47:55 +02:00
Marc-André Lureau
6edeb43747 Update spice-protocol 2014-03-19 17:56:04 +01:00
Marc-André Lureau
01955e7007 spice.proto: add webdav channel
This channel provides a webdav server (rfc4918). This allows various
guest or remote system that support webdav to access a folder shared by
the client (some agent can be used to proxy the requests on a local port
for example). The webdav server may also be accessed by an hypervisor as
a remote filesystem interface, which can then be accessed by the guest
via other means (fs/fat emulation, mtp device, etc)

Due to the usage of a single channel stream and the need for concurrent
requests, webdav clients streams are multiplexed. Each client stream is
framed within 64k max messages (in little-endian)

 int64    client_id
 uint16   size
 char     data[size]

A new client_id indicates a new connection. A new communication stream
with the webdav server should be started. A client stream message of
size 0 indicates a disconnection of client_id. This multiplexed
communication happens over the channel "data" message.

Only when the port is opened may the communication be started.
A closed port event should close all currently known multiplexed
connections.

Why WebDAV?

webdav is supported natively by various OS for a long time (circa
Windows XP). It has several open-source implementations and a variety of
tools exist. A webdav implementation can be tested and used without a
Spice server or any virtualization (this also permit sharing the
implementation with other projects in the future, such as GNOME). It is
an IETF open standard and thus thoroughly specified.

The basic requirements for an efficient remote filesystem are provided
by the standard (pipelining, concurrency, caching, copy/move, partial
io, compression, locking ...) While other features are easily possible
via extensions to the protocol (common ones are executable attributes,
or searching for example).

Given the requirements, and the popularity of http/webdav, I believe it
is the best candidate for Spice remote filesystem support.

Other alternatives (adhoc, p9, smb2, sftp) have been studied and
discarded so far since they do not match in term of features or
requirements.
2014-03-19 14:47:04 +01:00
Christophe Fergeau
96ca358669 quic: Fix test which is always true
find_model_params() is first doing *nbuckets = 0; and it then checks
nbuckets for NULL. This is redundant as the dereferencing would cause a
segfault if nbuckets was NULL, so the if (nbuckets) test can't be false.
As Uri pointed out, the "/* bucket start */" comment on the same line
probably implies that the test was meant to be 'if (*nbuckets)'
I've ran a few test and I did not observe issues because of it...
2014-01-20 14:33:33 +01:00
Christophe Fergeau
6175014ed7 ssl: Don't use uninitialized variable in verify_subject()
If verify_subject() is called with a SpiceOpenSSLVerify struct containing a
non-NULL 'in_subject' member, it would try to use the local 'in_entries'
variable without having initialized it first. This could happen if
verify_subject() was called multiple time with the same SpiceOpenSSLVerify
context, which probably isn't occurring the way we are using it.

However, since verify_subject() is the only method which needs in_subject,
we don't need to have it stored in SpiceOpenSSLVerify, and we can
recreate it as needed locally in that method, which avoids that issue.
2014-01-07 13:55:58 +01:00
Christophe Fergeau
a4f4ddf56c mi: Fix shadow warnings
Based off a xserver commit from Yaakov Selkowitz:
http://cgit.freedesktop.org/xorg/xserver/commit/mi/mispans.c?id=f02e27e4fcc34413b2051e5a01edc92172fa8612
2014-01-07 13:55:51 +01:00
Christophe Fergeau
ae39a05620 mi: fix memory leak in miFillUniqueSpanGroup
This is based off the corresponding xserver commit from Tiago Vignatti:
http://cgit.freedesktop.org/xorg/xserver/commit/mi/mispans.c?id=7ae46b69ba3f05f46529131e6a864904967cde3a

Since xrealloc is #defined to spice_realloc which aborts on failure, this
block is dead code, but I prefer to stay as close as possible to the
upstream xserver code this is based on.
2014-01-07 13:55:51 +01:00
Christophe Fergeau
d8e49b71d4 mi: Avoid stack smash when drawing dashed lines
Based off Peter Harris's xserver commit
http://cgit.freedesktop.org/xorg/xserver/commit/mi/miwideline.c?id=20c2a3bcb11b5baf564e2c73a477ba23f5ae2b10
2014-01-07 13:55:51 +01:00
Christophe Fergeau
ead4b8810a quic: Add missing break; in switch/case
Unhandled values call an error callback, and then fall through the default:
case, which will call again the error callback. This commit adds some
break; after these cases to avoid this.
2014-01-07 13:55:51 +01:00
Christophe Fergeau
793e5d0350 backtrace: Don't attempt to call seteuid(0)
We are mostly likely not running as root, so this call will fail. As we are
supposed to check its return value as it's declared with
warn_unused_result, the current way of using it is wrong, so this commit just
removes the call.
2014-01-07 13:55:50 +01:00
Christophe Fergeau
6674e1c136 Remove unused variable
It was assigned a value, but then the value was never used.
2014-01-07 13:55:50 +01:00
Jeremy White
57ce430ccd Add support for the Opus codec.
Signed-off-by: Jeremy White <jwhite@codeweavers.com>
2014-01-02 12:28:21 +01:00
Jeremy White
c108e4ee8c Add a snd_codec interface to abstract the use of audio codecs such as celt.
Signed-off-by: Jeremy White <jwhite@codeweavers.com>
2014-01-02 12:25:23 +01:00
Marc-André Lureau
261d270cc8 Update spice-protocol 2013-11-19 17:46:56 +01:00
Jonathon Jongsma
1450bb4ddb Be explicit about spice-common license
Use same license as spice-gtk and spice modules (LGPL 2.1) since those licenses
applied to the spice-common submodule in the past.  This makes it more clear
that if you use spice-common separately, the license is still LGPL.  Also
mention license and copyright in generated files.
2013-10-23 11:41:43 -05:00
Jonathon Jongsma
31ef0c626d codegen: Add a --generate-wireshark-dissector option
The wireshark protocol dissector is a bit out-of-date. Several new channel types
and enums have been added.  It would be nice if these values (and the
translation between the value and the name) could be automatically generated so
that updating the dissector was a slightly less manual process.  This patch adds
a commandline switch which generates both the enums and value-name lists in the
format that wireshark expects.
2013-10-23 11:41:43 -05:00
Christophe Fergeau
fa640286f4 ssl: Don't try hostname check if cert subject check fails
Currently, SSL verification of the peer certificate checks if
the certificate's subject CN or one of its subjectAltName match
the hostname. If this succeeds, then the verification succeeds.
Otherwise openssl_verify() checks the cert subject if this was set,
which means it checks the certificate's subject (not just its CN) matches
exactly the cert subject string that is set in SpiceSession.

Given that the cert subject is something the user specifies in addition
to the hostname, the cert subject check should have priority over the
hostname check, that is, when we have a cert subject set, the
success/failure of the cert subject cert should determine the
success/failure of openssl_verify(), and the hostname check
should only be carried out when no cert subject was set.

This fixes rhbz#871034
2013-10-11 10:21:54 +02:00
Christophe Fergeau
9b3e972cdc ssl: Log an error when peer certificate verification failed
We currently log an error when openssl_verify() is called with
preverify_ok set to 0 for all certificates in the certificate chain
except for the peer certificate (when 'depth' is 0).
This commit logs an error in the latter case as well.
2013-10-11 10:21:54 +02:00
Christophe Fergeau
b34169feb6 ssl: Improve error message in cert chain verification
It contains the same information as before, but should be more readable.
2013-10-11 10:21:54 +02:00
Marc-André Lureau
7e8ba10779 Remove INLINE usage
Since inline is c99 and its already used in some files
2013-10-04 12:45:00 +02:00
Marc-André Lureau
e443c9f603 gl: use glCopyPixels()
I don't see why the fallback method should be the default.

glCopyTexImage2D and glCopyPixels are equally broken with current Intel
mesa/drivers (I'll be filing a bug). But sw rendering is correct.
2013-09-30 02:18:37 +02:00
Marc-André Lureau
0aadda70d5 gl: cope with positive stride in put_image()
Keeping the warning, because I don't think this should happen anyway.
2013-09-30 02:18:37 +02:00
Marc-André Lureau
b6faccb381 gl: ignore alpha channel in draw_copy
Similar to sw canvas blit copy operation, and not a blend.
2013-09-30 02:18:37 +02:00
Marc-André Lureau
370ba35339 gl: ignore if mask has not bitmap
Similar to how sw canvas ignore mask if !bitmap in canvas_mask_pixman().
2013-09-30 02:18:37 +02:00
Marc-André Lureau
f88e851ed6 build-sys: add --enable-smartcard=auto
Use same implementation as spice-gtk, to avoid need to explicitely set
smartcard support
2013-09-26 19:03:31 +02:00
Marc-André Lureau
3363fe79f9 Update spice-protocol 2013-09-12 13:52:27 +02:00
Marc-André Lureau
4857653686 quic: precompute golomb codes
We can avoid repetitive computation by using two precomputed array, of
8k each.

before:
     1.79%  lt-spicy-stats  libspice-client-glib-2.0.so.8.4.0  [.]
     golomb_code_len_8bpc

after:
     0.79%  lt-spicy-stats  libspice-client-glib-2.0.so.8.4.0  [.]
     golomb_code_len_8bpc
2013-09-12 13:49:25 +02:00
Marc-André Lureau
8db88d2854 quic: compile with constant bpp
This simplifies a little bit function calling, and allows for compiler
to potentially specialize and optimize a bit better each version.
2013-09-12 13:49:25 +02:00
Marc-André Lureau
a7b93bd43d canvas: use precomputed revers_bits
Thos function shows up in some profiling results, it seems we can
trivially replace it with a precomputed array of 256bytes.

before:
     5.66%           691  lt-spicy-stats
libspice-client-glib-2.0.so.8.4.0  [.] revers_bits

after:
     0.53%            64  lt-spicy-stats
libspice-client-glib-2.0.so.8.4.0  [.] revers_bits
2013-09-12 13:49:25 +02:00
Marc-André Lureau
6440a1e533 proto: add fake last message in base channel
Make it explicit that 100 is the last value of the base channel
messages. This allows clients to use the generated enum value too.
2013-09-12 13:49:25 +02:00
Marc-André Lureau
4d8d2b6124 proto: comment future surface flags usage 2013-09-12 13:49:25 +02:00
Christophe Fergeau
ffc3e8a327 Fix min gcc version for __attribute__(format)
We currently use it only on gcc 4.5 or newer, but it was actually
introduced much earlier than that. It's documented in gcc 2.95.3
manual:
http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC84
and glib uses starting from gcc 2.2.5.
This commit uses the same minimum version as glib.

This was causing warnings on RHEL6 systems which have gcc 4.4.7
2013-08-20 10:38:07 +02:00
Uri Lublin
fe93908238 Update spice-protocol to 0.12.6 2013-07-10 17:53:20 +03:00
Hans de Goede
fc27fb20b8 Update spice-protocol
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2013-06-24 13:27:37 +02:00
Yonit Halperin
30e84783ca add SPICE_MSG_PLAYBACK_LATENCY
SPICE_MSG_PLAYBACK_LATENCY is intended for adjusting the
latency of the audio playback. It is used for synchronizing
the audio and video playback.
The corresponding capability is SPICE_PLAYBACK_CAP_LATENCY.
2013-04-22 11:34:49 -04:00
Yonit Halperin
7cdf8de00a add stream report messages
If the server & client support SPICE_DISPLAY_CAP_STREAM_REPORT,
the server first sends SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT. Then,
the client periodically sends SPICE_MSGC_DISPLAY_STREAM_REPORT
messages that supply the server details about the current quality of
the video streaming on the client side. The server analyses the
report and adjust the stream parameters accordingly.
2013-04-22 11:34:20 -04:00
Christophe Fergeau
5ebeee5114 Add compile-time check for lz arrays
In addition to Laszlo's commit fixing rhbz#928973, we can add
some compile-time assertion to lz_common.h to help catch similar
bugs in the future.
This uses gnulib's verify.h to make sure at compile-time that
the various constant arrays used in lz_common.h are of the expected
size.
I've checked that before Laszlo's patch, the assert triggers, and
that it's gone after it.
2013-04-10 09:53:51 +02:00
Laszlo Ersek
5aa31e753f supply missing IS_IMAGE_TYPE_* elements for LZ_IMAGE_TYPE_A8
The IS_IMAGE_TYPE_PLT and IS_IMAGE_TYPE_RGB arrays are supposed to decide
whether each image type is PLT or RGB. Dependent on the result, one of the
PLT_PIXELS_PER_BYTE and RGB_BYTES_PER_PIXEL arrays can be indexed.

Commit c0b048eb introduced the LZ_IMAGE_TYPE_A8 enum constant and grew the
RGB_BYTES_PER_PIXEL array by one element, but it missed to append a zero
to IS_IMAGE_TYPE_PLT, and a one to IS_IMAGE_TYPE_RGB. Do so now.

Related RHBZ: 928973.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
2013-04-10 09:53:51 +02:00
Yonit Halperin
b52948d792 region.c: fix region_bounds_intersects
region_bounds_intersects mistakingly ignored one of the input regions,
and compared the other region to itself.
2013-04-02 08:45:42 -04:00
Hans de Goede
063f4dd385 Update spice-protocol
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2013-03-07 11:50:42 +01:00
Hans de Goede
1a83284e9c Update spice-protocol
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2013-03-04 19:41:59 +01:00
Michael Tokarev
149bb89adb Address a compilation warning due to missing typecast
Author: Serge Hallyn <serge.hallyn@ubuntu.com>

This is a trivial typecast fix, -- all surrounding
lines cast lines_end to PIXEL* but one is apparently
forgotten.  This fixes a compiler warning about
incompatible types in assignment.
2013-02-07 19:49:18 +01:00
Michael Tokarev
9ffc614a6c spice-common: remove version construction
Version string isn't used anywhere in spice-common, and there's
no version for spice-common module per se, either.  Hoever,
configure.ac has this:

 AC_INIT([spice-common],
         [m4_esyscmd(build-aux/git-version-gen .tarball-version)],
         [spice-devel@lists.freedesktop.org])

But since git-version-gen script is not provided in spice-common
module, multiple error messages are produced when generating
configure (running autogen/autoreconf), like this:

  sh: ./build-aux/git-version-gen: not found

(repeated about 50 times).

The following trivial patch removes usage of build-aux/git-version-gen
from AC_INIT and replaces it with a string "noversion", to stop
these scary messages from being produced.

Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2013-02-07 19:33:14 +01:00
Yonit Halperin
df09927c3b canvas_base: fix not caching palettes that belong to images that are not rendered
Fixes: fedora 875348, 826036

When an image is not rendered, we still need to check if it contains
a palette that needs to be cached.
This bug caused the client to crash due to not finding palettes
in the cache.
2013-01-31 11:55:37 -05:00
Marc-André Lureau
c08e04b478 spice-protocol: updated submodule for new PROXY controller message 2013-01-28 15:44:54 +01:00
Hans de Goede
8a10919658 spice-common: Update spice-protocol to include VD_AGENT_CAP_SPARSE_MONITORS_CONFIG
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2013-01-18 14:26:49 +01:00
Dunrong Huang
81f40cca5f Update spice-protocol 2013-01-11 21:57:43 +01:00
Marc-André Lureau
b46d36bc1c Add a "port" channel
A Spice port channel carry arbitrary data between the Spice client and
the Spice server. It may be used to provide additional services on top
of a Spice connection. For example, a channel can be associated with
the qemu monitor for the client to interact with it, just like any
qemu chardev. Or it may be used with various protocols, such as the
Spice Controller.

A port kind is identified simply by its fqdn, such as org.qemu.monitor,
org.spice.spicy.test or org.ovirt.controller...

The channel is based on Spicevmc which simply tunnels data between
client and server. A few messages have been added:

SPICE_MSG_PORT_INIT: Describes the port state and fqdn name, should be
sent only once when the client connects.

SPICE_MSG_PORT_EVENT: Server port event. SPICE_PORT_EVENT_OPENED and
SPICE_PORT_EVENT_CLOSED are typical values when the chardev is opened
or closed.

SPICE_MSGC_PORT_EVENT: Client port event.
2012-12-05 11:24:05 +01:00
Marc-André Lureau
5f2e99c3da update spice-protocol 2012-12-05 11:24:05 +01:00
Alon Levy
be6392a5ad common/lz.c: improve lz_encode comment 2012-11-04 13:33:35 +02:00
Marc-André Lureau
8543d04cd2 ssl-verify: use more explicit error message
When the server certificate is not being signed by the provided CA,
the SSL debug message is currently for example:

ssl_verify.c:428:openssl_verify: openssl verify:num=19:self signed
certificate in certificate chain:depth=1:/C=IL/L=Raanana/O=Red
Hat/CN=my CA

Add a more explicit debug message too, as requested in bug:

https://bugzilla.redhat.com/show_bug.cgi?id=846666
2012-10-18 21:20:54 +02:00
Christophe Fergeau
222607814f Update spice-protocol submodule to 0.12.2 2012-09-21 15:53:09 +02:00
Christophe Fergeau
79502376d1 Update git.mk to latest version 2012-09-21 10:51:17 +02:00
Alon Levy
9b9592f80c Update spice-protocol module
Add support for client monitors config in qxl device.
2012-09-12 21:07:40 +03:00
Christophe Fergeau
f67bcd03e9 Update spice-protocol submodule
We need the latest spice-protocol to compile spice to get the A8
surface definitions
2012-09-10 10:45:26 +02:00
Marc-André Lureau
04dc2bee9e build-sys: remove Makefile from marshaller build dep
The release tarballs ship with the generated files to avoid extra
build work and dependency. However, build was still tiggering a
regenration, because of Makefile change.

Avoid required rebuild when running ./configure (generating Makefile),
there is no variable that could be tweaked, afaict.
2012-08-28 20:36:41 +02:00
Marc-André Lureau
86e286ba20 inputs: add a INPUTS_KEY_SCANCODE message
Add a new arbitrary keyboard scancodes message.

For now, it will be used to avoid unwanted key repeatition when there
is jitter in the network and too much time between DOWN and UP
messages, instead the client will send the press & release scancode in
a sequence.

See also: https://bugzilla.redhat.com/show_bug.cgi?id=812347
2012-08-27 17:12:07 +02:00
Alon Levy
2c55c9d0c6 configure.ac: support automake >= 1.12 2012-08-27 16:00:54 +03:00
Yonit Halperin
c2f58492ad support seamless migration
see spice-protocol for more details
commit 3838ad140a046c4ddf42fef58c9727ecfdc09f9f
2012-08-27 09:06:26 +03:00
Yonit Halperin
c6bd210ad0 add SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS
The msg is used for setting the number of allocated client tokens when
we notify the client that the agent is attached.
2012-08-27 09:02:05 +03:00
Søren Sandmann Pedersen
c0b048ebef Add support for A8 images to the LZ routines
This format is needed to add Render support to the X driver, so we
need the ability to compress and decompress it.
2012-08-24 13:37:51 -04:00
Søren Sandmann Pedersen
0c1b6de4ad canvas_utils: Make sure strides are aligned to multiple of 4
Pixman requires all strides to be aligned to a multiple of 4. With the
upcoming a8 images, this is not guaranteed anymore.
2012-08-13 11:54:04 -04:00
Marc-André Lureau
c2adbb00dc spice-common: don't install spice-protocol
Revert to usage of DIST_SUBDIRS to avoid make install under
spice-protocol. This is only possible since git.mk was fixed.
2012-08-09 12:44:41 +02:00
Marc-André Lureau
9768ebf80d Update git.mk to upstream version
wget https://raw.github.com/behdad/git.mk/master/git.mk
2012-08-09 12:44:41 +02:00
Marc-André Lureau
735e431671 build-sys: fix make distcheck
- don't try to overwrite read-only enums.h
- DIST_SUBDIRS is no longer needed
2012-07-16 17:35:08 +02:00
Alon Levy
7eba850ad5 support multiple monitors in single display channel
See spice-protocol commit for details:
 da908f89b581fd4725da997fdaea209f8e6548f6
 support multiple monitors on a single display channel
2012-07-12 19:50:40 +03:00
Alon Levy
b49c4794ee spice-protocol/spice/enums.h: rebuild from spice.proto
This file was hand generated until now, resulting in the wierd situation where
it is different for spice-gtk and spice-server even though they both use the
same spice-common and spice-protocol (or at least close) versions.

This patch generates the enums.h files from spice-common. While that file is
actually in the spice-protocol submodule, it cannot be generated from
spice-protocol since it lacks access to spice.proto and spice_codegen.py. So in
affect whenvever it will differ the spice-protocol module will become dirty and
hence hopefully commited with the new enums.h.

enums.h is generated from spice.proto is a superset of that generated from spice1.proto.
2012-07-08 18:12:18 +03:00
Alon Levy
2449260c81 common/log.h: add spice_info 2012-07-05 19:22:31 +03:00
Marc-André Lureau
f8f6231ecd Fix a gcc warning
warning: suggest explicit braces to avoid ambiguous 'else'
2012-06-30 02:54:53 +02:00
Marc-André Lureau
5020adc59f Fix invalid macro usage 2012-06-30 02:50:56 +02:00
Christophe Fergeau
bf5511033d ssl: more verbose output when SSL verification fails
This should make SSL connection failures easier to diagnose.
2012-06-25 14:59:59 +02:00
Alon Levy
800784df43 update spice-protocol for smartcard enums fix
d5d26cac49 broke spice-common by depending
on a local commit, fix it by depending on the now pushed commit.
2012-06-22 17:23:03 +03:00
Alon Levy
d40a181a20 Makefile.am: now that spice_codegen.py is used add *.pyc to ignored files in root 2012-06-20 16:25:33 +03:00
Alon Levy
9dff18a399 Makefile.am: fix .gitignore not being generated in spice-protocol/spice
By adding spice-protocol to SUBDIRS configure and make will be called in it.

Spotted by Marc-André.
2012-06-20 16:25:33 +03:00
Alon Levy
d5d26cac49 updated spice-protocol for smartcard enums non conflict with libcacard 2012-06-20 16:25:33 +03:00
Alon Levy
535b52db66 smartcard: build fixes for spice server
Define different enums that have a SPICE_ prefix to not conflict with same
value enums from libcacard/vsccard_common.h, and continue to use the same
SPICE_MSG_SMARTCARD_DATA and SPICE_MSGC_SMARTCARD_DATA enum that is used by the
server and clients (spice-gtk, spicec) alike.
2012-06-14 13:53:46 +03:00
Alon Levy
a976c16cf3 python_modules/ptypes.py/EnumBaseType.c_enumname: add missing return to fix broken enums generation
Fixes the resulting enums.h from the invocation of:
./spice_codegen.py --generate-enums spice.proto spice-protocol/spice/enums.h

Right now any enum will contain None as the enum members, with this fix
it will contain the real enum members, i.e. SPICE_FOO.
2012-06-14 13:53:46 +03:00
Marc-André Lureau
5f44094940 ssl-verify: add a bit of run-time checks
Even if they are not public functions, those conditions can be reached
in a invalid state.
2012-05-17 14:38:28 +02:00
Yonit Halperin
22fc0b0145 video streaming: add support for frames of different sizes
rhbz #813826, #815426

Add SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, for stream_data message
that also contains the size and destination box of the data.
The server can send such messages only to clients with
SPICE_DISPLAY_CAP_SIZED_STREAM.
2012-05-02 14:47:29 +03:00
Yonit Halperin
178c7eaff6 region: add region_extents 2012-05-02 14:47:27 +03:00
Yonit Halperin
cbf423f833 rect: add rect_debug 2012-05-02 14:47:26 +03:00
Yonit Halperin
ffeb6ce677 rect: add rect_get_area 2012-05-02 14:47:26 +03:00
Yonit Halperin
2e4b605272 rect: add rect_contains 2012-05-02 14:47:26 +03:00
Jeremy White
f37ba0d032 Set the clip type to reflect the on wire type. 2012-04-26 19:47:10 +03:00
Daniel P. Berrange
ff25524948 Add missing struct field initializers
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-04-25 14:23:31 +01:00
Aric Stewart
6af29a97ac move variable decleration to head of code block
Signed-off-by: Aric Stewart <aric@codeweavers.com>
2012-04-18 17:53:05 +03:00
Aric Stewart
6bb8d93bbf allow log.c to compile under MSVC++ 2012-04-18 16:54:33 +03:00
Aric Stewart
d77d056022 add padding member to SpiceMsgEmpty
Empty structures are undefined in C, gcc handles them without issue
assigning a size of 0. However MSVC++ generates a hard error (C2015)
this allows messages.h to be included in c files compiled by MSVC++.

Signed-off-by: Aric Stewart <aric@codeweavers.com>
2012-04-18 16:02:07 +03:00
Aric Stewart
7814bdf71d Add a return value to the default case in create_bitmap to satisfy VC++ 2012-04-17 10:17:10 +03:00
Christophe Fergeau
39fef7a5da demarshall: add missing parens in BE read_xxx functions
The missing parens causes build to fail on big-endian machines
2012-04-06 15:32:02 +02:00
Christophe Fergeau
e96dbb4172 Update spice-protocol submodule
We need the USB redirection controller messages
2012-04-04 10:20:00 +02:00
Hans de Goede
c678122d6a configure.ac: lower required autoconf version to 2.63
So that one can autogen.sh on RHEL-6.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2012-04-03 15:03:05 +02:00
Yonit Halperin
2ab866f522 update submodule spice-protocol
added the disable-effects and color-depth options to the controller

Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
2012-04-03 08:23:02 +03:00
Marc-André Lureau
e3f6941895 Bypass certicate verification failure if PUBKEY check only
During switch-host migration, only PUBKEY verification is required.
Couldn't it just load the certificate again for the new session?
perhaps, but that's they way the code used to work until I introduced
a regression in spice commit d46f9d3f4e006d3bca9b99fac25169b17e7ac803.
2012-03-30 14:10:00 +02:00
Marc-André Lureau
a0339261d4 ssl-verify: improve logging report in case of errors
Use the log.h system, and report a bit more information in the debug level
2012-03-30 14:10:00 +02:00
Marc-André Lureau
1b41d15a99 Fix harmless warnings in quic_encode()
The quic code has been changed recently this way:

-    ASSERT(encoder->usr, line);
+    if (line == NULL) {
+        spice_warn_if_reached();
+        return QUIC_ERROR;
+    }

It appears that the only caller of quic_encode() gives a NULL line and
rely on the more_lines() callback to return new lines instead.

Adjust the code accordingly, adding a few more checks to verify the
caller gives/returns correct values.
2012-03-28 13:30:18 +02:00
Marc-André Lureau
fb24e4e28b build-sys: split client marshallers in seperate lib 2012-03-25 18:38:09 +02:00
Marc-André Lureau
c1e4e1be63 build-sys: make it a seperately buildable spice-common library
- autotoolize
- fix headers inclusion
- generate gitignores
- workaround serverSMARTCARD support with dirty hack...
2012-03-22 20:21:05 +01:00
Marc-André Lureau
feaee86076 spice.proto: fix demarshaller crash with name message
It turned out the demarshaller wasn't allocating enough space to
memcpy the name. In order to take into account the size of a variable
array, it needs to be marked with the @end tag so that the
"extra_size" is added to the allocated memory.

It would be nice if the demarshaller would somehow fail if this wasn't
set explicitly, or do the right thing by default.

@end the name so that demarshaller
2012-03-21 13:24:17 +01:00
Marc-André Lureau
bc4f5db323 codegen: ifdef/endif function declaration too
Compile out part that we are not supporting.  In the future, we might
want to declare a fake type and an empty function to keep API
compatibility
2012-03-21 13:24:17 +01:00
Marc-André Lureau
b6afcd632e codegen: include headers locally 2012-03-21 13:24:17 +01:00
Marc-André Lureau
2d4e0d2000 codegen: struct marshallers are not current function helper
This solves the issue of struct_marshallers being included within the
current ifdef/endif body, although they are independant functions.
2012-03-21 13:24:16 +01:00
Christophe Fergeau
3df7798413 use new @ifdef directive for smartcard messages
We don't want to conditionally compile the smartcard messages
depending on whether USE_SMARTCARD is set or not, we can now use
the @ifdef attribute for that.
2012-03-20 15:31:30 +01:00
Christophe Fergeau
7f86151f18 add smartcard bits to spice.proto 2012-03-20 15:31:30 +01:00
Hans de Goede
69aecfc1bc spice_codegen: Always write a channels entry for an ifdef-ed channel
Before this patch, if a channel is defined conditionally in spice.proto
(because it depends on external headers like the smartcard channel),
spice_codegen would write an entry to the channels array in
spice_get_*_channel_parser which would only take up a place in the array
if the ifdef condition is true, thus moving up all other intializers
one place when it is not true. This was causing issues (crashes) when building
spice-gtk with the combination of usbredir support enabled and smartcard
support disabled.

This patch fixes this by adding #else { NULL, 0 }, to the generated code.

Thanks to coolper chen <lixin.chen@saicocch.com> for reporting this!

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
2012-03-20 15:31:30 +01:00
Christophe Fergeau
a7cc3c6a56 handle @ifdef on messages and channels 2012-03-20 15:31:30 +01:00
Christophe Fergeau
7307fccb71 allow attributes on channel elements in .proto files
We want to be able to add an @ifdef annotation to optional messages
For example, we want to compile in the smartcard messages only if
libcacard is available
2012-03-20 15:31:30 +01:00
Christophe Fergeau
eb01d2fc46 add ifdef/endif methods to spice code generator
These methods will be needed to be able to make some fields optional
in spice.proto
2012-03-20 15:31:30 +01:00
Christophe Fergeau
51cf6fce72 fix copy & paste error in ptypes.py 2012-03-20 15:31:30 +01:00
Marc-André Lureau
f7af6264ea Add SPICE_ATTR_NORETURN and use it for a few functions 2012-03-20 15:30:24 +01:00
Marc-André Lureau
a1df67b3c5 Fix build with SPICE_DISABLE_ABORT 2012-03-20 15:30:24 +01:00
Marc-André Lureau
13fb823795 Remove need for SPICE_CANVAS_INTERNAL
Why is this useful?
2012-03-20 15:30:24 +01:00
Marc-André Lureau
61c30fcdcf fix void* arithmetic
marshaller.c:528:50: error: pointer of type 'void *' used in arithmetic [-Werror=pointer-arith]
2012-03-20 15:30:24 +01:00
Marc-André Lureau
f87bb23ad2 build: replace INCLUDES with AM_CPPFLAGS
Fix warning `INCLUDES' is the old name for `AM_CPPFLAGS' (or `*_CPPFLAGS')
2012-03-20 15:30:24 +01:00
Daniel P. Berrange
fbb6b9984a Add missing includes & make some functions static
A number of functions were used without prior declaration. In
some cases this was due to missing include files. In other cases
the functions should have just been static.

Ideally this would allow -Wmissing-declarations to be enabled, but
the files generated by spice_codegen.py will still trip up on this.
2012-03-20 15:30:24 +01:00
Daniel P. Berrange
985ec9d6ec Add printf format annotations to all '...' functions
To allow the compile to detect incorrect printf formats, any
var-args function should have a format annotation

* common/macros.h: Helper to define ATTR_PRINTF for code
  which can't depend on glib
* common/canvas_base.c, common/lz.h, common/macros.h: Annotate
  some var-args methods
2012-03-20 15:30:24 +01:00
Daniel P. Berrange
9f7d6175e7 Fix some integer range checks which always evaluate false
There are some integer range checks which always evaluate false
due to use of unsigned integer types. One of these would prevent
detection of encoding errors from celt. The others are simply
no-ops.

* common/pixman_utils.c: SpiceROP is an enum & thus unsigned
2012-03-20 15:30:23 +01:00
Daniel P. Berrange
3bc7d096b6 Avoid warnings about empty conditional statement bodies
Add extra {} braces around if/else statements which only
call SPICE_DEBUG to avoid:

../common/ssl_verify.c: In function 'verify_pubkey':
../common/ssl_verify.c:87:50: warning: suggest braces around empty body in an 'else' statement [-Wempty-body]
../common/ssl_verify.c: In function 'verify_hostname':
../common/ssl_verify.c:254:53: warning: suggest braces around empty body in an 'if' statement [-Wempty-body]
../common/ssl_verify.c: In function 'verify_subject':
../common/ssl_verify.c:381:41: warning: suggest braces around empty body in an 'else' statement [-Wempty-body]
2012-03-20 15:30:23 +01:00
Marc-André Lureau
0a96fe9364 build: remove 'win' directory
Let's use the only included file directly instead.
2012-03-20 15:30:23 +01:00
Christophe Fergeau
4feaffad8e messages.h: add smartcard bits 2012-03-20 15:30:23 +01:00
Marc-André Lureau
508547c100 Add client_marshallers.h client_demarshallers.h from spice-gtk
spice-gtk uses a more up to date version of client/marshallers.h and client/demarshallers.h
2012-03-20 15:30:23 +01:00
Marc-André Lureau
c4482c7ff2 Use SPICE_{BEGIN,END}_DECLS 2012-03-20 15:30:23 +01:00
Christophe Fergeau
e800e51d4e add const to arrays in marshalling functions 2012-03-20 15:30:23 +01:00
Christophe Fergeau
c968e76f96 ssl_verify: include <string.h>
ssl_verify.c is using memcmp which comes from string.h, this was
breaking compilation with -Werror -Wall on Mac OS X
2012-03-20 15:30:23 +01:00
Marc-André Lureau
3e4b2571a2 ssl_verify: comment X509_NAME undef 2012-03-20 15:30:23 +01:00
Marc-André Lureau
c1403ee6bf Use a log handler to modify abort() behaviour
Be more library friendly, by not aborting in library errors.

spice_common now includes a proper log handler that will abort by
default when reaching a warning.

SPICE_ABORT_LEVEL can be changed to modify run-time abort level.

SPICE_DEBUG_LEVEL can be changed to be more verbose. By default, only
log level more importants than WARNING.

Only memory-related functions are allowed to abort(), since they are
not recoverable errors in the library.
2012-03-20 15:30:23 +01:00
Marc-André Lureau
bb133148d8 update gitignore 2012-03-20 15:30:23 +01:00
Marc-André Lureau
cf705650d4 common: remove unnecessary outdated c++ debug 2012-03-20 15:30:23 +01:00
Marc-André Lureau
124f767b94 common: ring.h should include stddef for NULL usage 2012-03-20 15:30:05 +01:00
127 changed files with 11562 additions and 12891 deletions

52
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,52 @@
image: fedora:latest
before_script:
- >
dnf install git libtool make libasan gawk
python3 python3-pyparsing glib-networking
meson ninja-build gdk-pixbuf2-devel
glib2-devel pixman-devel openssl-devel libjpeg-devel
libcacard-devel cyrus-sasl-devel lz4-devel opus-devel
gstreamer1-devel gstreamer1-plugins-base-devel
-y
- git clone ${CI_REPOSITORY_URL/spice-common.git/spice-protocol.git}
- meson --buildtype=release spice-protocol build-spice-protocol --prefix=/usr --werror
- ninja -C build-spice-protocol install
makecheck:
script:
- >
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
LDFLAGS='-fsanitize=address -lasan'
./autogen.sh --enable-extra-checks
- make
- make check || (cat tests/test-suite.log && exit 1)
meson-makecheck:
script:
- >
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
LDFLAGS='-fsanitize=address -lasan'
meson build -Dextra-checks=true || (cat build/meson-logs/meson-log.txt && exit 1)
- ninja -C build
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
make-win:
script:
- >
dnf install mingw64-gcc mingw64-pkg-config mingw64-pixman mingw64-openssl
mingw64-opus mingw64-glib2 mingw64-glib-networking mingw64-gdk-pixbuf
'wine-core(x86-64)'
-y
- mkdir spice-protocol/build
- (cd spice-protocol/build && mingw64-meson --werror && ninja install)
- NOCONFIGURE=yes ./autogen.sh
- export WINEPATH='Z:\usr\x86_64-w64-mingw32\sys-root\mingw\bin'
- >
PYTHON=python3
CFLAGS='-O2 -pipe -g -fsanitize=address -fno-omit-frame-pointer -Wframe-larger-than=40920'
LDFLAGS='-fsanitize=address -lasan'
mingw64-configure --enable-extra-checks
- make
- export LANG=en_US.UTF-8
- make LOG_COMPILER=wine check || (cat tests/test-suite.log && exit 1)

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "common/recorder"]
path = common/recorder
url = https://github.com/c3d/recorder.git

3
.gitpublish Normal file
View File

@ -0,0 +1,3 @@
[gitpublishprofile "default"]
to = spice-devel@lists.freedesktop.org
prefix = PATCH spice-common

502
COPYING Normal file
View File

@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

33
Makefile.am Normal file
View File

@ -0,0 +1,33 @@
NULL =
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = python_modules common docs
if ENABLE_TESTS
SUBDIRS += tests
endif
EXTRA_DIST = \
meson.build \
meson_options.txt \
spice_codegen.py \
spice.proto \
$(NULL)
DISTCLEANFILES = *.pyc
MAINTAINERCLEANFILES = \
$(srcdir)/INSTALL \
$(srcdir)/aclocal.m4 \
$(srcdir)/autoscan.log \
$(srcdir)/build-aux \
$(srcdir)/config.h.in \
$(srcdir)/m4/libtool.m4 \
$(srcdir)/m4/ltoptions.m4 \
$(srcdir)/m4/ltsugar.m4 \
$(srcdir)/m4/ltversion.m4 \
$(srcdir)/m4/lt~obsolete.m4 \
`find "$(srcdir)" -type f -name Makefile.in -print` \
$(NULL)
-include $(top_srcdir)/git.mk

17
autogen.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
set -e # exit on errors
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
olddir=`pwd`
cd "$srcdir"
mkdir -p m4
autoreconf --verbose --force --install
cd "$olddir"
if [ -z "$NOCONFIGURE" ]; then
"$srcdir"/configure --enable-maintainer-mode --enable-python-checks ${1+"$@"}
fi

9
common/.gitignore vendored
View File

@ -1,9 +0,0 @@
*.la
*.lo
*.loT
*.o
.deps
.dirstamp
.libs
Makefile
Makefile.in

View File

@ -1,27 +1,44 @@
if OS_WIN32
SUBDIRS = win
endif
NULL =
noinst_LTLIBRARIES = libspice-common.la
# Avoid need for python(pyparsing) by end users
CLIENT_MARSHALLERS = \
generated_client_demarshallers.c \
generated_client_marshallers.c \
generated_client_marshallers.h \
$(NULL)
SERVER_MARSHALLERS = \
generated_server_demarshallers.c \
generated_server_marshallers.c \
generated_server_marshallers.h \
$(NULL)
BUILT_SOURCES = $(CLIENT_MARSHALLERS) $(SERVER_MARSHALLERS)
noinst_LTLIBRARIES = libspice-common.la libspice-common-server.la libspice-common-client.la
libspice_common_la_SOURCES = \
bitops.h \
agent.c \
agent.h \
backtrace.c \
backtrace.h \
canvas_utils.c \
canvas_utils.h \
demarshallers.h \
draw.h \
lines.c \
lines.h \
log.c \
log.h \
lz.c \
lz.h \
lz_common.h \
lz_config.h \
macros.h \
marshaller.c \
marshaller.h \
mem.c \
mem.h \
messages.h \
mutex.h \
pixman_utils.c \
pixman_utils.h \
quic.c \
@ -33,44 +50,112 @@ libspice_common_la_SOURCES = \
ring.h \
rop3.c \
rop3.h \
spice_common.h \
ssl_verify.c \
ssl_verify.h \
backtrace.c \
backtrace.h \
snd_codec.c \
snd_codec.h \
udev.c \
udev.h \
utils.c \
utils.h \
verify.h \
recorder.h \
$(NULL)
if SUPPORT_GL
libspice_common_la_SOURCES += \
gl_utils.h \
glc.h \
glc.c \
ogl_ctx.h \
ogl_ctx.c \
if ENABLE_RECORDER
libspice_common_la_SOURCES += \
recorder/recorder.c \
recorder/recorder.h \
recorder/recorder_ring.c \
recorder/recorder_ring.h \
$(NULL)
endif
INCLUDES = \
$(GL_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(PROTOCOL_CFLAGS) \
$(VISIBILITY_HIDDEN_CFLAGS) \
$(WARN_CFLAGS) \
-std=gnu99 \
if ENABLE_AGENT_INTERFACE
libspice_common_la_SOURCES += \
agent_interface.c \
agent_interface.h \
$(NULL)
endif
EXTRA_DIST = \
canvas_base.c \
canvas_base.h \
gdi_canvas.c \
gdi_canvas.h \
gl_canvas.c \
gl_canvas.h \
# These 2 files are not build as part of spice-common
# build system, but modules using spice-common will build
# them with the appropriate options. We need to let automake
# know that these are source files so that it can properly
# track these files dependencies
EXTRA_libspice_common_la_SOURCES = \
sw_canvas.c \
sw_canvas.h \
$(NULL)
libspice_common_client_la_SOURCES = \
client_marshallers.h \
ssl_verify.c \
ssl_verify.h \
$(CLIENT_MARSHALLERS) \
$(NULL)
libspice_common_client_la_LIBADD = \
$(GIO2_LIBS) \
$(NULL)
libspice_common_server_la_SOURCES = \
$(SERVER_MARSHALLERS) \
$(NULL)
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir) \
$(SPICE_COMMON_CFLAGS) \
$(PROTOCOL_CFLAGS) \
$(NULL)
libspice_common_la_LIBADD = \
$(SPICE_COMMON_LIBS) \
$(UDEV_LIBS) \
$(NULL)
MARSHALLERS_DEPS = \
$(top_srcdir)/python_modules/__init__.py \
$(top_srcdir)/python_modules/codegen.py \
$(top_srcdir)/python_modules/demarshal.py \
$(top_srcdir)/python_modules/marshal.py \
$(top_srcdir)/python_modules/ptypes.py \
$(top_srcdir)/python_modules/spice_parser.py \
$(top_srcdir)/spice_codegen.py \
$(NULL)
# Note despite being autogenerated these are not part of CLEANFILES, they are
# actually a part of EXTRA_DIST, to avoid the need for pyparser by end users
generated_client_demarshallers.c generated_messages.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common/messages.h \
--generated-declaration-file generated_messages.h $< $@ >/dev/null
generated_client_marshallers.c generated_client_marshallers.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P --include common/client_marshallers.h --client \
--generate-header $< $@ >/dev/null
generated_server_demarshallers.c: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include common/messages.h $< $@ >/dev/null
STRUCTS = -M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlend -M Composite
generated_server_marshallers.c generated_server_marshallers.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server --include common/messages.h \
--generate-header $< $@ >/dev/null
EXTRA_DIST = \
$(CLIENT_MARSHALLERS) \
$(SERVER_MARSHALLERS) \
generated_messages.h \
meson.build \
canvas_base.c \
canvas_base.h \
lz_compress_tmpl.c \
lz_decompress_tmpl.c \
quic_family_tmpl.c \
quic_rgb_tmpl.c \
quic_tmpl.c \
$(NULL)
GITIGNOREFILES = \
generated_messages.h \
$(NULL)
-include $(top_srcdir)/git.mk

361
common/agent.c Normal file
View File

@ -0,0 +1,361 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2020 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "agent.h"
#ifdef _WIN32
// Windows is always little endian
# define FIX_ENDIAN16(x) (x) = (x)
# define FIX_ENDIAN32(x) (x) = (x)
# define FIX_ENDIAN64(x) (x) = (x)
#else
# include <glib.h>
# define FIX_ENDIAN16(x) (x) = GUINT16_FROM_LE(x)
# define FIX_ENDIAN32(x) (x) = GUINT32_FROM_LE(x)
# define FIX_ENDIAN64(x) (x) = GUINT64_FROM_LE(x)
#endif
#include <spice/start-packed.h>
typedef struct SPICE_ATTR_PACKED {
uint16_t v;
} uint16_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
uint32_t v;
} uint32_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
uint64_t v;
} uint64_unaligned_t;
#include <spice/end-packed.h>
static const int agent_message_min_size[] =
{
-1, /* Does not exist */
sizeof(VDAgentMouseState), /* VD_AGENT_MOUSE_STATE */
sizeof(VDAgentMonitorsConfig), /* VD_AGENT_MONITORS_CONFIG */
sizeof(VDAgentReply), /* VD_AGENT_REPLY */
sizeof(VDAgentClipboard), /* VD_AGENT_CLIPBOARD */
sizeof(VDAgentDisplayConfig), /* VD_AGENT_DISPLAY_CONFIG */
sizeof(VDAgentAnnounceCapabilities), /* VD_AGENT_ANNOUNCE_CAPABILITIES */
sizeof(VDAgentClipboardGrab), /* VD_AGENT_CLIPBOARD_GRAB */
sizeof(VDAgentClipboardRequest), /* VD_AGENT_CLIPBOARD_REQUEST */
sizeof(VDAgentClipboardRelease), /* VD_AGENT_CLIPBOARD_RELEASE */
sizeof(VDAgentFileXferStartMessage), /* VD_AGENT_FILE_XFER_START */
sizeof(VDAgentFileXferStatusMessage), /* VD_AGENT_FILE_XFER_STATUS */
sizeof(VDAgentFileXferDataMessage), /* VD_AGENT_FILE_XFER_DATA */
0, /* VD_AGENT_CLIENT_DISCONNECTED */
sizeof(VDAgentMaxClipboard), /* VD_AGENT_MAX_CLIPBOARD */
sizeof(VDAgentAudioVolumeSync), /* VD_AGENT_AUDIO_VOLUME_SYNC */
sizeof(VDAgentGraphicsDeviceInfo), /* VD_AGENT_GRAPHICS_DEVICE_INFO */
};
static AgentCheckResult
agent_message_check_size(const VDAgentMessage *message_header,
const uint32_t *capabilities, uint32_t capabilities_size)
{
if (message_header->protocol != VD_AGENT_PROTOCOL) {
return AGENT_CHECK_WRONG_PROTOCOL_VERSION;
}
if (message_header->type >= SPICE_N_ELEMENTS(agent_message_min_size) ||
agent_message_min_size[message_header->type] < 0) {
return AGENT_CHECK_UNKNOWN_MESSAGE;
}
uint32_t min_size = agent_message_min_size[message_header->type];
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
switch (message_header->type) {
case VD_AGENT_CLIPBOARD_GRAB:
case VD_AGENT_CLIPBOARD_REQUEST:
case VD_AGENT_CLIPBOARD:
case VD_AGENT_CLIPBOARD_RELEASE:
min_size += 4;
}
}
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)
&& message_header->type == VD_AGENT_CLIPBOARD_GRAB) {
min_size += 4;
}
switch (message_header->type) {
case VD_AGENT_MONITORS_CONFIG:
case VD_AGENT_FILE_XFER_START:
case VD_AGENT_FILE_XFER_DATA:
case VD_AGENT_CLIPBOARD:
case VD_AGENT_CLIPBOARD_GRAB:
case VD_AGENT_AUDIO_VOLUME_SYNC:
case VD_AGENT_ANNOUNCE_CAPABILITIES:
case VD_AGENT_GRAPHICS_DEVICE_INFO:
case VD_AGENT_FILE_XFER_STATUS:
if (message_header->size < min_size) {
return AGENT_CHECK_INVALID_SIZE;
}
break;
case VD_AGENT_MOUSE_STATE:
case VD_AGENT_DISPLAY_CONFIG:
case VD_AGENT_REPLY:
case VD_AGENT_CLIPBOARD_REQUEST:
case VD_AGENT_CLIPBOARD_RELEASE:
case VD_AGENT_MAX_CLIPBOARD:
case VD_AGENT_CLIENT_DISCONNECTED:
if (message_header->size != min_size) {
return AGENT_CHECK_INVALID_SIZE;
}
break;
default:
return AGENT_CHECK_UNKNOWN_MESSAGE;
}
return AGENT_CHECK_NO_ERROR;
}
static void uint16_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
{
uint32_t i;
uint16_unaligned_t *msg = (uint16_unaligned_t *)(_msg + offset);
/* size % 2 should be 0 - extra bytes are ignored */
for (i = 0; i < size / 2; i++) {
FIX_ENDIAN16(msg[i].v);
}
}
static void uint32_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
{
uint32_t i;
uint32_unaligned_t *msg = (uint32_unaligned_t *)(_msg + offset);
/* size % 4 should be 0 - extra bytes are ignored */
for (i = 0; i < size / 4; i++) {
FIX_ENDIAN32(msg[i].v);
}
}
static void
agent_message_clipboard_from_le(const VDAgentMessage *message_header, uint8_t *data,
const uint32_t *capabilities, uint32_t capabilities_size)
{
size_t min_size = agent_message_min_size[message_header->type];
uint32_unaligned_t *data_type = (uint32_unaligned_t *) data;
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
min_size += 4;
data_type++;
}
switch (message_header->type) {
case VD_AGENT_CLIPBOARD_REQUEST:
case VD_AGENT_CLIPBOARD:
FIX_ENDIAN32(data_type->v);
break;
case VD_AGENT_CLIPBOARD_GRAB:
uint32_from_le(data, message_header->size - min_size, min_size);
break;
case VD_AGENT_CLIPBOARD_RELEASE:
// empty
break;
}
}
static void
agent_message_file_xfer_from_le(const VDAgentMessage *message_header, uint8_t *data)
{
uint32_unaligned_t *id = (uint32_unaligned_t *)data;
FIX_ENDIAN32(id->v);
id++; // result
switch (message_header->type) {
case VD_AGENT_FILE_XFER_DATA: {
VDAgentFileXferDataMessage *msg = (VDAgentFileXferDataMessage *) data;
FIX_ENDIAN64(msg->size);
break;
}
case VD_AGENT_FILE_XFER_STATUS: {
VDAgentFileXferStatusMessage *msg = (VDAgentFileXferStatusMessage *) data;
FIX_ENDIAN32(msg->result);
// from client/server we don't expect any detail
switch (msg->result) {
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
sizeof(VDAgentFileXferStatusNotEnoughSpace)) {
VDAgentFileXferStatusNotEnoughSpace *err =
(VDAgentFileXferStatusNotEnoughSpace*) msg->data;
FIX_ENDIAN64(err->disk_free_space);
}
break;
case VD_AGENT_FILE_XFER_STATUS_ERROR:
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
sizeof(VDAgentFileXferStatusError)) {
VDAgentFileXferStatusError *err =
(VDAgentFileXferStatusError *) msg->data;
FIX_ENDIAN32(err->error_code);
}
break;
}
break;
}
}
}
static AgentCheckResult
agent_message_graphics_device_info_check_from_le(const VDAgentMessage *message_header,
uint8_t *data)
{
uint8_t *const end = data + message_header->size;
uint32_unaligned_t *u32 = (uint32_unaligned_t *) data;
FIX_ENDIAN32(u32->v);
const uint32_t count = u32->v;
data += 4;
for (size_t i = 0; i < count; ++i) {
if ((size_t) (end - data) < sizeof(VDAgentDeviceDisplayInfo)) {
return AGENT_CHECK_TRUNCATED;
}
uint32_from_le(data, sizeof(VDAgentDeviceDisplayInfo), 0);
VDAgentDeviceDisplayInfo *info = (VDAgentDeviceDisplayInfo *) data;
data += sizeof(VDAgentDeviceDisplayInfo);
if (!info->device_address_len) {
return AGENT_CHECK_INVALID_DATA;
}
if ((size_t) (end - data) < info->device_address_len) {
return AGENT_CHECK_TRUNCATED;
}
info->device_address[info->device_address_len - 1] = 0;
data += info->device_address_len;
}
return AGENT_CHECK_NO_ERROR;
}
static AgentCheckResult
agent_message_monitors_config_from_le(const VDAgentMessage *message_header, uint8_t *message)
{
uint32_from_le(message, sizeof(VDAgentMonitorsConfig), 0);
VDAgentMonitorsConfig *vdata = (VDAgentMonitorsConfig*) message;
vdata->flags &= VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS|
VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE;
size_t element_size = sizeof(vdata->monitors[0]);
if ((vdata->flags & VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE) != 0) {
element_size += sizeof(VDAgentMonitorMM);
}
const size_t max_monitors =
(message_header->size - sizeof(*vdata)) / element_size;
if (vdata->num_of_monitors > max_monitors) {
return AGENT_CHECK_TRUNCATED;
}
uint32_from_le(message, sizeof(vdata->monitors[0]) * vdata->num_of_monitors,
sizeof(*vdata));
if ((vdata->flags & VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE) != 0) {
uint16_from_le(message, sizeof(VDAgentMonitorMM) * vdata->num_of_monitors,
sizeof(*vdata) + sizeof(vdata->monitors[0]) * vdata->num_of_monitors);
}
return AGENT_CHECK_NO_ERROR;
}
AgentCheckResult
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
const uint32_t *capabilities, uint32_t capabilities_size)
{
AgentCheckResult res;
res = agent_message_check_size(message_header, capabilities, capabilities_size);
if (res != AGENT_CHECK_NO_ERROR) {
return res;
}
switch (message_header->type) {
case VD_AGENT_MOUSE_STATE:
uint32_from_le(message, 3 * sizeof(uint32_t), 0);
break;
case VD_AGENT_REPLY:
case VD_AGENT_DISPLAY_CONFIG:
case VD_AGENT_MAX_CLIPBOARD:
case VD_AGENT_ANNOUNCE_CAPABILITIES:
uint32_from_le(message, message_header->size, 0);
break;
case VD_AGENT_MONITORS_CONFIG:
return agent_message_monitors_config_from_le(message_header, message);
case VD_AGENT_CLIPBOARD:
case VD_AGENT_CLIPBOARD_GRAB:
case VD_AGENT_CLIPBOARD_REQUEST:
case VD_AGENT_CLIPBOARD_RELEASE:
agent_message_clipboard_from_le(message_header, message,
capabilities, capabilities_size);
break;
case VD_AGENT_FILE_XFER_START:
case VD_AGENT_FILE_XFER_STATUS:
case VD_AGENT_FILE_XFER_DATA:
agent_message_file_xfer_from_le(message_header, message);
break;
case VD_AGENT_CLIENT_DISCONNECTED:
break;
case VD_AGENT_GRAPHICS_DEVICE_INFO:
return agent_message_graphics_device_info_check_from_le(message_header, message);
case VD_AGENT_AUDIO_VOLUME_SYNC: {
VDAgentAudioVolumeSync *vdata = (VDAgentAudioVolumeSync *)message;
const size_t max_channels =
(message_header->size - sizeof(*vdata)) / sizeof(vdata->volume[0]);
if (vdata->nchannels > max_channels) {
return AGENT_CHECK_TRUNCATED;
}
uint16_from_le(message, message_header->size - sizeof(*vdata), sizeof(*vdata));
break;
}
default:
return AGENT_CHECK_UNKNOWN_MESSAGE;
}
return AGENT_CHECK_NO_ERROR;
}
void
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
const uint32_t *capabilities, uint32_t capabilities_size)
{
if (*status_size < sizeof(status->common)) {
*status_size = sizeof(status->common);
}
// if there are details but no cap for detail remove it
if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS)) {
*status_size = sizeof(status->common);
// if detail cap is not provided and error > threshold set to error
if (status->common.result >= VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE) {
status->common.result = VD_AGENT_FILE_XFER_STATUS_ERROR;
}
}
// fix endian
switch (status->common.result) {
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
FIX_ENDIAN64(status->not_enough_space.disk_free_space);
break;
case VD_AGENT_FILE_XFER_STATUS_ERROR:
FIX_ENDIAN32(status->error.error_code);
break;
}
// header should be done last
FIX_ENDIAN32(status->common.id);
FIX_ENDIAN32(status->common.result);
}

83
common/agent.h Normal file
View File

@ -0,0 +1,83 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2020 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <spice/macros.h>
#include <spice/vd_agent.h>
SPICE_BEGIN_DECLS
#include <spice/start-packed.h>
/* This helper macro is to define a structure in a way compatible with
* Microsoft compiler */
#define SPICE_INNER_FIELD_STATUS_ERROR(type, name) \
struct SPICE_ATTR_PACKED { \
char common_ ## name[sizeof(VDAgentFileXferStatusMessage)]; \
type name; \
}
/**
* Structure to fill with transfer status.
* Fill as much details as you can and call agent_prepare_filexfer_status
* before sending to adjust for capabilities and endianness.
* If any detail are filled the status_size passed to agent_prepare_filexfer_status
* should be updated.
*/
typedef union SPICE_ATTR_PACKED AgentFileXferStatusMessageFull {
VDAgentFileXferStatusMessage common;
SPICE_INNER_FIELD_STATUS_ERROR(VDAgentFileXferStatusNotEnoughSpace, not_enough_space);
SPICE_INNER_FIELD_STATUS_ERROR(VDAgentFileXferStatusError, error);
} AgentFileXferStatusMessageFull;
#undef SPICE_INNER_FIELD_STATUS_ERROR
#include <spice/end-packed.h>
/**
* Prepare AgentFileXferStatusMessageFull to
* be sent to network.
* Avoid protocol incompatibilities and endian issues
*/
void
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
const uint32_t *capabilities, uint32_t capabilities_size);
/**
* Possible results checking a message.
* Beside AGENT_CHECK_NO_ERROR all other conditions are errors.
*/
typedef enum AgentCheckResult {
AGENT_CHECK_NO_ERROR,
AGENT_CHECK_WRONG_PROTOCOL_VERSION,
AGENT_CHECK_UNKNOWN_MESSAGE,
AGENT_CHECK_INVALID_SIZE,
AGENT_CHECK_TRUNCATED,
AGENT_CHECK_INVALID_DATA,
} AgentCheckResult;
/**
* Check message from network and fix endianness
* Returns AGENT_CHECK_NO_ERROR if message is valid.
* message buffer size should be message_header->size.
*/
AgentCheckResult
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
const uint32_t *capabilities, uint32_t capabilities_size);
SPICE_END_DECLS

510
common/agent_interface.c Normal file
View File

@ -0,0 +1,510 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2019 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include <glib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/eventfd.h>
#include <errno.h>
#include <poll.h>
#include <common/agent_interface.h>
typedef struct sockaddr SA;
static GThread *recorder_comm_thr;
static bool agent_terminated = false;
static int terminate_efd = -1;
static FILE *communication_f = NULL;
#define NB_MAX_RECORDERS 16
static recorder_info *recorders[NB_MAX_RECORDERS];
static uint32_t nb_recorders = 0;
static forward_quality_cb_t forward_quality_cb;
static void *forward_quality_cb_data;
static on_connect_cb_t on_connect_cb;
static void *on_connect_cb_data;
static uintptr_t recorder_tick(void);
#ifndef RECORDER_HZ
#define RECORDER_HZ 1000000
#endif // RECORDER_HZ
static GMutex mutex_socket;
static int agent_initialize_communication(int socket)
{
uint32_t i;
int ret = -1;
FILE *socket_f;
g_mutex_lock(&mutex_socket);
if (communication_f != NULL) {
g_warning("A client is already connected, rejecting the connection.");
goto unlock;
}
socket_f = fdopen(socket, "w+b");
fprintf(socket_f, "Recorders: ");
for (i = 0; i < nb_recorders; i++) {
g_debug("Sending %s", recorders[i]->name);
fprintf(socket_f, "%s;", recorders[i]->name);
}
fprintf(socket_f, "\n");
fflush(socket_f);
for (i = 0; i < nb_recorders; i++) {
char enable;
if (read(socket, &enable, sizeof(enable)) != sizeof(enable)) {
g_warning("Invalid read on the client socket");
goto unlock;
}
if (enable != '0' && enable != '1') {
g_critical("Invalid enable-value received for recorder '%s': %u",
recorders[i]->name, enable);
goto unlock;
}
if (enable == '0') {
continue;
}
recorders[i]->trace = 1;
g_info("Enable recorder '%s'", recorders[i]->name);
}
if (on_connect_cb && on_connect_cb(on_connect_cb_data)) {
goto unlock;
}
communication_f = socket_f;
ret = 0;
unlock:
g_mutex_unlock(&mutex_socket);
return ret;
}
static void agent_finalize_communication(int socket)
{
uint32_t i;
g_info("Communication socket closed.");
g_mutex_lock(&mutex_socket);
g_assert(socket == fileno(communication_f));
fclose(communication_f);
communication_f = NULL;
for (i = 0; i < nb_recorders; i++) {
recorders[i]->trace = 0;
}
g_mutex_unlock(&mutex_socket);
}
static void forward_quality(const char *quality)
{
if (!forward_quality_cb) {
g_warning("Quality: No callback set, dropping the message (%s).", quality);
return;
}
g_info("Quality: Forwarding '%s'", quality);
forward_quality_cb(forward_quality_cb_data, quality);
}
static int agent_process_communication(int socket)
{
static char msg_in[128];
static long unsigned int len = 0;
g_assert(socket == fileno(communication_f));
int nbytes = read(socket, msg_in + len, 1);
if (nbytes < 0 && errno == EINTR) {
return 0;
}
if (nbytes <= 0) {
agent_finalize_communication(socket);
return -1; // socket closed
}
if (msg_in[len] == '\0') {
// process quality indicator
forward_quality(msg_in);
len = 0;
return 0;
}
len += nbytes;
if (len >= sizeof(msg_in) - 1) {
msg_in[sizeof(msg_in) - 1] = '\0';
g_warning("Invalid message received (too long?): %s", msg_in);
len = 0;
}
return 0;
}
static int make_socket(guint port)
{
struct sockaddr_in servaddr;
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket == -1) {
g_critical("socket creation failed");
return -1;
}
int enable = 1;
if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
g_critical("setsockopt(SO_REUSEADDR) failed");
close(listen_socket);
return -1;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
if (bind(listen_socket, (SA *) &servaddr, sizeof(servaddr)) != 0) {
g_critical("socket bind failed");
close(listen_socket);
return -1;
}
return listen_socket;
}
static gpointer handle_communications(gpointer user_data)
{
struct pollfd fds[3];
int nb_fd = 0;
int listen_socket;
int i;
guint port = GPOINTER_TO_UINT(user_data);
listen_socket = make_socket(port);
if (listen_socket < 0) {
return NULL;
}
g_debug("Listening!");
if ((listen(listen_socket, 1)) != 0) {
g_critical("listen failed: %m");
return NULL;
}
fds[0].fd = terminate_efd;
fds[0].events = POLLIN;
fds[1].fd = listen_socket;
fds[1].events = POLLIN;
nb_fd = 2;
while (!agent_terminated) {
/* Block until input arrives on one or more active sockets. */
int ret = poll(fds, nb_fd, -1);
if (ret < 0) {
g_critical("poll failed: %m");
break;
}
/* Service all the sockets with input pending. */
for (i = 0; i < nb_fd; i++) {
int fd = fds[i].fd;
if (fd == terminate_efd) {
if (fds[i].revents & POLLIN) {
g_assert(agent_terminated);
break;
}
} else if (fd == listen_socket) {
if (fds[i].revents & ~POLLIN) {
g_critical("server socket closed");
break;
}
if (!(fds[i].revents & POLLIN)) {
continue;
}
/* Connection request on original socket. */
int new_fd = accept(listen_socket, NULL, NULL);
if (new_fd < 0) {
g_critical("accept failed: %m");
break;
}
if (nb_fd == 3) {
close(new_fd);
g_warning("Too many clients accepted ...");
continue;
}
g_debug("Agent Interface: client connected!");
if (agent_initialize_communication(new_fd)) {
close(new_fd);
g_warning("Initialization failed ...");
continue;
}
fds[nb_fd].fd = new_fd;
fds[nb_fd].events = POLLIN;
nb_fd++;
/* fds array modified, restart the poll. */
break;
} else {
if (!(fds[i].revents & POLLIN)) {
continue;
}
/* Data arriving on an already-connected socket. */
if (agent_process_communication(fd) < 0) {
nb_fd--;
}
}
}
}
close(terminate_efd);
close(listen_socket);
g_info("Agent interface thread: bye!");
return NULL;
}
static void recorder_deregister(void);
static void recorder_initialization(unsigned int port)
{
GError *error = NULL;
terminate_efd = eventfd(0, 0);
if (terminate_efd == -1) {
g_critical("eventfd failed: %m");
return;
}
recorder_comm_thr = g_thread_try_new("smart_agent_interface",
handle_communications,
GUINT_TO_POINTER((guint) port), &error);
if (error) {
g_assert(!recorder_comm_thr);
g_critical("Error: Could not start the agent interface thread: %s", error->message);
g_error_free(error);
return;
}
atexit(recorder_deregister);
}
static void recorder_interrupt_communications(void)
{
agent_terminated = true;
uint64_t msg = 1;
ssize_t s = write(terminate_efd, &msg, sizeof(uint64_t));
if (s != sizeof(uint64_t)) {
g_warning("failed to send recorder thread termination event: %m");
}
}
static void recorder_deregister(void)
{
if (recorder_comm_thr) {
recorder_interrupt_communications();
g_thread_join(recorder_comm_thr);
recorder_comm_thr = NULL;
}
}
void recorder_activate(recorder_info *recorder)
{
if (nb_recorders >= NB_MAX_RECORDERS) {
g_critical("Too many recorders configured (nb max: %d)", NB_MAX_RECORDERS);
return;
}
recorders[nb_recorders] = recorder;
nb_recorders++;
}
static void do_send_entry(FILE *dest, recorder_info *info, recorder_entry *entry, va_list args)
{
fprintf(dest, "Name: %s\nFunction: %s\nTime: %lu\n",
info->name, entry->where, entry->timestamp);
vfprintf(dest, entry->format, args);
fprintf(dest, "\n\n");
fflush(dest);
}
static void recorder_trace_entry(recorder_info *info, recorder_entry *entry, ...)
// ----------------------------------------------------------------------------
// Show a recorder entry when a trace is enabled
// ----------------------------------------------------------------------------
{
va_list args;
if (strchr(entry->format, '\n') != NULL) {
g_critical("Agent records cannot contain '\n' char ... (%s)", entry->where);
return;
}
// send info/entry to the socket
g_mutex_lock(&mutex_socket);
if (communication_f == NULL) {
g_mutex_unlock(&mutex_socket);
return;
}
va_start(args, entry);
do_send_entry(communication_f, info, entry, args);
va_end(args);
if (g_strcmp0(g_getenv("SPICE_AGENT_LOG_RECORDS"), "1") == 0) {
va_start(args, entry);
do_send_entry(stderr, info, entry, args);
va_end(args);
}
g_mutex_unlock(&mutex_socket);
}
void agent_interface_start(unsigned int port)
{
g_info("Launch on port %u", port);
recorder_initialization(port);
}
void agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data)
{
g_debug("Received forward_quality callback");
forward_quality_cb = cb;
forward_quality_cb_data = data;
}
void agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data)
{
g_debug("Received on_connect callback");
on_connect_cb = cb;
on_connect_cb_data = data;
}
void recorder_append(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3)
// ----------------------------------------------------------------------------
// Enter a record entry in ring buffer with given set of args
// ----------------------------------------------------------------------------
{
recorder_entry entry;
if (!rec->trace) {
return;
}
entry.format = format;
entry.timestamp = recorder_tick();
entry.where = where;
recorder_trace_entry(rec, &entry, a0, a1, a2, a3);
}
void recorder_append2(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5,
uintptr_t a6,
uintptr_t a7)
// ----------------------------------------------------------------------------
// Enter a double record (up to 8 args)
// ----------------------------------------------------------------------------
{
recorder_entry entry;
if (!rec->trace) {
return;
}
entry.format = format;
entry.timestamp = recorder_tick();
entry.where = where;
recorder_trace_entry(rec, &entry, a0, a1, a2, a3, a4, a5, a6, a7);
}
// ============================================================================
//
// Support functions
//
// ============================================================================
static uintptr_t recorder_tick(void)
// ----------------------------------------------------------------------------
// Return the "ticks" as stored in the recorder
// ----------------------------------------------------------------------------
{
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec * RECORDER_HZ + t.tv_usec / (1000000 / RECORDER_HZ);
}

564
common/agent_interface.h Normal file
View File

@ -0,0 +1,564 @@
#pragma once
// *****************************************************************************
// This software is licensed under the GNU Lesser General Public License v2+
// (C) 2017-2019, Christophe de Dinechin <christophe@dinechin.org>
// *****************************************************************************
// This file was part of Recorder
//
// Recorder is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Recorder is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Recorder, in a file named COPYING.
// If not, see <https://www.gnu.org/licenses/>.
// *****************************************************************************
/* This file is based on Recorder's recorder.h file, that describes a general-
* purpose instrumentation interface. agent_interface.h is a trimmed-down
* version of it. */
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
static inline void
recorder_dump_on_common_signals(unsigned add, unsigned remove)
{
}
// ============================================================================
//
// Recorder data structures
//
// ============================================================================
typedef struct recorder_entry
/// ---------------------------------------------------------------------------
/// Entry in the flight recorder.
///----------------------------------------------------------------------------
/// Notice that the arguments are stored as "intptr_t" because that type
/// is guaranteed to be the same size as a pointer. This allows us to
/// properly align recorder entries to powers of 2 for efficiency.
/// Also read explanations of \ref _recorder_double and \ref _recorder_float
/// below regarding how to use floating-point with the recorder.
{
const char *format; ///< Printf-style format for record + file/line
uintptr_t timestamp; ///< Time at which record took place
const char *where; ///< Source code function
uintptr_t args[4]; ///< Four arguments, for a total of 8 fields
} recorder_entry;
/// A global counter indicating the order of entries across recorders.
/// this is incremented atomically for each record() call.
/// It must be exposed because all XYZ_record() implementations need to
/// touch the same shared variable in order to provide a global order.
extern uintptr_t recorder_order;
typedef struct recorder_info
///----------------------------------------------------------------------------
/// A linked list of the activated recorders
///----------------------------------------------------------------------------
{
intptr_t trace; ///< Trace this recorder
const char * name; ///< Name of this parameter / recorder
const char * description;///< Description of what is recorded
recorder_entry data[0]; ///< Data for this recorder
} recorder_info;
// ============================================================================
//
// Adding data to a recorder
//
// ============================================================================
extern void recorder_append(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3);
extern void recorder_append2(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5,
uintptr_t a6,
uintptr_t a7);
extern void recorder_append3(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5,
uintptr_t a6,
uintptr_t a7,
uintptr_t a8,
uintptr_t a9,
uintptr_t a10,
uintptr_t a11);
/// Activate a recorder (during construction time)
extern void recorder_activate(recorder_info *recorder);
// ============================================================================
//
// Declaration of recorders and tweaks
//
// ============================================================================
#define RECORDER_DECLARE(Name) \
/* ----------------------------------------------------------------*/ \
/* Declare a recorder with the given name (for use in headers) */ \
/* ----------------------------------------------------------------*/ \
extern recorder_info * const recorder_info_ptr_for_##Name; \
extern struct recorder_info_for_##Name recorder_info_for_##Name
// ============================================================================
//
// Definition of recorders and tweaks
//
// ============================================================================
#define RECORDER(Name, Size, Info) RECORDER_DEFINE(Name,Size,Info)
#define RECORDER_DEFINE(Name, Size, Info) \
/*!----------------------------------------------------------------*/ \
/*! Define a recorder type with Size elements */ \
/*!----------------------------------------------------------------*/ \
/*! \param Name is the C name fo the recorder. \
*! \param Size is the number of entries in the circular buffer. \
*! \param Info is a description of the recorder for help. */ \
\
/* The entry in linked list for this type */ \
struct recorder_info_for_##Name \
{ \
recorder_info info; \
recorder_entry data[Size]; \
} \
recorder_info_for_##Name = \
{ \
{ \
0, #Name, Info, {} \
}, \
{} \
}; \
recorder_info * const recorder_info_ptr_for_##Name = \
&recorder_info_for_##Name.info; \
\
RECORDER_CONSTRUCTOR \
static void recorder_activate_##Name(void) \
/* ----------------------------------------------------------------*/ \
/* Activate recorder before entering main() */ \
/* ----------------------------------------------------------------*/ \
{ \
recorder_activate(RECORDER_INFO(Name)); \
} \
\
/* Purposefully generate compile error if macro not followed by ; */ \
extern void recorder_activate(recorder_info *recorder)
typedef struct SpiceDummyTweak {
intptr_t tweak_value;
} SpiceDummyTweak;
typedef struct SpiceEmptyStruct {
char dummy[0];
} SpiceEmptyStruct;
#define RECORDER_TWEAK_DECLARE(rec) \
extern const SpiceDummyTweak spice_recorder_tweak_ ## rec
#define RECORDER_TWEAK_DEFINE(rec, value, comment) \
const SpiceDummyTweak spice_recorder_tweak_ ## rec = { (value) }
#define RECORDER_TWEAK(rec) \
((spice_recorder_tweak_ ## rec).tweak_value)
#define RECORDER_TRACE(rec) \
(sizeof(struct recorder_info_for_ ## rec) != sizeof(SpiceEmptyStruct))
// ============================================================================
//
// Access to recorder and tweak info
//
// ============================================================================
#define RECORDER_INFO(Name) (recorder_info_ptr_for_##Name)
// ============================================================================
//
// Recording stuff
//
// ============================================================================
#define record(Name, ...) RECORD_MACRO(Name, __VA_ARGS__)
#define RECORD(Name,...) RECORD_MACRO(Name, __VA_ARGS__)
#define RECORD_MACRO(Name, ...) \
RECORD_(RECORD,RECORD_COUNT_(__VA_ARGS__),Name,__VA_ARGS__)
#define RECORD_(RECORD,RCOUNT,Name,...) \
RECORD__(RECORD,RCOUNT,Name,__VA_ARGS__)
#define RECORD__(RECORD,RCOUNT,Name,...) \
RECORD##RCOUNT(Name,__VA_ARGS__)
#define RECORD_COUNT_(...) RECORD_COUNT__(Dummy,##__VA_ARGS__,_X,_X,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,_0)
#define RECORD_COUNT__(Dummy,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_N,...) _N
#define RECORD_0(Name, Format) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, 0, 0, 0, 0)
#define RECORD_1(Name, Format, a) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), 0, 0, 0)
#define RECORD_2(Name, Format, a,b) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), 0, 0)
#define RECORD_3(Name, Format, a,b,c) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), 0)
#define RECORD_4(Name, Format, a,b,c,d) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d))
#define RECORD_5(Name, Format, a,b,c,d,e) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), 0, 0, 0)
#define RECORD_6(Name, Format, a,b,c,d,e,f) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), 0, 0)
#define RECORD_7(Name, Format, a,b,c,d,e,f,g) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), 0)
#define RECORD_8(Name, Format, a,b,c,d,e,f,g,h) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h))
#define RECORD_9(Name, Format, a,b,c,d,e,f,g,h,i) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), 0,0,0)
#define RECORD_10(Name, Format, a,b,c,d,e,f,g,h,i,j) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), \
RECORDER_ARG(j), 0,0)
#define RECORD_11(Name, Format, a,b,c,d,e,f,g,h,i,j,k) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), \
RECORDER_ARG(j), \
RECORDER_ARG(k),0)
#define RECORD_12(Name,Format,a,b,c,d,e,f,g,h,i,j,k,l) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), \
RECORDER_ARG(j), \
RECORDER_ARG(k), \
RECORDER_ARG(l))
#define RECORD_X(Name, ...) RECORD_TOO_MANY_ARGS(printf(__VA_ARGS__))
// Some ugly macro drudgery to make things easy to use. Adjust type.
#ifdef __cplusplus
#define RECORDER_ARG(arg) _recorder_arg(arg)
#else // !__cplusplus
#if defined(__GNUC__) && !defined(__clang__)
# if __GNUC__ <= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
# define RECORDER_WITHOUT_GENERIC
# endif
#endif // __GNUC__
#ifdef RECORDER_WITHOUT_GENERIC
#define RECORDER_ARG(arg) ((uintptr_t) (arg))
#else // !RECORDER_WITHOUT_GENERIC
#define RECORDER_ARG(arg) \
_Generic(arg, \
unsigned char: _recorder_unsigned, \
unsigned short: _recorder_unsigned, \
unsigned: _recorder_unsigned, \
unsigned long: _recorder_unsigned, \
unsigned long long:_recorder_unsigned, \
char: _recorder_char, \
signed char: _recorder_signed, \
signed short: _recorder_signed, \
signed: _recorder_signed, \
signed long: _recorder_signed, \
signed long long: _recorder_signed, \
float: _recorder_float, \
double: _recorder_double, \
default: _recorder_pointer)(arg)
#endif // RECORDER_WITHOUT_GENERIC
#endif // __cplusplus
// ============================================================================
//
// Timing information
//
// ============================================================================
#define RECORD_TIMING_BEGIN(rec) \
do { RECORD(rec, "begin");
#define RECORD_TIMING_END(rec, op, name, value) \
RECORD(rec, "end" op name); \
} while (0)
// ============================================================================
//
// Support macros
//
// ============================================================================
#define RECORDER_SOURCE_FUNCTION __func__ /* Works in C99 and C++11 */
#define RECORDER_SOURCE_LOCATION __FILE__ ":" RECORDER_STRING(__LINE__) ":"
#define RECORDER_STRING(LINE) RECORDER_STRING_(LINE)
#define RECORDER_STRING_(LINE) #LINE
#ifdef __GNUC__
#define RECORDER_CONSTRUCTOR __attribute__((constructor))
#else
#define RECORDER_CONSTRUCTOR
#endif
#ifdef __cplusplus
}
#endif // __cplusplus
// ============================================================================
//
// Utility: Convert floating point values for vararg format
//
// ============================================================================
//
// The recorder stores only uintptr_t in recorder entries. Integer types
// are promoted, pointer types are converted. Floating point values
// are converted a floating point type of the same size as uintptr_t,
// i.e. float are converted to double on 64-bit platforms, and conversely.
#ifdef __cplusplus
#include <string>
// In C++, we don't use _Generic but actual overloading
template <class inttype>
static inline uintptr_t _recorder_arg(inttype i)
{
return (uintptr_t) i;
}
static inline uintptr_t _recorder_arg(const std::string &arg)
{
return (uintptr_t) arg.c_str();
}
#define _recorder_float _recorder_arg
#define _recorder_double _recorder_arg
#else // !__cplusplus
static inline uintptr_t _recorder_char(char c)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return c;
}
static inline uintptr_t _recorder_unsigned(uintptr_t i)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return i;
}
static inline uintptr_t _recorder_signed(intptr_t i)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return (uintptr_t) i;
}
static inline uintptr_t _recorder_pointer(const void *i)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return (uintptr_t) i;
}
#endif // __cplusplus
static inline uintptr_t _recorder_float(float f)
// ----------------------------------------------------------------------------
// Convert floating point number to intptr_t representation for recorder
// ----------------------------------------------------------------------------
{
if (sizeof(float) == sizeof(intptr_t)) {
union { float f; uintptr_t i; } u;
u.f = f;
return u.i;
} else {
union { double d; uintptr_t i; } u;
u.d = (double) f;
return u.i;
}
}
static inline uintptr_t _recorder_double(double d)
// ----------------------------------------------------------------------------
// Convert double-precision floating point number to intptr_t representation
// ----------------------------------------------------------------------------
{
if (sizeof(double) == sizeof(intptr_t)) {
union { double d; uintptr_t i; } u;
u.d = d;
return u.i;
} else {
// Better to lose precision than not store any data
union { float f; uintptr_t i; } u;
u.f = d;
return u.i;
}
}
// ============================================================================
// Agent-Interface specific definitions
// ============================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// launch the Agent-Interface server socket
extern void agent_interface_start(unsigned int port);
//
typedef void (*forward_quality_cb_t)(void *, const char *);
extern void agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data);
// set a callback function triggered when a new client connects to the socket
typedef int (*on_connect_cb_t)(void *);
extern void agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data);
#ifdef __cplusplus
}
#endif // __cplusplus

View File

@ -22,18 +22,20 @@
*/
#include <config.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#if !defined(WIN32) || defined(__MINGW32__)
#include "backtrace.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#ifndef __MINGW32__
#include <sys/wait.h>
#endif
#include "spice_common.h"
#define GSTACK_PATH "/usr/bin/gstack"
#if HAVE_EXECINFO_H
@ -75,7 +77,6 @@ static int spice_backtrace_gstack(void)
/* CHILD */
char parent[16];
seteuid(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
dup2(pipefd[1],STDOUT_FILENO);
@ -131,3 +132,4 @@ void spice_backtrace(void)
spice_backtrace_backtrace();
}
}
#endif

View File

@ -16,8 +16,8 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BACKTRACE_H
#define BACKTRACE_H
#ifndef H_SPICE_COMMON_BACKTRACE
#define H_SPICE_COMMON_BACKTRACE
#include <spice/macros.h>
@ -31,4 +31,4 @@ void spice_backtrace(void);
SPICE_END_DECLS
#endif // BACKTRACE_H
#endif // H_SPICE_COMMON_BACKTRACE

View File

@ -1,91 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BITOPS_H
#define BITOPS_H
#include <spice/macros.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
static inline int spice_bit_find_msb(unsigned int val)
{
int ret;
asm ("bsrl %1,%0\n\t"
"jnz 1f\n\t"
"movl $-1,%0\n"
"1:"
: "=r"(ret) : "r"(val));
return ret + 1;
}
#elif defined(WIN32) && !defined(_WIN64)
static INLINE int spice_bit_find_msb(uint32_t val)
{
uint32_t r;
__asm {
bsr eax, val
jnz found
mov eax, -1
found:
mov r, eax
}
return r + 1;
}
#else
static INLINE int spice_bit_find_msb(unsigned int val)
{
signed char index = 31;
if(val == 0) {
return 0;
}
do {
if(val & 0x80000000) {
break;
}
val <<= 1;
} while(--index >= 0);
return index+1;
}
#endif
static INLINE int spice_bit_next_pow2(unsigned int val)
{
if ((val & (val - 1)) == 0) {
return val;
}
return 1 << spice_bit_find_msb(val);
}
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -16,24 +16,17 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CANVAS_BASE
#define _H_CANVAS_BASE
#ifndef H_SPICE_COMMON_CANVAS_BASE
#define H_SPICE_COMMON_CANVAS_BASE
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#include <spice/macros.h>
#include "pixman_utils.h"
#include "lz.h"
#include "region.h"
#include "draw.h"
#ifdef WIN32
#include <windows.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
typedef void (*spice_destroy_fn_t)(void *data);
@ -64,7 +57,7 @@ typedef struct {
} SpiceImageCacheOps;
struct _SpiceImageCache {
SpiceImageCacheOps *ops;
const SpiceImageCacheOps *ops;
};
typedef struct {
@ -73,7 +66,7 @@ typedef struct {
} SpiceImageSurfacesOps;
struct _SpiceImageSurfaces {
SpiceImageSurfacesOps *ops;
const SpiceImageSurfacesOps *ops;
};
typedef struct {
@ -137,6 +130,7 @@ typedef struct {
void (*draw_text)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text);
void (*draw_stroke)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke);
void (*draw_rop3)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3);
void (*draw_composite)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceComposite *composite);
void (*draw_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend);
void (*draw_blackness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness);
void (*draw_whiteness)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness);
@ -144,9 +138,6 @@ typedef struct {
void (*draw_transparent)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent* transparent);
void (*draw_alpha_blend)(SpiceCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend* alpha_blend);
void (*put_image)(SpiceCanvas *canvas,
#ifdef WIN32
HDC dc,
#endif
const SpiceRect *dest, const uint8_t *src_data,
uint32_t src_width, uint32_t src_height, int src_stride,
const QRegion *clip);
@ -310,18 +301,13 @@ typedef struct {
void (*copy_region)(SpiceCanvas *canvas,
pixman_region32_t *dest_region,
int dx, int dy);
pixman_image_t *(*get_image)(SpiceCanvas *canvas);
pixman_image_t *(*get_image)(SpiceCanvas *canvas, int force_opaque);
} SpiceCanvasOps;
void spice_canvas_set_usr_data(SpiceCanvas *canvas, void *data, spice_destroy_fn_t destroy_fn);
void *spice_canvas_get_usr_data(SpiceCanvas *canvas);
struct _SpiceCanvas {
SpiceCanvasOps *ops;
};
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

View File

@ -15,42 +15,21 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "canvas_utils.h"
#include <spice/macros.h>
#ifdef __GNUC__
#include <stdlib.h>
#include <stdio.h>
#endif
#include "mem.h"
#ifdef WIN32
static int gdi_handlers = 0;
#endif
typedef struct PixmanData {
uint8_t *data;
pixman_format_code_t format;
} PixmanData;
#ifndef CANVAS_ERROR
#define CANVAS_ERROR(format, ...) { \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__); \
abort(); \
}
#endif
static void release_data(pixman_image_t *image, void *release_data)
static void release_data(SPICE_GNUC_UNUSED pixman_image_t *image,
void *release_data)
{
PixmanData *data = (PixmanData *)release_data;
#ifdef WIN32
if (data->bitmap) {
DeleteObject((HBITMAP)data->bitmap);
CloseHandle(data->mutex);
gdi_handlers--;
}
#endif
free(data->data);
free(data);
@ -65,7 +44,7 @@ pixman_image_add_data(pixman_image_t *image)
if (data == NULL) {
data = (PixmanData *)calloc(1, sizeof(PixmanData));
if (data == NULL) {
CANVAS_ERROR("out of memory");
spice_error("out of memory");
}
pixman_image_set_destroy_function(image,
release_data,
@ -85,21 +64,25 @@ spice_pixman_image_set_format(pixman_image_t *image,
data->format = format;
}
pixman_format_code_t
spice_pixman_image_get_format(pixman_image_t *image)
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format)
{
PixmanData *data;
data = (PixmanData *)pixman_image_get_destroy_data(image);
if (data != NULL &&
data->format != 0)
return data->format;
spice_return_val_if_fail(format != NULL, 0);
CANVAS_ERROR("Unknown pixman image type");
data = (PixmanData *)pixman_image_get_destroy_data(image);
if (data != NULL && data->format != 0) {
*format = data->format;
return 1;
}
spice_warn_if_reached();
return 0;
}
static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t format, int width, int height,
int stride)
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
int stride)
{
uint8_t *data;
uint8_t *stride_data;
@ -117,7 +100,8 @@ static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t forma
if (surface == NULL) {
free(data);
CANVAS_ERROR("create surface failed, out of memory");
data = NULL;
spice_error("create surface failed, out of memory");
}
pixman_data = pixman_image_add_data(surface);
@ -127,98 +111,8 @@ static INLINE pixman_image_t *__surface_create_stride(pixman_format_code_t forma
return surface;
}
#ifdef WIN32
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
int width, int height, int top_down)
#else
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down)
#endif
{
#ifdef WIN32
/*
* Windows xp allow only 10,000 of gdi handlers, considering the fact that
* we limit here the number to 5000, we dont use atomic operations to sync
* this calculation against the other canvases (in case of multiple
* monitors), in worst case there will be little more than 5000 gdi
* handlers.
*/
if (dc && gdi_handlers < 5000) {
uint8_t *data;
uint8_t *src;
struct {
BITMAPINFO inf;
RGBQUAD palette[255];
} bitmap_info;
int nstride;
pixman_image_t *surface;
PixmanData *pixman_data;
HBITMAP bitmap;
HANDLE mutex;
memset(&bitmap_info, 0, sizeof(bitmap_info));
bitmap_info.inf.bmiHeader.biSize = sizeof(bitmap_info.inf.bmiHeader);
bitmap_info.inf.bmiHeader.biWidth = width;
bitmap_info.inf.bmiHeader.biHeight = (!top_down) ? height : -height;
bitmap_info.inf.bmiHeader.biPlanes = 1;
switch (format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
bitmap_info.inf.bmiHeader.biBitCount = 32;
nstride = width * 4;
break;
case PIXMAN_x1r5g5b5:
case PIXMAN_r5g6b5:
bitmap_info.inf.bmiHeader.biBitCount = 16;
nstride = SPICE_ALIGN(width * 2, 4);
break;
case PIXMAN_a8:
bitmap_info.inf.bmiHeader.biBitCount = 8;
nstride = SPICE_ALIGN(width, 4);
break;
case PIXMAN_a1:
bitmap_info.inf.bmiHeader.biBitCount = 1;
nstride = SPICE_ALIGN(width, 32) / 8;
break;
default:
CANVAS_ERROR("invalid format");
}
bitmap_info.inf.bmiHeader.biCompression = BI_RGB;
mutex = CreateMutex(NULL, 0, NULL);
if (!mutex) {
CANVAS_ERROR("Unable to CreateMutex");
}
bitmap = CreateDIBSection(dc, &bitmap_info.inf, 0, (VOID **)&data, NULL, 0);
if (!bitmap) {
CloseHandle(mutex);
CANVAS_ERROR("Unable to CreateDIBSection");
}
if (top_down) {
src = data;
} else {
src = data + nstride * (height - 1);
nstride = -nstride;
}
surface = pixman_image_create_bits(format, width, height, (uint32_t *)src, nstride);
if (surface == NULL) {
CloseHandle(mutex);
DeleteObject(bitmap);
CANVAS_ERROR("create surface failed, out of memory");
}
pixman_data = pixman_image_add_data(surface);
pixman_data->format = format;
pixman_data->bitmap = bitmap;
pixman_data->mutex = mutex;
gdi_handlers++;
return surface;
} else {
#endif
if (top_down) {
pixman_image_t *surface;
PixmanData *data;
@ -233,8 +127,19 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
switch (format) {
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
#ifdef WORDS_BIGENDIAN
case PIXMAN_b8g8r8a8:
case PIXMAN_b8g8r8x8:
#endif
stride = width * 4;
break;
case PIXMAN_r8g8b8:
#ifdef WORDS_BIGENDIAN
case PIXMAN_b8g8r8:
#endif
// NOTE: LZ4 also decodes to RGB24
stride = SPICE_ALIGN(width * 3, 4);
break;
case PIXMAN_x1r5g5b5:
case PIXMAN_r5g6b5:
stride = SPICE_ALIGN(width * 2, 4);
@ -246,34 +151,11 @@ pixman_image_t * surface_create(pixman_format_code_t format, int width, int heig
stride = SPICE_ALIGN(width, 32) / 8;
break;
default:
CANVAS_ERROR("invalid format");
spice_error("invalid format");
}
stride = -stride;
return __surface_create_stride(format, width, height, stride);
return surface_create_stride(format, width, height, stride);
}
#ifdef WIN32
}
#endif
}
#ifdef WIN32
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
int stride)
#else
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
int stride)
#endif
{
#ifdef WIN32
if (dc) {
if (abs(stride) == (width * 4)) {
return surface_create(dc, format, width, height, (stride > 0));
}
}
#endif
return __surface_create_stride(format, width, height, stride);
}
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
@ -285,15 +167,14 @@ pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);
/* pixman requires strides to be 4-byte aligned */
stride = SPICE_ALIGN(stride, 4);
if (!top_down) {
stride = -stride;
}
surface = surface_create_stride(
#ifdef WIN32
canvas_data->dc,
#endif
pixman_format, width, height, stride);
surface = surface_create_stride(pixman_format, width, height, stride);
canvas_data->out_surface = surface;
return surface;
}

View File

@ -16,56 +16,29 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CANVAS_UTILS
#define _H_CANVAS_UTILS
#ifdef WIN32
#include <windows.h>
#endif
#ifndef H_SPICE_COMMON_CANVAS_UTILS
#define H_SPICE_COMMON_CANVAS_UTILS
#include <spice/types.h>
#include <spice/macros.h>
#include "pixman_utils.h"
#include "lz.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct PixmanData {
#ifdef WIN32
HBITMAP bitmap;
HANDLE mutex;
#endif
uint8_t *data;
pixman_format_code_t format;
} PixmanData;
SPICE_BEGIN_DECLS
void spice_pixman_image_set_format(pixman_image_t *image,
pixman_format_code_t format);
pixman_format_code_t spice_pixman_image_get_format(pixman_image_t *image);
int spice_pixman_image_get_format(pixman_image_t *image, pixman_format_code_t *format);
#ifdef WIN32
pixman_image_t *surface_create(HDC dc, pixman_format_code_t format,
int width, int height, int top_down);
#else
pixman_image_t *surface_create(pixman_format_code_t format, int width, int height, int top_down);
#endif
#ifdef WIN32
pixman_image_t *surface_create_stride(HDC dc, pixman_format_code_t format, int width, int height,
int stride);
#else
pixman_image_t *surface_create_stride(pixman_format_code_t format, int width, int height,
int stride);
#endif
typedef struct LzDecodeUsrData {
#ifdef WIN32
HDC dc;
#endif
pixman_image_t *out_surface;
} LzDecodeUsrData;
@ -73,8 +46,7 @@ typedef struct LzDecodeUsrData {
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
pixman_format_code_t pixman_format, int width,
int height, int gross_pixels, int top_down);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

View File

@ -1,6 +1,6 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -16,23 +16,19 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GLCTX
#define _H_GLCTX
#ifndef H_SPICE_COMMON_CLIENT_MARSHALLERS
#define H_SPICE_COMMON_CLIENT_MARSHALLERS
#ifdef __cplusplus
extern "C" {
#endif
#include <spice/protocol.h>
typedef struct OGLCtx OGLCtx;
#include "messages.h"
#include "common/generated_client_marshallers.h"
#include "marshaller.h"
const char *oglctx_type_str(OGLCtx *ctx);
void oglctx_make_current(OGLCtx *ctx);
OGLCtx *pbuf_create(int width, int heigth);
OGLCtx *pixmap_create(int width, int heigth);
void oglctx_destroy(OGLCtx *ctx);
SPICE_BEGIN_DECLS
#ifdef __cplusplus
}
#endif
SpiceMessageMarshallers *spice_message_marshallers_get(void);
SPICE_END_DECLS
#endif

38
common/demarshallers.h Normal file
View File

@ -0,0 +1,38 @@
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef H_SPICE_COMMON_DEMARSHALLERS
#define H_SPICE_COMMON_DEMARSHALLERS
#include <stddef.h>
#include <spice/macros.h>
SPICE_BEGIN_DECLS
typedef void (*message_destructor_t)(uint8_t *message);
typedef uint8_t * (*spice_parse_channel_func_t)(uint8_t *message_start, uint8_t *message_end,
uint16_t message_type, int minor,
size_t *size_out,
message_destructor_t *free_message);
spice_parse_channel_func_t
spice_get_server_channel_parser(uint32_t channel, unsigned int *max_message_type);
spice_parse_channel_func_t
spice_get_client_channel_parser(uint32_t channel, unsigned int *max_message_type);
SPICE_END_DECLS
#endif

View File

@ -28,16 +28,15 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _H_SPICE_DRAW
#define _H_SPICE_DRAW
#ifndef H_SPICE_COMMON_DRAW
#define H_SPICE_COMMON_DRAW
#include <spice/macros.h>
#include <spice/types.h>
#include <spice/enums.h>
#include "mem.h"
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
#define SPICE_GET_ADDRESS(addr) ((void *)(uintptr_t)(addr))
#define SPICE_SET_ADDRESS(addr, val) ((addr) = (uintptr_t)(val))
@ -83,7 +82,7 @@ typedef struct SpiceClipRects {
} SpiceClipRects;
typedef struct SpiceClip {
uint32_t type;
uint8_t type;
SpiceClipRects *rects;
} SpiceClip;
@ -121,7 +120,7 @@ typedef struct SpiceSurface {
typedef struct SpiceQUICData {
uint32_t data_size;
SpiceChunks *data;
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData;
} SpiceQUICData, SpiceLZRGBData, SpiceJPEGData, SpiceLZ4Data;
typedef struct SpiceLZPLTData {
uint8_t flags;
@ -154,6 +153,7 @@ typedef struct SpiceImage {
SpiceLZRGBData lz_rgb;
SpiceLZPLTData lz_plt;
SpiceJPEGData jpeg;
SpiceLZ4Data lz4;
SpiceZlibGlzRGBData zlib_glz;
SpiceJPEGAlphaData jpeg_alpha;
} u;
@ -224,6 +224,26 @@ typedef struct SpiceRop3 {
SpiceQMask mask;
} SpiceRop3;
/* Given in 16.16 fixed point */
typedef struct SpiceTransform {
uint32_t t00;
uint32_t t01;
uint32_t t02;
uint32_t t10;
uint32_t t11;
uint32_t t12;
} SpiceTransform;
typedef struct SpiceComposite {
uint32_t flags;
SpiceImage *src_bitmap;
SpiceImage *mask_bitmap;
SpiceTransform src_transform;
SpiceTransform mask_transform;
SpicePoint16 src_origin;
SpicePoint16 mask_origin;
} SpiceComposite;
typedef struct SpiceBlackness {
SpiceQMask mask;
} SpiceBlackness, SpiceInvers, SpiceWhiteness;
@ -274,8 +294,12 @@ typedef struct SpiceCursorHeader {
uint16_t hot_spot_y;
} SpiceCursorHeader;
#ifdef __cplusplus
static inline int spice_image_descriptor_is_lossy(const SpiceImageDescriptor *descriptor)
{
return descriptor->type == SPICE_IMAGE_TYPE_JPEG ||
descriptor->type == SPICE_IMAGE_TYPE_JPEG_ALPHA;
}
#endif
#endif /* _H_SPICE_DRAW */
SPICE_END_DECLS
#endif // H_SPICE_COMMON_DRAW

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H__GDI_CANVAS
#define _H__GDI_CANVAS
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "pixman_utils.h"
#include "canvas_base.h"
#include "region.h"
SpiceCanvas *gdi_canvas_create(int width, int height,
HDC dc, class RecurciveMutex *lock, uint32_t format,
SpiceImageCache *bits_cache,
SpicePaletteCache *palette_cache,
SpiceImageSurfaces *surfaces,
SpiceGlzDecoder *glz_decoder,
SpiceJpegDecoder *jpeg_decoder,
SpiceZlibDecoder *zlib_decoder);
void gdi_canvas_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,906 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef SPICE_CANVAS_INTERNAL
#error "This file shouldn't be compiled directly"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "quic.h"
#include "rop3.h"
#include "region.h"
#define GL_CANVAS
#include "canvas_base.c"
typedef struct GLCanvas GLCanvas;
struct GLCanvas {
CanvasBase base;
GLCCtx glc;
void *private_data;
int private_data_size;
int textures_lost;
};
static inline uint8_t *copy_opposite_image(GLCanvas *canvas, void *data, int stride, int height)
{
uint8_t *ret_data = (uint8_t *)data;
uint8_t *dest;
uint8_t *src;
int i;
if (!canvas->private_data) {
canvas->private_data = spice_malloc_n(height, stride);
if (!canvas->private_data) {
return ret_data;
}
canvas->private_data_size = stride * height;
}
if (canvas->private_data_size < (stride * height)) {
free(canvas->private_data);
canvas->private_data = spice_malloc_n(height, stride);
if (!canvas->private_data) {
return ret_data;
}
canvas->private_data_size = stride * height;
}
dest = (uint8_t *)canvas->private_data;
src = (uint8_t *)data + (height - 1) * stride;
for (i = 0; i < height; ++i) {
memcpy(dest, src, stride);
dest += stride;
src -= stride;
}
return (uint8_t *)canvas->private_data;
}
static pixman_image_t *canvas_surf_to_trans_surf(GLCImage *image,
uint32_t trans_color)
{
int width = image->width;
int height = image->height;
uint8_t *src_line;
uint8_t *end_src_line;
int src_stride;
uint8_t *dest_line;
int dest_stride;
pixman_image_t *ret;
int i;
ret = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0);
if (ret == NULL) {
CANVAS_ERROR("create surface failed");
}
src_line = image->pixels;
src_stride = image->stride;
end_src_line = src_line + src_stride * height;
dest_line = (uint8_t *)pixman_image_get_data(ret);
dest_stride = pixman_image_get_stride(ret);
for (; src_line < end_src_line; src_line += src_stride, dest_line += dest_stride) {
for (i = 0; i < width; i++) {
if ((((uint32_t*)src_line)[i] & 0x00ffffff) == trans_color) {
((uint32_t*)dest_line)[i] = 0;
} else {
((uint32_t*)dest_line)[i] = (((uint32_t*)src_line)[i]) | 0xff000000;
}
}
}
return ret;
}
static GLCPath get_path(GLCanvas *canvas, SpicePath *s)
{
GLCPath path = glc_path_create(canvas->glc);
int i;
for (i = 0; i < s->num_segments; i++) {
SpicePathSeg* seg = s->segments[i];
SpicePointFix* point = seg->points;
SpicePointFix* end_point = point + seg->count;
if (seg->flags & SPICE_PATH_BEGIN) {
glc_path_move_to(path, fix_to_double(point->x), fix_to_double(point->y));
point++;
}
if (seg->flags & SPICE_PATH_BEZIER) {
ASSERT((point - end_point) % 3 == 0);
for (; point + 2 < end_point; point += 3) {
glc_path_curve_to(path,
fix_to_double(point[0].x), fix_to_double(point[0].y),
fix_to_double(point[1].x), fix_to_double(point[1].y),
fix_to_double(point[2].x), fix_to_double(point[2].y));
}
} else {
for (; point < end_point; point++) {
glc_path_line_to(path, fix_to_double(point->x), fix_to_double(point->y));
}
}
if (seg->flags & SPICE_PATH_END) {
if (seg->flags & SPICE_PATH_CLOSE) {
glc_path_close(path);
}
}
}
return path;
}
#define SET_GLC_RECT(dest, src) { \
(dest)->x = (src)->left; \
(dest)->y = (src)->top; \
(dest)->width = (src)->right - (src)->left; \
(dest)->height = (src)->bottom - (src)->top; \
}
#define SET_GLC_BOX(dest, src) { \
(dest)->x = (src)->x1; \
(dest)->y = (src)->y1; \
(dest)->width = (src)->x2 - (src)->x1; \
(dest)->height = (src)->y2 - (src)->y1; \
}
static void set_clip(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip)
{
GLCRect rect;
glc_clip_reset(canvas->glc);
switch (clip->type) {
case SPICE_CLIP_TYPE_NONE:
break;
case SPICE_CLIP_TYPE_RECTS: {
uint32_t n = clip->rects->num_rects;
SpiceRect *now = clip->rects->rects;
SpiceRect *end = now + n;
if (n == 0) {
rect.x = rect.y = 0;
rect.width = rect.height = 0;
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
break;
} else {
SET_GLC_RECT(&rect, now);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
}
for (now++; now < end; now++) {
SET_GLC_RECT(&rect, now);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
}
break;
}
default:
CANVAS_ERROR("invalid clip type");
}
}
static void set_mask(GLCanvas *canvas, SpiceQMask *mask, int x, int y)
{
pixman_image_t *image;
if (!(image = canvas_get_mask(&canvas->base, mask, NULL))) {
glc_clear_mask(canvas->glc, GLC_MASK_A);
return;
}
glc_set_mask(canvas->glc, x - mask->pos.x, y - mask->pos.y,
pixman_image_get_width(image),
pixman_image_get_height(image),
pixman_image_get_stride(image),
(uint8_t *)pixman_image_get_data(image), GLC_MASK_A);
}
static inline void surface_to_image(GLCanvas *canvas, pixman_image_t *surface, GLCImage *image,
int ignore_stride)
{
int depth = pixman_image_get_depth(surface);
ASSERT(depth == 32 || depth == 24);
image->format = (depth == 24) ? GLC_IMAGE_RGB32 : GLC_IMAGE_ARGB32;
image->width = pixman_image_get_width(surface);
image->height = pixman_image_get_height(surface);
image->stride = pixman_image_get_stride(surface);
image->pixels = (uint8_t *)pixman_image_get_data(surface);
image->pallet = NULL;
if (ignore_stride) {
return;
}
if (image->stride < 0) {
image->stride = -image->stride;
image->pixels = image->pixels - (image->height - 1) * image->stride;
} else {
image->pixels = copy_opposite_image(canvas, image->pixels, image->stride, image->height);
}
}
static void set_brush(GLCanvas *canvas, SpiceBrush *brush)
{
switch (brush->type) {
case SPICE_BRUSH_TYPE_SOLID: {
uint32_t color = brush->u.color;
double r, g, b;
b = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
color >>= canvas->base.color_shift;
g = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
color >>= canvas->base.color_shift;
r = (double)(color & canvas->base.color_mask) / canvas->base.color_mask;
glc_set_rgb(canvas->glc, r, g, b);
break;
}
case SPICE_BRUSH_TYPE_PATTERN: {
GLCImage image;
GLCPattern pattern;
pixman_image_t *surface;
surface = canvas_get_image(&canvas->base, brush->u.pattern.pat, FALSE);
surface_to_image(canvas, surface, &image, 0);
pattern = glc_pattern_create(canvas->glc, -brush->u.pattern.pos.x,
-brush->u.pattern.pos.y, &image);
glc_set_pattern(canvas->glc, pattern);
glc_pattern_destroy(pattern);
pixman_image_unref (surface);
}
case SPICE_BRUSH_TYPE_NONE:
return;
default:
CANVAS_ERROR("invalid brush type");
}
}
static void set_op(GLCanvas *canvas, uint16_t rop_decriptor)
{
GLCOp op;
switch (rop_decriptor) {
case SPICE_ROPD_OP_PUT:
op = GLC_OP_COPY;
break;
case SPICE_ROPD_OP_XOR:
op = GLC_OP_XOR;
break;
case SPICE_ROPD_OP_BLACKNESS:
op = GLC_OP_CLEAR;
break;
case SPICE_ROPD_OP_WHITENESS:
op = GLC_OP_SET;
break;
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_BRUSH:
case SPICE_ROPD_OP_PUT | SPICE_ROPD_INVERS_SRC:
op = GLC_OP_COPY_INVERTED;
break;
case SPICE_ROPD_OP_INVERS:
op = GLC_OP_INVERT;
break;
case SPICE_ROPD_OP_AND:
op = GLC_OP_AND;
break;
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_RES:
op = GLC_OP_NAND;
break;
case SPICE_ROPD_OP_OR:
op = GLC_OP_OR;
break;
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_RES:
op = GLC_OP_NOR;
break;
case SPICE_ROPD_OP_XOR | SPICE_ROPD_INVERS_RES:
op = GLC_OP_EQUIV;
break;
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_DEST:
op = GLC_OP_AND_REVERSE;
break;
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_BRUSH:
case SPICE_ROPD_OP_AND | SPICE_ROPD_INVERS_SRC:
op = GLC_OP_AND_INVERTED;
break;
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_DEST:
op = GLC_OP_OR_REVERSE;
break;
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_BRUSH:
case SPICE_ROPD_OP_OR | SPICE_ROPD_INVERS_SRC:
op = GLC_OP_OR_INVERTED;
break;
default:
WARN("GLC_OP_NOOP");
op = GLC_OP_NOOP;
}
glc_set_op(canvas->glc, op);
}
static void gl_canvas_draw_fill(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceFill *fill)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRect rect;
set_clip(canvas, bbox, clip);
set_mask(canvas, &fill->mask, bbox->left, bbox->top);
set_brush(canvas, &fill->brush);
set_op(canvas, fill->rop_descriptor);
SET_GLC_RECT(&rect, bbox);
glc_fill_rect(canvas->glc, &rect);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_copy(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceCopy *copy)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCImage image;
set_clip(canvas, bbox, clip);
set_mask(canvas, &copy->mask, bbox->left, bbox->top);
set_op(canvas, copy->rop_descriptor);
//todo: optimize get_image (use ogl conversion + remove unnecessary copy of 32bpp)
surface = canvas_get_image(&canvas->base, copy->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &copy->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(surface);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_opaque(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceOpaque *opaque)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCRect fill_rect;
GLCImage image;
set_clip(canvas, bbox, clip);
set_mask(canvas, &opaque->mask, bbox->left, bbox->top);
glc_set_op(canvas->glc, (opaque->rop_descriptor & SPICE_ROPD_INVERS_SRC) ? GLC_OP_COPY_INVERTED :
GLC_OP_COPY);
surface = canvas_get_image(&canvas->base, opaque->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &opaque->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(surface);
set_brush(canvas, &opaque->brush);
set_op(canvas, opaque->rop_descriptor & ~SPICE_ROPD_INVERS_SRC);
SET_GLC_RECT(&fill_rect, bbox);
glc_fill_rect(canvas->glc, &fill_rect);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_alpha_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceAlphaBlend *alpha_blend)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCImage image;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
surface = canvas_get_image(&canvas->base, alpha_blend->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &alpha_blend->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, (double)alpha_blend->alpha / 0xff);
pixman_image_unref(surface);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_blend(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlend *blend)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
GLCRecti src;
GLCRecti dest;
GLCImage image;
set_clip(canvas, bbox, clip);
set_mask(canvas, &blend->mask, bbox->left, bbox->top);
set_op(canvas, blend->rop_descriptor);
surface = canvas_get_image(&canvas->base, blend->src_bitmap, FALSE);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &blend->src_area);
surface_to_image(canvas, surface, &image, 0);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(surface);
glc_flush(canvas->glc);
}
static void gl_canvas_draw_transparent(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceTransparent *transparent)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *surface;
pixman_image_t *trans_surf;
GLCImage image;
GLCRecti src;
GLCRecti dest;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
surface = canvas_get_image(&canvas->base, transparent->src_bitmap, FALSE);
surface_to_image(canvas, surface, &image, 0);
trans_surf = canvas_surf_to_trans_surf(&image, transparent->true_color);
pixman_image_unref(surface);
surface_to_image(canvas, trans_surf, &image, 1);
SET_GLC_RECT(&dest, bbox);
SET_GLC_RECT(&src, &transparent->src_area);
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(trans_surf);
glc_flush(canvas->glc);
}
static inline void fill_common(GLCanvas *canvas, SpiceRect *bbox, SpiceClip *clip, SpiceQMask * mask, GLCOp op)
{
GLCRect rect;
set_clip(canvas, bbox, clip);
set_mask(canvas, mask, bbox->left, bbox->top);
glc_set_op(canvas->glc, op);
SET_GLC_RECT(&rect, bbox);
glc_fill_rect(canvas->glc, &rect);
}
static void gl_canvas_draw_whiteness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceWhiteness *whiteness)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
fill_common(canvas, bbox, clip, &whiteness->mask, GLC_OP_SET);
}
static void gl_canvas_draw_blackness(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceBlackness *blackness)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
fill_common(canvas, bbox, clip, &blackness->mask, GLC_OP_CLEAR);
}
static void gl_canvas_draw_invers(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceInvers *invers)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
fill_common(canvas, bbox, clip, &invers->mask, GLC_OP_INVERT);
}
static void gl_canvas_draw_rop3(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceRop3 *rop3)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
pixman_image_t *d;
pixman_image_t *s;
GLCImage image;
SpicePoint src_pos;
uint8_t *data_opp;
int src_stride;
set_clip(canvas, bbox, clip);
set_mask(canvas, &rop3->mask, bbox->left, bbox->top);
glc_set_op(canvas->glc, GLC_OP_COPY);
image.format = GLC_IMAGE_RGB32;
image.width = bbox->right - bbox->left;
image.height = bbox->bottom - bbox->top;
image.pallet = NULL;
d = pixman_image_create_bits(PIXMAN_x8r8g8b8, image.width, image.height, NULL, 0);
if (d == NULL) {
CANVAS_ERROR("create surface failed");
}
image.pixels = (uint8_t *)pixman_image_get_data(d);
image.stride = pixman_image_get_stride(d);
glc_read_pixels(canvas->glc, bbox->left, bbox->top, &image);
data_opp = copy_opposite_image(canvas, image.pixels,
image.stride,
pixman_image_get_height(d));
memcpy(image.pixels, data_opp,
image.stride * pixman_image_get_height(d));
s = canvas_get_image(&canvas->base, rop3->src_bitmap, FALSE);
src_stride = pixman_image_get_stride(s);
if (src_stride > 0) {
data_opp = copy_opposite_image(canvas, (uint8_t *)pixman_image_get_data(s),
src_stride, pixman_image_get_height(s));
memcpy((uint8_t *)pixman_image_get_data(s), data_opp,
src_stride * pixman_image_get_height(s));
}
if (!rect_is_same_size(bbox, &rop3->src_area)) {
pixman_image_t *scaled_s = canvas_scale_surface(s, &rop3->src_area, image.width,
image.height, rop3->scale_mode);
pixman_image_unref(s);
s = scaled_s;
src_pos.x = 0;
src_pos.y = 0;
} else {
src_pos.x = rop3->src_area.left;
src_pos.y = rop3->src_area.top;
}
if (pixman_image_get_width(s) - src_pos.x < image.width ||
pixman_image_get_height(s) - src_pos.y < image.height) {
CANVAS_ERROR("bad src bitmap size");
}
if (rop3->brush.type == SPICE_BRUSH_TYPE_PATTERN) {
pixman_image_t *p = canvas_get_image(&canvas->base, rop3->brush.u.pattern.pat, FALSE);
SpicePoint pat_pos;
pat_pos.x = (bbox->left - rop3->brush.u.pattern.pos.x) % pixman_image_get_width(p);
pat_pos.y = (bbox->top - rop3->brush.u.pattern.pos.y) % pixman_image_get_height(p);
//for now (bottom-top)
if (pat_pos.y < 0) {
pat_pos.y = pixman_image_get_height(p) + pat_pos.y;
}
pat_pos.y = (image.height + pat_pos.y) % pixman_image_get_height(p);
pat_pos.y = pixman_image_get_height(p) - pat_pos.y;
do_rop3_with_pattern(rop3->rop3, d, s, &src_pos, p, &pat_pos);
pixman_image_unref(p);
} else {
uint32_t color = (canvas->base.color_shift) == 8 ? rop3->brush.u.color :
canvas_16bpp_to_32bpp(rop3->brush.u.color);
do_rop3_with_color(rop3->rop3, d, s, &src_pos, color);
}
pixman_image_unref(s);
GLCRecti dest;
GLCRecti src;
dest.x = bbox->left;
dest.y = bbox->top;
image.pixels = copy_opposite_image(canvas, image.pixels, pixman_image_get_stride(d),
pixman_image_get_height(d));
src.x = src.y = 0;
dest.width = src.width = image.width;
dest.height = src.height = image.height;
glc_draw_image(canvas->glc, &dest, &src, &image, 0, 1);
pixman_image_unref(d);
}
static void gl_canvas_draw_stroke(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceStroke *stroke)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCPath path;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
set_op(canvas, stroke->fore_mode);
set_brush(canvas, &stroke->brush);
if (stroke->attr.flags & SPICE_LINE_FLAGS_STYLED) {
WARN("SPICE_LINE_FLAGS_STYLED");
}
glc_set_line_width(canvas->glc, 1.0);
path = get_path(canvas, stroke->path);
glc_stroke_path(canvas->glc, path);
glc_path_destroy(path);
}
static void gl_canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpiceText *text)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRect rect;
SpiceString *str;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
if (!rect_is_empty(&text->back_area)) {
set_brush(canvas, &text->back_brush);
set_op(canvas, text->back_mode);
SET_GLC_RECT(&rect, bbox);
glc_fill_rect(canvas->glc, &rect);
}
str = (SpiceString *)SPICE_GET_ADDRESS(text->str);
set_brush(canvas, &text->fore_brush);
set_op(canvas, text->fore_mode);
if (str->flags & SPICE_STRING_FLAGS_RASTER_A1) {
SpicePoint pos;
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 1, &pos);
_glc_fill_mask(canvas->glc, pos.x, pos.y,
pixman_image_get_width(mask),
pixman_image_get_height(mask),
pixman_image_get_stride(mask),
(uint8_t *)pixman_image_get_data(mask));
pixman_image_unref(mask);
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
SpicePoint pos;
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 4, &pos);
glc_fill_alpha(canvas->glc, pos.x, pos.y,
pixman_image_get_width(mask),
pixman_image_get_height(mask),
pixman_image_get_stride(mask),
(uint8_t *)pixman_image_get_data(mask));
pixman_image_unref(mask);
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
WARN("untested path A8 glyphs, doing nothing");
if (0) {
SpicePoint pos;
pixman_image_t *mask = canvas_get_str_mask(&canvas->base, str, 8, &pos);
glc_fill_alpha(canvas->glc, pos.x, pos.y,
pixman_image_get_width(mask),
pixman_image_get_height(mask),
pixman_image_get_stride(mask),
(uint8_t *)pixman_image_get_data(mask));
pixman_image_unref(mask);
}
} else {
WARN("untested path vector glyphs, doing nothing");
if (0) {
//draw_vector_str(canvas, str, &text->fore_brush, text->fore_mode);
}
}
glc_flush(canvas->glc);
}
static void gl_canvas_clear(SpiceCanvas *spice_canvas)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
glc_clear(canvas->glc);
glc_flush(canvas->glc);
}
static void gl_canvas_copy_bits(SpiceCanvas *spice_canvas, SpiceRect *bbox, SpiceClip *clip, SpicePoint *src_pos)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
set_clip(canvas, bbox, clip);
glc_clear_mask(canvas->glc, GLC_MASK_A);
glc_set_op(canvas->glc, GLC_OP_COPY);
glc_copy_pixels(canvas->glc, bbox->left, bbox->top, src_pos->x, src_pos->y,
bbox->right - bbox->left, bbox->bottom - bbox->top);
}
static void gl_canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest, int dest_stride, const SpiceRect *area)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCImage image;
ASSERT(dest_stride > 0);
image.format = GLC_IMAGE_RGB32;
image.height = area->bottom - area->top;
image.width = area->right - area->left;
image.pixels = dest;
image.stride = dest_stride;
glc_read_pixels(canvas->glc, area->left, area->top, &image);
}
static void gl_canvas_group_start(SpiceCanvas *spice_canvas, QRegion *region)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRect *glc_rects;
GLCRect *now, *end;
int num_rect;
pixman_box32_t *rects;
canvas_base_group_start(spice_canvas, region);
rects = pixman_region32_rectangles(region, &num_rect);
glc_rects = spice_new(GLCRect, num_rect);
now = glc_rects;
end = glc_rects + num_rect;
for (; now < end; now++, rects++) {
SET_GLC_BOX(now, rects);
}
glc_mask_rects(canvas->glc, num_rect, glc_rects, GLC_MASK_B);
free(glc_rects);
}
static void gl_canvas_put_image(SpiceCanvas *spice_canvas, const SpiceRect *dest, const uint8_t *src_data,
uint32_t src_width, uint32_t src_height, int src_stride,
const QRegion *clip)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
GLCRecti src;
GLCRecti gldest;
GLCImage image;
uint32_t i;
ASSERT(src_stride <= 0)
glc_clip_reset(canvas->glc);
if (clip) {
int num_rects;
pixman_box32_t *rects = pixman_region32_rectangles((pixman_region32_t *)clip,
&num_rects);
GLCRect rect;
if (num_rects == 0) {
rect.x = rect.y = rect.width = rect.height = 0;
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
} else {
SET_GLC_BOX(&rect, rects);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_SET);
for (i = 1; i < num_rects; i++) {
SET_GLC_BOX(&rect, rects + i);
glc_clip_rect(canvas->glc, &rect, GLC_CLIP_OP_OR);
}
}
}
SET_GLC_RECT(&gldest, dest);
src.x = src.y = 0;
src.width = src_width;
src.height = src_height;
image.format = GLC_IMAGE_RGB32;
image.width = src_width;
image.height = src_height;
src_stride = -src_stride;
image.stride = src_stride;
image.pixels = (uint8_t *)src_data - (src_height - 1) * src_stride;
image.pallet = NULL;
glc_draw_image(canvas->glc, &gldest, &src, &image, 0, 1);
glc_flush(canvas->glc);
}
static void gl_canvas_group_end(SpiceCanvas *spice_canvas)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
canvas_base_group_end(spice_canvas);
glc_clear_mask(canvas->glc, GLC_MASK_B);
}
static int need_init = 1;
static SpiceCanvasOps gl_canvas_ops;
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
)
{
GLCanvas *canvas;
int init_ok;
if (need_init) {
return NULL;
}
canvas = spice_new0(GLCanvas, 1);
if (!(canvas->glc = glc_create(width, height))) {
goto error_1;
}
canvas->private_data = NULL;
init_ok = canvas_base_init(&canvas->base, &gl_canvas_ops,
width, height, format
#ifdef SW_CANVAS_CACHE
, bits_cache
, palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, bits_cache
#endif
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
);
if (!init_ok) {
goto error_2;
}
return (SpiceCanvas *)canvas;
error_2:
glc_destroy(canvas->glc, 0);
error_1:
free(canvas);
return NULL;
}
void gl_canvas_set_textures_lost(SpiceCanvas *spice_canvas,
int textures_lost)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
canvas->textures_lost = textures_lost;
}
static void gl_canvas_destroy(SpiceCanvas *spice_canvas)
{
GLCanvas *canvas = (GLCanvas *)spice_canvas;
if (!canvas) {
return;
}
canvas_base_destroy(&canvas->base);
glc_destroy(canvas->glc, canvas->textures_lost);
free(canvas->private_data);
free(canvas);
}
void gl_canvas_init(void) //unsafe global function
{
if (!need_init) {
return;
}
need_init = 0;
canvas_base_init_ops(&gl_canvas_ops);
gl_canvas_ops.draw_fill = gl_canvas_draw_fill;
gl_canvas_ops.draw_copy = gl_canvas_draw_copy;
gl_canvas_ops.draw_opaque = gl_canvas_draw_opaque;
gl_canvas_ops.copy_bits = gl_canvas_copy_bits;
gl_canvas_ops.draw_text = gl_canvas_draw_text;
gl_canvas_ops.draw_stroke = gl_canvas_draw_stroke;
gl_canvas_ops.draw_rop3 = gl_canvas_draw_rop3;
gl_canvas_ops.draw_blend = gl_canvas_draw_blend;
gl_canvas_ops.draw_blackness = gl_canvas_draw_blackness;
gl_canvas_ops.draw_whiteness = gl_canvas_draw_whiteness;
gl_canvas_ops.draw_invers = gl_canvas_draw_invers;
gl_canvas_ops.draw_transparent = gl_canvas_draw_transparent;
gl_canvas_ops.draw_alpha_blend = gl_canvas_draw_alpha_blend;
gl_canvas_ops.put_image = gl_canvas_put_image;
gl_canvas_ops.clear = gl_canvas_clear;
gl_canvas_ops.read_bits = gl_canvas_read_bits;
gl_canvas_ops.group_start = gl_canvas_group_start;
gl_canvas_ops.group_end = gl_canvas_group_end;
gl_canvas_ops.destroy = gl_canvas_destroy;
rop3_init();
}

View File

@ -1,53 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "glc.h"
#include "canvas_base.h"
#include "region.h"
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#ifndef _H__GL_CANVAS
#define _H__GL_CANVAS
#ifdef __cplusplus
extern "C" {
#endif
SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
);
void gl_canvas_set_textures_lost(SpiceCanvas *canvas, int textures_lost);
void gl_canvas_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,61 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef GL_UTILS_H
#define GL_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RED_DEBUG
#define GLC_ERROR_TEST_FLUSH { \
GLenum gl_err; glFlush(); \
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
gluErrorString(gl_err)); \
abort(); \
} \
}
#define GLC_ERROR_TEST_FINISH { \
GLenum gl_err; glFinish(); \
if ((gl_err = glGetError()) != GL_NO_ERROR) { \
printf("%s[%d]: opengl error: %s\n", __FUNCTION__, __LINE__, \
gluErrorString(gl_err)); \
abort(); \
} \
}
#else
#define GLC_ERROR_TEST_FLUSH ;
#define GLC_ERROR_TEST_FINISH ;
#endif
#include "bitops.h"
#define find_msb spice_bit_find_msb
#define gl_get_to_power_two spice_bit_next_pow2
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,167 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _H_GL_CANVASE
#define _H_GL_CANVASE
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void * GLCCtx;
typedef void * GLCPattern;
typedef void * GLCPath;
typedef struct GLCRect {
double x;
double y;
double width;
double height;
} GLCRect;
typedef struct GLCRecti {
int x;
int y;
int width;
int height;
} GLCRecti;
typedef enum {
GLC_IMAGE_RGB32,
GLC_IMAGE_ARGB32,
} GLCImageFormat;
typedef struct GLCPImage {
GLCImageFormat format;
int width;
int height;
int stride;
uint8_t *pixels;
uint32_t *pallet;
} GLCImage;
GLCPattern glc_pattern_create(GLCCtx glc, int x_orign, int y_orign, const GLCImage *image);
void glc_pattern_set(GLCPattern pattern, int x_orign, int y_orign, const GLCImage *image);
void glc_pattern_destroy(GLCPattern pattern);
void glc_path_move_to(GLCPath path, double x, double y);
void glc_path_line_to(GLCPath path, double x, double y);
void glc_path_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
double p3_x, double p3_y);
void glc_path_rel_move_to(GLCPath path, double x, double y);
void glc_path_rel_line_to(GLCPath path, double x, double y);
void glc_path_rel_curve_to(GLCPath path, double p1_x, double p1_y, double p2_x, double p2_y,
double p3_x, double p3_y);
void glc_path_close(GLCPath path);
void glc_path_cleare(GLCPath);
GLCPath glc_path_create(GLCCtx glc);
void glc_path_destroy(GLCPath path);
void glc_set_rgb(GLCCtx glc, double red, double green, double blue);
void glc_set_rgba(GLCCtx glc, double red, double green, double blue, double alpha);
void glc_set_pattern(GLCCtx glc, GLCPattern pattern);
typedef enum {
GLC_OP_CLEAR = 0x1500,
GLC_OP_SET = 0x150F,
GLC_OP_COPY = 0x1503,
GLC_OP_COPY_INVERTED = 0x150C,
GLC_OP_NOOP = 0x1505,
GLC_OP_INVERT = 0x150A,
GLC_OP_AND = 0x1501,
GLC_OP_NAND = 0x150E,
GLC_OP_OR = 0x1507,
GLC_OP_NOR = 0x1508,
GLC_OP_XOR = 0x1506,
GLC_OP_EQUIV = 0x1509,
GLC_OP_AND_REVERSE = 0x1502,
GLC_OP_AND_INVERTED = 0x1504,
GLC_OP_OR_REVERSE = 0x150B,
GLC_OP_OR_INVERTED = 0x150D,
} GLCOp;
void glc_set_op(GLCCtx glc, GLCOp op);
void glc_set_alpha_factor(GLCCtx glc, double alpah);
typedef enum {
GLC_FILL_MODE_WINDING_ODD,
GLC_FILL_MODE_WINDING_NONZERO,
} GLCFillMode;
void glc_set_fill_mode(GLCCtx glc, GLCFillMode mode);
void glc_set_line_width(GLCCtx glc, double width);
void glc_set_line_end_cap(GLCCtx glc, int style);
void glc_set_line_join(GLCCtx glc, int style);
void glc_set_miter_limit(GLCCtx glc, int limit);
void glc_set_line_dash(GLCCtx glc, const double *dashes, int num_dashes, double offset);
typedef enum {
GLC_MASK_A,
GLC_MASK_B,
} GLCMaskID;
void glc_set_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height,
int stride, const uint8_t *bitmap, GLCMaskID id);
void glc_mask_rects(GLCCtx glc, int num_rect, GLCRect *rects, GLCMaskID id);
void glc_clear_mask(GLCCtx glc, GLCMaskID id);
typedef enum {
GLC_CLIP_OP_SET,
GLC_CLIP_OP_OR,
GLC_CLIP_OP_AND,
GLC_CLIP_OP_EXCLUDE,
} GLCClipOp;
void glc_clip_rect(GLCCtx glc, const GLCRect *rect, GLCClipOp op);
void glc_clip_path(GLCCtx glc, GLCPath path, GLCClipOp op);
void glc_clip_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
const uint8_t *bitmap, GLCClipOp op);
void glc_clip_reset(GLCCtx glc);
void glc_fill_rect(GLCCtx glc, const GLCRect *rect);
void glc_fill_path(GLCCtx glc, GLCPath path);
void _glc_fill_mask(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
const uint8_t *bitmap);
void glc_fill_alpha(GLCCtx glc, int x_dest, int y_dest, int width, int height, int stride,
const uint8_t *alpha_mask);
void glc_stroke_rect(GLCCtx glc, const GLCRect *rect);
void glc_stroke_path(GLCCtx glc, GLCPath path);
void glc_draw_image(GLCCtx glc, const GLCRecti *dest, const GLCRecti *src, const GLCImage *image,
int scale_mode, double alpha);
void glc_copy_pixels(GLCCtx glc, int x_dest, int y_dest, int x_src, int y_src, int width,
int height);
void glc_read_pixels(GLCCtx glc, int x, int y, GLCImage *image);
void glc_flush(GLCCtx glc);
void glc_clear(GLCCtx glc);
GLCCtx glc_create(int width, int height);
void glc_destroy(GLCCtx glc, int textures_lost);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -45,9 +45,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <spice/macros.h>
@ -84,7 +82,7 @@ typedef struct lineGC *GCPtr;
#define miWideDash spice_canvas_wide_dash_line
#define miWideLine spice_canvas_wide_line
static INLINE int ICEIL (double x)
static inline int ICEIL (double x)
{
int _cTmp = (int)x;
return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp + 1;
@ -412,7 +410,7 @@ miStepDash (int dist, /* distance to step */
totallen = 0;
for (i = 0; i < numInDashList; i++)
totallen += pDash[i];
if (totallen <= dist)
if (totallen > 0 && totallen <= dist)
dist = dist % totallen;
while (dist >= pDash[dashIndex]) {
dist -= pDash[dashIndex];
@ -806,14 +804,14 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
newwidths = xrealloc (newspans->widths,
ysizes[index] * sizeof (int));
if (!newpoints || !newwidths) {
int i;
for (i = 0; i < ylength; i++) {
xfree (yspans[i].points);
xfree (yspans[i].widths);
}
xfree (yspans);
xfree (ysizes);
xfree (newpoints);
xfree (newwidths);
miDisposeSpanGroup (spanGroup);
return;
}
@ -836,8 +834,6 @@ miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
points = (DDXPointRec*)xalloc (count * sizeof (DDXPointRec));
widths = (int *)xalloc (count * sizeof (int));
if (!points || !widths) {
int i;
for (i = 0; i < ylength; i++) {
xfree (yspans[i].points);
xfree (yspans[i].widths);
@ -929,7 +925,7 @@ end of the line, we will find the largest number of Y steps that
satisfies the inequality. In that case, since we are representing
the Y steps as (dy - N), we will actually want to solve for the
smallest N in that equation.
Case 1: X major, starting X coordinate moved by M steps
-2dx <= 2Mdy - 2Ndx - dx - B < 0
@ -977,7 +973,7 @@ steps, so we want the highest N, so we use the < inequality:
= floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
= floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
= floor((2Mdy + dx + B - 1) / 2dx)
Case 3: Y major, starting X coordinate moved by M steps
-2dy <= 2Ndx - 2Mdy - dy - B < 0
@ -1023,7 +1019,7 @@ Same analysis as Case 4, but we want the smallest number of Y steps
which means the largest N, so we use the <= inequality:
N = floor((2Mdy + dy - B) / 2dx)
Now let's try the Y coordinates, we have the same 4 cases.
Case 5: X major, starting Y coordinate moved by N steps
@ -1068,7 +1064,7 @@ Same derivations as Case 6, but we want the smallest # of X steps
which means the largest M, so use the <= inequality:
M = floor((2Ndx + dx - B) / 2dy)
Case 7: Y major, starting Y coordinate moved by N steps
-2dy <= 2Ndx - 2Mdy - dy - B < 0
@ -1113,7 +1109,7 @@ steps which means the largest M, so we use the < inequality:
= floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
= floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
= floor((2Ndx + dy + B - 1) / 2dy)
So, our equations are:
1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
@ -1826,7 +1822,7 @@ miFillRectPolyHelper (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x
}
static int
miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
miPolyBuildEdge (SPICE_GNUC_UNUSED double x0, double y0, double k, /* x0 * dy - y0 * dx */
int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
{
int x, y, e;
@ -1837,15 +1833,6 @@ miPolyBuildEdge (double x0, double y0, double k, /* x0 * dy - y0 * dx */
dx = -dx;
k = -k;
}
#ifdef NOTDEF
{
double realk, kerror;
realk = x0 * dy - y0 * dx;
kerror = Fabs (realk - k);
if (kerror > .1)
printf ("realk: %g k: %g\n", realk, k);
}
#endif
y = ICEIL (y0);
xady = ICEIL (k) + y * dx;
@ -1970,7 +1957,11 @@ miPolyBuildPoly (PolyVertexPtr vertices,
}
static void
miLineOnePoint (GCPtr pGC, Boolean foreground, SpanDataPtr spanData, int x, int y)
miLineOnePoint (GCPtr pGC,
Boolean foreground,
SPICE_GNUC_UNUSED SpanDataPtr spanData,
int x,
int y)
{
DDXPointRec pt;
int wid;
@ -2430,7 +2421,7 @@ miLineArc (GCPtr pGC,
int xorgi = 0, yorgi = 0;
Spans spanRec;
int n;
PolyEdgeRec edge1, edge2;
PolyEdgeRec edge1 = { 0 }, edge2 = { 0 };
int edgey1, edgey2;
Boolean edgeleft1, edgeleft2;
@ -2501,13 +2492,18 @@ miLineArc (GCPtr pGC,
}
static void
miLineProjectingCap (GCPtr pGC, Boolean foreground,
SpanDataPtr spanData, LineFacePtr face, Boolean isLeft,
double xorg, double yorg, Boolean isInt)
miLineProjectingCap (GCPtr pGC,
Boolean foreground,
SpanDataPtr spanData,
LineFacePtr face,
Boolean isLeft,
SPICE_GNUC_UNUSED double xorg,
SPICE_GNUC_UNUSED double yorg,
Boolean isInt)
{
int xorgi = 0, yorgi = 0;
int lw;
PolyEdgeRec lefts[2], rights[2];
PolyEdgeRec lefts[4], rights[4];
int lefty, righty, topy, bottomy;
PolyEdgePtr left, right;
PolyEdgePtr top, bottom;
@ -2665,7 +2661,7 @@ miWideSegment (GCPtr pGC,
PolyEdgePtr top, bottom;
int lefty, righty, topy, bottomy;
int signdx;
PolyEdgeRec lefts[2], rights[2];
PolyEdgeRec lefts[4], rights[4];
LineFacePtr tface;
int lw = pGC->lineWidth;
@ -2980,9 +2976,9 @@ miWideDashSegment (GCPtr pGC,
double L, l;
double k;
PolyVertexRec vertices[4];
PolyVertexRec saveRight = { 0 }, saveBottom;
PolyVertexRec saveRight = { 0, 0 }, saveBottom;
PolySlopeRec slopes[4];
PolyEdgeRec left[2], right[2];
PolyEdgeRec left[4], right[4];
LineFaceRec lcapFace, rcapFace;
int nleft, nright;
int h;

View File

@ -46,17 +46,17 @@ SOFTWARE.
******************************************************************/
#ifndef LINES_H
#define LINES_H
#ifndef H_SPICE_COMMON_LINES
#define H_SPICE_COMMON_LINES
#include <pixman_utils.h>
#include <stdlib.h>
#include <string.h>
#include <spice/macros.h>
#include "pixman_utils.h"
#include "draw.h"
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
typedef struct lineGC lineGC;
@ -131,8 +131,6 @@ extern int spice_canvas_clip_spans(pixman_region32_t *clip_region,
int *new_widths,
int sorted);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif /* LINES_H */
#endif // H_SPICE_COMMON_LINES

71
common/log.c Normal file
View File

@ -0,0 +1,71 @@
/*
Copyright (C) 2012-2015 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <stdlib.h>
#include <common/recorder.h>
#include "log.h"
#include "backtrace.h"
#define G_LOG_DOMAIN "Spice"
SPICE_CONSTRUCTOR_FUNC(spice_log_init)
{
recorder_dump_on_common_signals(0, 0);
}
G_GNUC_PRINTF(5, 0)
static void spice_logv(const char *log_domain,
GLogLevelFlags log_level,
const char *strloc,
const char *function,
const char *format,
va_list args)
{
GString *log_msg;
log_msg = g_string_new(NULL);
if (strloc && function) {
g_string_append_printf(log_msg, "%s:%s: ", strloc, function);
}
if (format) {
g_string_append_vprintf(log_msg, format, args);
}
g_log(log_domain, log_level, "%s", log_msg->str);
g_string_free(log_msg, TRUE);
if ((log_level & G_LOG_LEVEL_CRITICAL) != 0) {
spice_backtrace();
abort();
}
}
void spice_log(GLogLevelFlags log_level,
const char *strloc,
const char *function,
const char *format,
...)
{
va_list args;
va_start (args, format);
spice_logv (G_LOG_DOMAIN, log_level, strloc, function, format, args);
va_end (args);
}

110
common/log.h Normal file
View File

@ -0,0 +1,110 @@
/*
Copyright (C) 2012 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef H_SPICE_COMMON_LOG
#define H_SPICE_COMMON_LOG
#include <stdarg.h>
#include <stdio.h>
#include <glib.h>
#include <spice/macros.h>
#include "macros.h"
SPICE_BEGIN_DECLS
#ifdef SPICE_LOG_DOMAIN
#error Do not use obsolete SPICE_LOG_DOMAIN macro, is currently unused
#endif
#define SPICE_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__)
void spice_log(GLogLevelFlags log_level,
const char *strloc,
const char *function,
const char *format,
...) G_GNUC_PRINTF(4, 5);
/* FIXME: name is misleading, this aborts.. */
#define spice_return_if_fail(x) G_STMT_START { \
if G_LIKELY(x) { } else { \
spice_critical("condition `%s' failed", #x); \
return; \
} \
} G_STMT_END
/* FIXME: name is misleading, this aborts.. */
#define spice_return_val_if_fail(x, val) G_STMT_START { \
if G_LIKELY(x) { } else { \
spice_critical("condition `%s' failed", #x); \
return (val); \
} \
} G_STMT_END
#define spice_warn_if_reached() G_STMT_START { \
spice_log(G_LOG_LEVEL_WARNING, SPICE_STRLOC, __FUNCTION__, "should not be reached"); \
} G_STMT_END
#define spice_info(...) G_STMT_START { \
spice_log(G_LOG_LEVEL_INFO, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
} G_STMT_END
#define spice_debug(...) G_STMT_START { \
spice_log(G_LOG_LEVEL_DEBUG, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
} G_STMT_END
#define spice_warning(...) G_STMT_START { \
spice_log(G_LOG_LEVEL_WARNING, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
} G_STMT_END
#define spice_critical(...) G_STMT_START { \
spice_log(G_LOG_LEVEL_CRITICAL, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
SPICE_UNREACHABLE; \
} G_STMT_END
#define spice_error(...) G_STMT_START { \
spice_log(G_LOG_LEVEL_ERROR, SPICE_STRLOC, __FUNCTION__, "" __VA_ARGS__); \
SPICE_UNREACHABLE; \
} G_STMT_END
#define spice_warn_if_fail(x) G_STMT_START { \
if G_LIKELY(x) { } else { \
spice_warning("condition `%s' failed", #x); \
} \
} G_STMT_END
#define spice_assert(x) G_STMT_START { \
if G_LIKELY(x) { } else { \
spice_error("assertion `%s' failed", #x); \
} \
} G_STMT_END
#if ENABLE_EXTRA_CHECKS
enum { spice_extra_checks = 1 };
#else
enum { spice_extra_checks = 0 };
#endif
#define spice_extra_assert(x) G_STMT_START { \
if (!spice_extra_checks || G_LIKELY(x)) { } else { \
spice_error("assertion `%s' failed", #x); \
} \
} G_STMT_END
SPICE_END_DECLS
#endif // H_SPICE_COMMON_LOG

View File

@ -43,29 +43,16 @@
SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "lz.h"
#define DEBUG
#ifdef DEBUG
#define ASSERT(usr, x) \
if (!(x)) (usr)->error(usr, "%s: ASSERT %s failed\n", __FUNCTION__, #x);
#else
#define ASSERT(usr, x)
#endif
#define HASH_LOG 13
#define HASH_SIZE (1 << HASH_LOG)
#define HASH_MASK (HASH_SIZE - 1)
/* Maximum image size, mainly to avoid possible integer overflows */
#define SPICE_MAX_IMAGE_SIZE (1024 * 1024 * 1024 - 1)
typedef struct LzImageSegment LzImageSegment;
struct LzImageSegment {
@ -102,7 +89,6 @@ typedef struct Encoder {
// (2) a pointer to the first byte in the segment that matches the word
HashEntry htab[HASH_SIZE];
uint8_t *io_start;
uint8_t *io_now;
uint8_t *io_end;
size_t io_bytes_count;
@ -113,7 +99,7 @@ typedef struct Encoder {
/****************************************************/
/* functions for managing the pool of image segments*/
/****************************************************/
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder);
static inline LzImageSegment *lz_alloc_image_seg(Encoder *encoder);
static void lz_reset_image_seg(Encoder *encoder);
static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
unsigned int num_first_lines);
@ -121,7 +107,7 @@ static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
// return a free image segment if one exists. Make allocation if needed. adds it to the
// tail of the image segments lists
static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
static inline LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
{
LzImageSegment *ret;
@ -148,7 +134,7 @@ static INLINE LzImageSegment *lz_alloc_image_seg(Encoder *encoder)
}
// adding seg to the head of free segments (lz_reset_image_seg removes it from used ones)
static INLINE void __lz_free_image_seg(Encoder *encoder, LzImageSegment *seg)
static inline void __lz_free_image_seg(Encoder *encoder, LzImageSegment *seg)
{
seg->next = encoder->free_image_segs;
encoder->free_image_segs = seg;
@ -184,7 +170,7 @@ static int lz_read_image_segments(Encoder *encoder, uint8_t *first_lines,
uint8_t* lines = first_lines;
int row;
ASSERT(encoder->usr, !encoder->head_image_segs);
spice_return_val_if_fail(!encoder->head_image_segs, FALSE);
image_seg = lz_alloc_image_seg(encoder);
if (!image_seg) {
@ -224,7 +210,7 @@ error_1:
/**************************************************************************
* Handling encoding and decoding of a byte
***************************************************************************/
static INLINE int more_io_bytes(Encoder *encoder)
static inline int more_io_bytes(Encoder *encoder)
{
uint8_t *io_ptr;
int num_io_bytes = encoder->usr->more_space(encoder->usr, &io_ptr);
@ -234,20 +220,20 @@ static INLINE int more_io_bytes(Encoder *encoder)
return num_io_bytes;
}
static INLINE void encode(Encoder *encoder, uint8_t byte)
static inline void encode(Encoder *encoder, uint8_t byte)
{
if (encoder->io_now == encoder->io_end) {
if (more_io_bytes(encoder) <= 0) {
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
}
ASSERT(encoder->usr, encoder->io_now);
spice_return_if_fail(encoder->io_now);
}
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
spice_return_if_fail(encoder->io_now < encoder->io_end);
*(encoder->io_now++) = byte;
}
static INLINE void encode_32(Encoder *encoder, unsigned int word)
static inline void encode_32(Encoder *encoder, unsigned int word)
{
encode(encoder, (uint8_t)(word >> 24));
encode(encoder, (uint8_t)(word >> 16) & 0x0000ff);
@ -255,37 +241,32 @@ static INLINE void encode_32(Encoder *encoder, unsigned int word)
encode(encoder, (uint8_t)(word & 0x0000ff));
}
static INLINE void encode_copy_count(Encoder *encoder, uint8_t copy_count)
static inline void encode_copy_count(Encoder *encoder, uint8_t copy_count)
{
encode(encoder, copy_count);
encoder->io_last_copy = encoder->io_now - 1; // io_now cannot be the first byte of the buffer
}
static INLINE void update_copy_count(Encoder *encoder, uint8_t copy_count)
static inline void update_copy_count(Encoder *encoder, uint8_t copy_count)
{
ASSERT(encoder->usr, encoder->io_last_copy);
spice_return_if_fail(encoder->io_last_copy);
*(encoder->io_last_copy) = copy_count;
}
static INLINE void encode_level(Encoder *encoder, uint8_t level_code)
{
*(encoder->io_start) |= level_code;
}
// decrease the io ptr by 1
static INLINE void compress_output_prev(Encoder *encoder)
static inline void compress_output_prev(Encoder *encoder)
{
// io_now cannot be the first byte of the buffer
encoder->io_now--;
// the function should be called only when copy count is written unnecessarily by lz_compress
ASSERT(encoder->usr, encoder->io_now == encoder->io_last_copy)
spice_return_if_fail(encoder->io_now == encoder->io_last_copy);
}
static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
{
ASSERT(encoder->usr, io_ptr <= io_ptr_end);
spice_return_val_if_fail(io_ptr <= io_ptr_end, FALSE);
encoder->io_bytes_count = io_ptr_end - io_ptr;
encoder->io_start = io_ptr;
encoder->io_now = io_ptr;
encoder->io_end = io_ptr_end;
encoder->io_last_copy = NULL;
@ -293,20 +274,20 @@ static int encoder_reset(Encoder *encoder, uint8_t *io_ptr, uint8_t *io_ptr_end)
return TRUE;
}
static INLINE uint8_t decode(Encoder *encoder)
static inline uint8_t decode(Encoder *encoder)
{
if (encoder->io_now == encoder->io_end) {
int num_io_bytes = more_io_bytes(encoder);
if (num_io_bytes <= 0) {
encoder->usr->error(encoder->usr, "%s: no more bytes\n", __FUNCTION__);
}
ASSERT(encoder->usr, encoder->io_now);
spice_assert(encoder->io_now);
}
ASSERT(encoder->usr, encoder->io_now < encoder->io_end);
spice_assert(encoder->io_now < encoder->io_end);
return *(encoder->io_now++);
}
static INLINE uint32_t decode_32(Encoder *encoder)
static inline uint32_t decode_32(Encoder *encoder)
{
uint32_t word = 0;
word |= decode(encoder);
@ -319,7 +300,7 @@ static INLINE uint32_t decode_32(Encoder *encoder)
return word;
}
static INLINE int is_io_to_decode_end(Encoder *encoder)
static inline int is_io_to_decode_end(Encoder *encoder)
{
if (encoder->io_now != encoder->io_end) {
return FALSE;
@ -393,30 +374,23 @@ void lz_destroy(LzContext *lz)
#endif
#ifdef __GNUC__
#define ATTR_PACKED __attribute__ ((__packed__))
#else
#define ATTR_PACKED
#pragma pack(push)
#pragma pack(1)
#endif
#include <spice/start-packed.h>
/* the palette images will be treated as one byte pixels. Their width should be transformed
accordingly.
*/
typedef struct ATTR_PACKED one_byte_pixel_t {
typedef struct SPICE_ATTR_PACKED one_byte_pixel_t {
uint8_t a;
} one_byte_pixel_t;
typedef struct ATTR_PACKED rgb32_pixel_t {
typedef struct SPICE_ATTR_PACKED rgb32_pixel_t {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t pad;
} rgb32_pixel_t;
typedef struct ATTR_PACKED rgb24_pixel_t {
typedef struct SPICE_ATTR_PACKED rgb24_pixel_t {
uint8_t b;
uint8_t g;
uint8_t r;
@ -424,11 +398,7 @@ typedef struct ATTR_PACKED rgb24_pixel_t {
typedef uint16_t rgb16_pixel_t;
#ifndef __GNUC__
#pragma pack(pop)
#endif
#undef ATTR_PACKED
#include <spice/end-packed.h>
#define MAX_COPY 32
@ -476,6 +446,13 @@ typedef uint16_t rgb16_pixel_t;
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_A8
#include "lz_compress_tmpl.c"
#define LZ_A8
#include "lz_decompress_tmpl.c"
#define LZ_A8
#define TO_RGB32
#include "lz_decompress_tmpl.c"
#define LZ_RGB16
#include "lz_compress_tmpl.c"
@ -504,6 +481,44 @@ typedef uint16_t rgb16_pixel_t;
#undef LZ_UNEXPECT_CONDITIONAL
#undef LZ_EXPECT_CONDITIONAL
static void lz_set_sizes(Encoder *encoder, int type, int width, int height, int stride)
{
if (width < 0) {
encoder->usr->error(encoder->usr, "invalid lz width %d\n", width);
}
if (height < 0) {
encoder->usr->error(encoder->usr, "invalid lz height %d\n", height);
}
if (stride < 0) {
encoder->usr->error(encoder->usr, "invalid lz stride %d\n", stride);
}
if (IS_IMAGE_TYPE_PLT[type]) {
if (stride > (width / PLT_PIXELS_PER_BYTE[type])) {
if (((width % PLT_PIXELS_PER_BYTE[type]) == 0) || (
(stride - (width / PLT_PIXELS_PER_BYTE[type])) > 1)) {
encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
}
}
} else {
if (stride != width * RGB_BYTES_PER_PIXEL[type]) {
encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb) %d != %d * %d (%d)\n",
stride, width, RGB_BYTES_PER_PIXEL[type],
type);
}
}
// avoid too big images
if ((uint64_t) stride * height > SPICE_MAX_IMAGE_SIZE) {
encoder->usr->error(encoder->usr, "image too large\n");
}
encoder->type = type;
encoder->width = width;
encoder->height = height;
encoder->stride = stride;
}
int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_down,
uint8_t *lines, unsigned int num_lines, int stride,
uint8_t *io_ptr, unsigned int num_io_bytes)
@ -511,23 +526,7 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
Encoder *encoder = (Encoder *)lz;
uint8_t *io_ptr_end = io_ptr + num_io_bytes;
encoder->type = type;
encoder->width = width;
encoder->height = height;
encoder->stride = stride;
if (IS_IMAGE_TYPE_PLT[encoder->type]) {
if (encoder->stride > (width / PLT_PIXELS_PER_BYTE[encoder->type])) {
if (((width % PLT_PIXELS_PER_BYTE[encoder->type]) == 0) || (
(encoder->stride - (width / PLT_PIXELS_PER_BYTE[encoder->type])) > 1)) {
encoder->usr->error(encoder->usr, "stride overflows (plt)\n");
}
}
} else {
if (encoder->stride != width * RGB_BYTES_PER_PIXEL[encoder->type]) {
encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n");
}
}
lz_set_sizes(encoder, type, width, height, stride);
// assign the output buffer
if (!encoder_reset(encoder, io_ptr, io_ptr_end)) {
@ -571,6 +570,9 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
case LZ_IMAGE_TYPE_XXXA:
lz_rgb_alpha_compress(encoder);
break;
case LZ_IMAGE_TYPE_A8:
lz_a8_compress(encoder);
break;
case LZ_IMAGE_TYPE_INVALID:
default:
encoder->usr->error(encoder->usr, "bad image type\n");
@ -610,10 +612,15 @@ void lz_decode_begin(LzContext *lz, uint8_t *io_ptr, unsigned int num_io_bytes,
encoder->usr->error(encoder->usr, "bad version\n");
}
encoder->type = (LzImageType)decode_32(encoder);
encoder->width = decode_32(encoder);
encoder->height = decode_32(encoder);
encoder->stride = decode_32(encoder);
int type = decode_32(encoder);
if (type <= LZ_IMAGE_TYPE_INVALID || type > LZ_IMAGE_TYPE_A8) {
encoder->usr->error(encoder->usr, "invalid lz type %d\n", type);
}
int width = decode_32(encoder);
int height = decode_32(encoder);
int stride = decode_32(encoder);
lz_set_sizes(encoder, type, width, height, stride);
*out_top_down = decode_32(encoder);
*out_width = encoder->width;
@ -646,6 +653,7 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
if (!encoder->palette) {
encoder->usr->error(encoder->usr,
"a palette is missing (for bpp to rgb decoding)\n");
return;
}
switch (encoder->type) {
case LZ_IMAGE_TYPE_PLT1_BE:
@ -707,7 +715,7 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
if (encoder->type == to_type) {
out_size = lz_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size);
ASSERT(encoder->usr, alpha_size == size);
spice_assert(alpha_size == size);
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
@ -720,6 +728,17 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
break;
case LZ_IMAGE_TYPE_A8:
if (encoder->type == to_type) {
alpha_size = lz_a8_decompress(encoder, (one_byte_pixel_t *)buf, size);
out_size = alpha_size;
} else if (to_type == LZ_IMAGE_TYPE_RGB32) {
alpha_size = lz_a8_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
out_size = alpha_size;
} else {
encoder->usr->error(encoder->usr, "unsupported output format\n");
}
break;
case LZ_IMAGE_TYPE_PLT1_LE:
case LZ_IMAGE_TYPE_PLT1_BE:
case LZ_IMAGE_TYPE_PLT4_LE:
@ -731,8 +750,8 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
}
}
ASSERT(encoder->usr, is_io_to_decode_end(encoder));
ASSERT(encoder->usr, out_size == size);
spice_assert(is_io_to_decode_end(encoder));
spice_assert(out_size == size);
if (out_size != size) {
encoder->usr->error(encoder->usr, "bad decode size\n");

View File

@ -3,24 +3,26 @@
dictionary compression for images based on fastlz (http://www.fastlz.org/)
(Distributed under MIT license).
*/
#ifndef __LZ_H
#define __LZ_H
#ifndef H_SPICE_COMMON_LZ
#define H_SPICE_COMMON_LZ
#include <spice/macros.h>
#include "lz_common.h"
#include "lz_config.h"
#include "draw.h"
#include "macros.h"
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
typedef void *LzContext;
typedef struct LzUsrContext LzUsrContext;
struct LzUsrContext {
void (*error)(LzUsrContext *usr, const char *fmt, ...);
void (*warn)(LzUsrContext *usr, const char *fmt, ...);
void (*info)(LzUsrContext *usr, const char *fmt, ...);
SPICE_GNUC_NORETURN
SPICE_GNUC_PRINTF(2, 3) void (*error)(LzUsrContext *usr, const char *fmt, ...);
SPICE_GNUC_PRINTF(2, 3) void (*warn)(LzUsrContext *usr, const char *fmt, ...);
SPICE_GNUC_PRINTF(2, 3) void (*info)(LzUsrContext *usr, const char *fmt, ...);
void *(*malloc)(LzUsrContext *usr, int size);
void (*free)(LzUsrContext *usr, void *ptr);
int (*more_space)(LzUsrContext *usr, uint8_t **io_ptr); // get the next chunk of the
@ -75,8 +77,6 @@ LzContext *lz_create(LzUsrContext *usr);
void lz_destroy(LzContext *lz);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif // __LZ_H
#endif // H_SPICE_COMMON_LZ

View File

@ -20,14 +20,13 @@
/*common header for encoder and decoder*/
#ifndef _LZ_COMMON_H
#define _LZ_COMMON_H
#ifndef H_SPICE_COMMON_LZ_COMMON
#define H_SPICE_COMMON_LZ_COMMON
#ifdef __cplusplus
extern "C" {
#endif
#include <spice/macros.h>
#include "verify.h"
//#define DEBUG
SPICE_BEGIN_DECLS
/* change the max window size will require change in the encoding format*/
#define LZ_MAX_WINDOW_SIZE (1 << 25)
@ -44,26 +43,30 @@ typedef enum {
LZ_IMAGE_TYPE_RGB24,
LZ_IMAGE_TYPE_RGB32,
LZ_IMAGE_TYPE_RGBA,
LZ_IMAGE_TYPE_XXXA
LZ_IMAGE_TYPE_XXXA,
LZ_IMAGE_TYPE_A8
} LzImageType;
#define LZ_IMAGE_TYPE_MASK 0x0f
#define LZ_IMAGE_TYPE_LOG 4 // number of bits required for coding the image type
/* access to the arrays is based on the image types */
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0};
static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1};
static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1};
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4};
static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1};
verify(SPICE_N_ELEMENTS(IS_IMAGE_TYPE_PLT) == (LZ_IMAGE_TYPE_A8 + 1));
verify(SPICE_N_ELEMENTS(IS_IMAGE_TYPE_RGB) == (LZ_IMAGE_TYPE_A8 + 1));
verify(SPICE_N_ELEMENTS(PLT_PIXELS_PER_BYTE) == (LZ_IMAGE_TYPE_PLT8 + 1));
verify(SPICE_N_ELEMENTS(RGB_BYTES_PER_PIXEL) == (LZ_IMAGE_TYPE_A8 + 1));
#define LZ_MAGIC (*(uint32_t *)"LZ ")
/* ASCII "LZ " */
#define LZ_MAGIC 0x20205a4c
#define LZ_VERSION_MAJOR 1U
#define LZ_VERSION_MINOR 1U
#define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif // _LZ_COMMON_H
#endif // H_SPICE_COMMON_LZ_COMMON

View File

@ -40,11 +40,9 @@
SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define DJB2_START 5381;
#define DJB2_START 5381
#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;}
/*
@ -71,6 +69,21 @@
}
#endif
#ifdef LZ_A8
#define PIXEL one_byte_pixel_t
#define FNAME(name) lz_a8_##name
#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes
// from the pixel
#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a)
#define HASH_FUNC(v, p) { \
v = DJB2_START; \
DJB2_HASH(v, p[0].a); \
DJB2_HASH(v, p[1].a); \
DJB2_HASH(v, p[2].a); \
v &= HASH_MASK; \
}
#endif
#ifdef LZ_RGB_ALPHA
//#undef LZ_RGB_ALPHA
#define PIXEL rgb32_pixel_t
@ -90,9 +103,8 @@
#ifdef LZ_RGB16
#define PIXEL rgb16_pixel_t
#define FNAME(name) lz_rgb16_##name
#define GET_r(pix) (((pix) >> 10) & 0x1f)
#define GET_g(pix) (((pix) >> 5) & 0x1f)
#define GET_b(pix) ((pix) & 0x1f)
#define GET_rgb(pix) ((pix) & 0x7fffu)
#define SAME_PIXEL(p1, p2) (GET_rgb(p1) == GET_rgb(p2))
#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);}
#define HASH_FUNC(v, p) { \
@ -110,20 +122,17 @@
#ifdef LZ_RGB24
#define PIXEL rgb24_pixel_t
#define FNAME(name) lz_rgb24_##name
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
#endif
#ifdef LZ_RGB32
#define PIXEL rgb32_pixel_t
#define FNAME(name) lz_rgb32_##name
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
#endif
#if defined(LZ_RGB24) || defined(LZ_RGB32)
#define GET_r(pix) ((pix).r)
#define GET_g(pix) ((pix).g)
#define GET_b(pix) ((pix).b)
#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);}
#define SAME_PIXEL(p1, p2) ((p1).r == (p2).r && (p1).g == (p2).g && (p1).b == (p2).b)
#define HASH_FUNC(v, p) { \
v = DJB2_START; \
DJB2_HASH(v, p[0].r); \
@ -139,12 +148,6 @@
}
#endif
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
#define SAME_PIXEL(p1, p2) (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
GET_b(p1) == GET_b(p2))
#endif
#define PIXEL_ID(pix_ptr, seg_ptr) (pix_ptr - ((PIXEL *)seg_ptr->lines) + seg_ptr->size_delta)
// when encoding, the ref can be in previous segment, and we should check that it doesn't
@ -177,7 +180,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
size_t distance;
/* minimum match length */
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
size_t len = 3;
#elif defined(LZ_RGB16)
size_t len = 2;
@ -199,9 +202,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
ip += 3;
ref = anchor + 2;
ref_limit = (PIXEL *)(seg->lines_end);
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
len = 3;
#endif
goto match;
}
}
@ -234,7 +235,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
ip++;
/* minimum match length for rgb16 is 2 and for plt and alpha is 3 */
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16)
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16) || defined(LZ_A8)
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
@ -244,7 +245,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
ip++;
#endif
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
@ -255,7 +256,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
#endif
/* far, needs at least 5-byte match */
if (distance >= MAX_DISTANCE) {
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
if (ref >= (ref_limit - 1)) {
goto literal;
}
@ -272,7 +273,7 @@ static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
ref++;
ip++;
len++;
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
@ -310,18 +311,15 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
// TODO: maybe separate a run from the same seg or from different ones in order
// to spare ref < ref_limit and that way we can also perform 8 calls of
// (ref++ != ip++) outside a loop
for (;;) {
while ((ip < ip_bound) && (ref < ref_limit)) {
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
break;
} else {
ref++;
ip++;
}
while ((ip < ip_bound) && (ref < ref_limit)) {
if (!SAME_PIXEL(*ref, *ip)) {
ref++;
ip++;
break;
} else {
ref++;
ip++;
}
break;
}
}
@ -393,27 +391,23 @@ match: // RLE or dictionary (both are encoded by distance from ref (-1) a
/* update the hash at match boundary */
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
if (ip > anchor) {
if (ip > anchor)
#endif
HASH_FUNC(hval, ip);
encoder->htab[hval].ref = (uint8_t *)ip;
{
HASH_FUNC(hval, ip);
encoder->htab[hval].ref = (uint8_t *)ip;
encoder->htab[hval].image_seg = seg;
}
ip++;
encoder->htab[hval].image_seg = seg;
#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32)
} else {ip++;
}
#endif
#if defined(LZ_RGB24) || defined(LZ_RGB32)
if (ip > anchor) {
if (ip > anchor)
#endif
HASH_FUNC(hval, ip);
encoder->htab[hval].ref = (uint8_t *)ip;
{
HASH_FUNC(hval, ip);
encoder->htab[hval].ref = (uint8_t *)ip;
encoder->htab[hval].image_seg = seg;
}
ip++;
encoder->htab[hval].image_seg = seg;
#if defined(LZ_RGB24) || defined(LZ_RGB32)
} else {ip++;
}
#endif
/* assuming literal copy */
encode_copy_count(encoder, MAX_COPY - 1);
continue;
@ -513,17 +507,11 @@ static void FNAME(compress)(Encoder *encoder)
#undef PIXEL
#undef ENCODE_PIXEL
#undef SAME_PIXEL
#undef LZ_READU16
#undef HASH_FUNC
#undef BYTES_TO_16
#undef HASH_FUNC_16
#undef GET_r
#undef GET_g
#undef GET_b
#undef GET_CODE
#undef GET_rgb
#undef LZ_PLT
#undef LZ_RGB_ALPHA
#undef LZ_RGB16
#undef LZ_RGB24
#undef LZ_RGB32
#undef HASH_FUNC2
#undef LZ_A8

View File

@ -18,8 +18,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __LZ_CONFIG_H
#define __LZ_CONFIG_H
#ifndef H_SPICE_COMMON_LZ_CONFIG
#define H_SPICE_COMMON_LZ_CONFIG
#include <spice/types.h>
#include <spice/macros.h>
@ -36,4 +36,4 @@
#endif // QXLDD
#endif //__GNUC__
#endif //__LZ_CONFIG_H
#endif // H_SPICE_COMMON_LZ_CONFIG

View File

@ -50,18 +50,16 @@
/*
For each output pixel type the following macros are defined:
OUT_PIXEL - the output pixel type
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and increases
out. Used in RLE. Need special handling because in alpha we
copy only the pad byte.
OUT_PIXEL - the output pixel type
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and increases
out. Used in RLE. Need special handling because in alpha we
copy only the pad byte.
COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out.
Increases ref and out.
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
buffer. Increases out.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if !defined(LZ_RGB_ALPHA)
#define COPY_PIXEL(p, out) (*out++ = p)
@ -153,6 +151,26 @@
#endif // TO_RGB32
#endif
#ifndef CAST_PLT_DISTANCE
#define CAST_PLT_DISTANCE(dist) (dist)
#endif
#ifdef LZ_A8
#ifndef TO_RGB32
#define OUT_PIXEL one_byte_pixel_t
#define FNAME(name) lz_a8_##name
#define COPY_COMP_PIXEL(encoder, out) {out->a = decode(encoder); out++;}
#else // TO_RGB32
#define OUT_PIXEL rgb32_pixel_t
#define FNAME(name) lz_a8_to_rgb32_##name
#define COPY_COMP_PIXEL(encoder, out) { \
(out)->b = (out)->g = (out)->r = 0; \
(out)->pad = decode(encoder); \
(out)++; \
}
#endif
#endif
#ifdef LZ_RGB16
#ifndef TO_RGB32
#define OUT_PIXEL rgb16_pixel_t
@ -204,18 +222,18 @@
static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
{
OUT_PIXEL *op = out_buf;
OUT_PIXEL *op_limit = out_buf + size;
uint32_t ctrl = decode(encoder);
int loop = TRUE;
OUT_PIXEL *const op_limit = out_buf + size;
do {
const OUT_PIXEL *ref = op;
uint32_t len = ctrl >> 5;
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
for (;;) {
uint32_t ctrl = decode(encoder);
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
/* retrieving the reference and the match length */
const OUT_PIXEL *ref = op;
uint32_t len = ctrl >> 5;
uint32_t ofs = (ctrl & 31) << 8; // 5 MSb of distance
uint8_t code;
len--;
//ref -= ofs;
@ -237,7 +255,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
}
}
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
len += 3; // length is biased by 2 + 1 (fixing bias)
#elif defined(LZ_RGB16)
len += 2; // length is biased by 1 + 1 (fixing bias)
@ -246,17 +264,13 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
#endif
ofs += 1; // offset is biased by 1 (fixing bias)
#if defined(TO_RGB32)
#if defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || defined(PLT1_LE)
ofs = CAST_PLT_DISTANCE(ofs);
len = CAST_PLT_DISTANCE(len);
#endif
#endif
ref -= ofs;
ASSERT(encoder->usr, op + len <= op_limit);
ASSERT(encoder->usr, ref + len <= op_limit);
ASSERT(encoder->usr, ref >= out_buf);
spice_assert(op + len <= op_limit);
spice_assert(ref + len <= op_limit);
spice_assert(ref >= out_buf);
// TODO: optimize by not calling loop at least 3 times when not PLT_TO_RGB32 (len is
// always >=3). in PLT_TO_RGB32 len >= 3*number_of_pixels_per_byte
@ -267,41 +281,31 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
// because the number of pixel copied is larger
// then one...
/* optimize copy for a run */
OUT_PIXEL b = *ref;
const OUT_PIXEL b = *ref;
for (; len; --len) {
COPY_PIXEL(b, op);
ASSERT(encoder->usr, op <= op_limit);
spice_extra_assert(op <= op_limit);
}
} else {
for (; len; --len) {
COPY_REF_PIXEL(ref, op);
ASSERT(encoder->usr, op <= op_limit);
spice_extra_assert(op <= op_limit);
}
}
} else { // copy
ctrl++; // copy count is biased by 1
#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
defined(PLT1_LE))
ASSERT(encoder->usr, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
#else
ASSERT(encoder->usr, op + ctrl <= op_limit);
#endif
COPY_COMP_PIXEL(encoder, op);
spice_assert(op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
ASSERT(encoder->usr, op <= op_limit);
for (--ctrl; ctrl; ctrl--) {
do {
COPY_COMP_PIXEL(encoder, op);
ASSERT(encoder->usr, op <= op_limit);
}
spice_extra_assert(op <= op_limit);
} while(--ctrl);
}
if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
ctrl = decode(encoder);
} else {
loop = FALSE;
if (LZ_UNEXPECT_CONDITIONAL(op >= op_limit)) {
break;
}
} while (LZ_EXPECT_CONDITIONAL(loop));
}
return (op - out_buf);
}
@ -315,6 +319,7 @@ static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
#undef LZ_RGB16
#undef LZ_RGB24
#undef LZ_RGB32
#undef LZ_A8
#undef LZ_RGB_ALPHA
#undef TO_RGB32
#undef OUT_PIXEL

56
common/macros.h Normal file
View File

@ -0,0 +1,56 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef H_SPICE_COMMON_MACROS
#define H_SPICE_COMMON_MACROS
#include "verify.h"
#ifdef __GNUC__
#define SPICE_CONSTRUCTOR_FUNC(func_name) \
static void __attribute__((constructor)) func_name(void)
#define SPICE_DESTRUCTOR_FUNC(func_name) \
static void __attribute__((destructor)) func_name(void)
#elif defined(_MSC_VER)
#define SPICE_CONSTRUCTOR_FUNC(func_name) \
static void func_name(void); \
static int func_name ## _wrapper(void) { func_name(); return 0; } \
__pragma(section(".CRT$XCU",read)) \
__declspec(allocate(".CRT$XCU")) static int (* _array ## func_name)(void) = func_name ## _wrapper; \
static void func_name(void)
#define SPICE_DESTRUCTOR_FUNC(func_name) \
static void func_name(void); \
static int func_name ## _wrapper(void) { func_name(); return 0; } \
__pragma(section(".CRT$XPU",read)) \
__declspec(allocate(".CRT$XPU")) static int (* _array ## func_name)(void) = func_name ## _wrapper; \
static void func_name(void)
#else
#error Please implement SPICE_CONSTRUCTOR_FUNC and SPICE_DESTRUCTOR_FUNC for this compiler
#endif
#define SPICE_VERIFY(cond) verify_expr(cond, (void)1)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
#define SPICE_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define SPICE_UNREACHABLE __assume(0)
#else
#define SPICE_UNREACHABLE for(;;) continue
#endif
#endif // H_SPICE_COMMON_MACROS

View File

@ -15,34 +15,60 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "log.h"
#include "marshaller.h"
#include "mem.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <spice/start-packed.h>
typedef struct SPICE_ATTR_PACKED {
int16_t val;
} int16_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
uint16_t val;
} uint16_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
int32_t val;
} int32_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
uint32_t val;
} uint32_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
int64_t val;
} int64_unaligned_t;
typedef struct SPICE_ATTR_PACKED {
uint64_t val;
} uint64_unaligned_t;
#include <spice/end-packed.h>
#define write_int8(ptr,v) (*(int8_t *)(ptr) = v)
#define write_uint8(ptr,v) (*(uint8_t *)(ptr) = v)
#ifdef WORDS_BIGENDIAN
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = SPICE_BYTESWAP64((uint64_t)(v)))
#define write_int16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
#define write_int32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
#define write_int64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
#else
#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
#define write_int16(ptr,v) (*((int16_t *)(ptr)) = v)
#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = v)
#define write_int32(ptr,v) (*((int32_t *)(ptr)) = v)
#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = v)
#define write_int64(ptr,v) (*((int64_t *)(ptr)) = v)
#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = v)
#define write_int16(ptr,v) (((int16_unaligned_t *)(ptr))->val = v)
#define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = v)
#define write_int32(ptr,v) (((int32_unaligned_t *)(ptr))->val = v)
#define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = v)
#define write_int64(ptr,v) (((int64_unaligned_t *)(ptr))->val = v)
#define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = v)
#endif
typedef struct {
@ -68,7 +94,6 @@ typedef struct SpiceMarshallerData SpiceMarshallerData;
typedef struct {
SpiceMarshaller *marshaller;
int item_nr;
int is_64bit;
size_t offset;
} MarshallerRef;
@ -80,25 +105,26 @@ struct SpiceMarshaller {
MarshallerRef pointer_ref;
int n_items;
int items_size; /* number of items availible in items */
int items_size; /* number of items available in items */
MarshallerItem *items;
MarshallerItem static_items[N_STATIC_ITEMS];
int num_fd;
int fd[4];
};
struct SpiceMarshallerData {
size_t total_size;
size_t base;
SpiceMarshaller *marshallers;
SpiceMarshaller *last_marshaller;
size_t current_buffer_position;
MarshallerBuffer *current_buffer;
MarshallerItem *current_buffer_item;
MarshallerBuffer *buffers;
SpiceMarshaller static_marshaller;
MarshallerBuffer static_buffer;
// first marshaller and buffer are statically allocated here
SpiceMarshaller marshallers[1];
MarshallerBuffer buffers[1];
};
static void spice_marshaller_init(SpiceMarshaller *m,
@ -111,6 +137,8 @@ static void spice_marshaller_init(SpiceMarshaller *m,
m->n_items = 0;
m->items_size = N_STATIC_ITEMS;
m->items = m->static_items;
m->fd[0] = m->fd[1] = m->fd[2] = m->fd[3] = -1;
m->num_fd = 0;
}
SpiceMarshaller *spice_marshaller_new(void)
@ -120,16 +148,15 @@ SpiceMarshaller *spice_marshaller_new(void)
d = spice_new(SpiceMarshallerData, 1);
d->last_marshaller = d->marshallers = &d->static_marshaller;
d->last_marshaller = d->marshallers;
d->total_size = 0;
d->base = 0;
d->buffers = &d->static_buffer;
d->buffers->next = NULL;
d->current_buffer = d->buffers;
d->current_buffer_position = 0;
d->current_buffer_item = NULL;
m = &d->static_marshaller;
m = d->marshallers;
spice_marshaller_init(m, d);
return m;
@ -160,6 +187,7 @@ void spice_marshaller_reset(SpiceMarshaller *m)
{
SpiceMarshaller *m2, *next;
SpiceMarshallerData *d;
int i;
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
@ -179,6 +207,14 @@ void spice_marshaller_reset(SpiceMarshaller *m)
m->n_items = 0;
m->total_size = 0;
for (i = 0; i < m->num_fd; i++) {
if (m->fd[i] >= 0) {
close(m->fd[i]);
m->fd[i] = -1;
}
}
m->num_fd = 0;
d = m->data;
d->last_marshaller = d->marshallers;
d->total_size = 0;
@ -238,6 +274,11 @@ static size_t remaining_buffer_size(SpiceMarshallerData *d)
return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
}
static void reserve_space_free_data(uint8_t *data, SPICE_GNUC_UNUSED void *opaque)
{
free(data);
}
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
{
MarshallerItem *item;
@ -276,7 +317,7 @@ uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
/* Large item, allocate by itself */
item->data = (uint8_t *)spice_malloc(size);
item->len = size;
item->free_data = (spice_marshaller_item_free_func)free;
item->free_data = reserve_space_free_data;
item->opaque = NULL;
} else {
/* Use next buffer */
@ -310,8 +351,8 @@ void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
item->len -= size;
}
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
spice_marshaller_item_free_func free_data, void *opaque)
uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
spice_marshaller_item_free_func free_data, void *opaque)
{
MarshallerItem *item;
SpiceMarshallerData *d;
@ -333,7 +374,7 @@ uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t
return data;
}
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size)
{
uint8_t *ptr;
@ -342,18 +383,21 @@ uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
return ptr;
}
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size)
uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size)
{
return spice_marshaller_add_ref_full(m, data, size, NULL, NULL);
/* the cast to no-const here is safe as data is used for writing only if
* free_data pointer is not NULL
*/
return spice_marshaller_add_by_ref_full(m, (uint8_t *) data, size, NULL, NULL);
}
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks)
void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks)
{
unsigned int i;
for (i = 0; i < chunks->num_chunks; i++) {
spice_marshaller_add_ref(m, chunks->chunk[i].data,
chunks->chunk[i].len);
spice_marshaller_add_by_ref(m, chunks->chunk[i].data,
chunks->chunk[i].len);
}
}
@ -373,13 +417,13 @@ SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
return m2;
}
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit)
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m)
{
SpiceMarshaller *m2;
uint8_t *p;
int size;
size = is_64bit ? 8 : 4;
size = 4;
p = spice_marshaller_reserve_space(m, size);
memset(p, 0, size);
@ -387,12 +431,11 @@ SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int
m2->pointer_ref.marshaller = m;
m2->pointer_ref.item_nr = m->n_items - 1;
m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
m2->pointer_ref.is_64bit = is_64bit;
return m2;
}
uint8_t *lookup_ref(MarshallerRef *ref)
static uint8_t *lookup_ref(MarshallerRef *ref)
{
MarshallerItem *item;
@ -419,7 +462,7 @@ uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip_bytes,
/* Only supported for root marshaller */
assert(m->data->marshallers == m);
if (m->n_items == 1) {
if (m->n_items == 1 && m->next == NULL) {
*free_res = FALSE;
if (m->items[0].len <= skip_bytes) {
*len = 0;
@ -492,18 +535,19 @@ void spice_marshaller_flush(SpiceMarshaller *m)
for (m2 = m; m2 != NULL; m2 = m2->next) {
if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
ptr_pos = lookup_ref(&m2->pointer_ref);
if (m2->pointer_ref.is_64bit) {
write_uint64(ptr_pos,
spice_marshaller_get_offset(m2));
} else {
write_uint32(ptr_pos,
spice_marshaller_get_offset(m2));
}
write_uint32(ptr_pos, spice_marshaller_get_offset(m2));
}
}
}
#ifndef WIN32
#ifdef WIN32
// this definition is ABI compatible with WSABUF
struct iovec {
unsigned long iov_len;
void *iov_base;
};
#endif
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
int n_vec, size_t skip_bytes)
{
@ -525,7 +569,7 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
if (v == n_vec) {
return v; /* Not enough space in vec */
}
vec[v].iov_base = (void *)item->data + skip_bytes;
vec[v].iov_base = (uint8_t *)item->data + skip_bytes;
vec[v].iov_len = item->len - skip_bytes;
skip_bytes = 0;
v++;
@ -535,7 +579,6 @@ int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
return v;
}
#endif
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
{
@ -564,7 +607,7 @@ void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
return (void *)ptr;
}
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v)
void spice_marshaller_set_uint32(SPICE_GNUC_UNUSED SpiceMarshaller *m, void *ref, uint32_t v)
{
write_uint32((uint8_t *)ref, v);
}
@ -613,3 +656,26 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
write_int8(ptr, v);
return (void *)ptr;
}
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd)
{
spice_assert(m->num_fd < 4);
if (fd != -1) {
m->fd[m->num_fd] = dup(fd);
if (m->fd[m->num_fd] == -1) {
perror("dup");
}
m->num_fd++;
}
}
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4])
{
int num_fd = m->num_fd;
memcpy(fd, m->fd, sizeof(m->fd));
m->num_fd = 0;
return num_fd;
}

View File

@ -16,18 +16,20 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MARSHALLER
#define _H_MARSHALLER
#ifndef H_SPICE_COMMON_MARSHALLER
#define H_SPICE_COMMON_MARSHALLER
#include <stdbool.h>
#include <spice/macros.h>
#include <spice/types.h>
#include "mem.h"
#ifndef WIN32
#include <sys/uio.h>
#else
struct iovec;
#endif
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
typedef struct SpiceMarshaller SpiceMarshaller;
typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
@ -37,11 +39,11 @@ void spice_marshaller_reset(SpiceMarshaller *m);
void spice_marshaller_destroy(SpiceMarshaller *m);
uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size);
void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size);
uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size);
uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size);
uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
spice_marshaller_item_free_func free_data, void *opaque);
void spice_marshaller_add_ref_chunks(SpiceMarshaller *m, SpiceChunks *chunks);
uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size);
uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size);
uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
spice_marshaller_item_free_func free_data, void *opaque);
void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks);
void spice_marshaller_flush(SpiceMarshaller *m);
void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip,
@ -51,11 +53,9 @@ size_t spice_marshaller_get_offset(SpiceMarshaller *m);
size_t spice_marshaller_get_size(SpiceMarshaller *m);
size_t spice_marshaller_get_total_size(SpiceMarshaller *m);
SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit);
#ifndef WIN32
SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m);
int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
int n_vec, size_t skip_bytes);
#endif
void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
@ -67,8 +67,9 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
void spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
#ifdef __cplusplus
}
#endif
void spice_marshaller_add_fd(SpiceMarshaller *m, int fd);
int spice_marshaller_get_fds(SpiceMarshaller *m, int fd[4]);
SPICE_END_DECLS
#endif

View File

@ -15,20 +15,17 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mem.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef MALLOC_ERROR
#define MALLOC_ERROR(format, ...) { \
printf(format "\n", ## __VA_ARGS__); \
abort(); \
}
#define MALLOC_ERROR(...) SPICE_STMT_START { \
spice_error(__VA_ARGS__); \
abort(); \
} SPICE_STMT_END
#endif
size_t spice_strnlen(const char *str, size_t max_len)
@ -46,13 +43,15 @@ size_t spice_strnlen(const char *str, size_t max_len)
char *spice_strdup(const char *str)
{
char *copy;
size_t len;
if (str == NULL) {
return NULL;
}
copy = (char *)spice_malloc(strlen(str) + 1);
strcpy(copy, str);
len = strlen(str) + 1;
copy = (char *)spice_malloc(len);
memcpy(copy, str, len);
return copy;
}
@ -94,8 +93,7 @@ void *spice_malloc(size_t n_bytes)
return mem;
}
MALLOC_ERROR("spice_malloc: panic: unable to allocate %lu bytes\n",
(unsigned long)n_bytes);
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
}
return NULL;
}
@ -111,8 +109,7 @@ void *spice_malloc0(size_t n_bytes)
return mem;
}
MALLOC_ERROR("spice_malloc0: panic: unable to allocate %lu bytes\n",
(unsigned long)n_bytes);
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
}
return NULL;
}
@ -126,8 +123,7 @@ void *spice_realloc(void *mem, size_t n_bytes)
return mem;
}
MALLOC_ERROR("spice_realloc: panic: unable to allocate %lu bytes\n",
(unsigned long)n_bytes);
MALLOC_ERROR("unable to allocate %lu bytes", (unsigned long)n_bytes);
}
free(mem);
@ -140,7 +136,7 @@ void *spice_realloc(void *mem, size_t n_bytes)
void *spice_malloc_n(size_t n_blocks, size_t n_block_bytes)
{
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
MALLOC_ERROR("spice_malloc_n: overflow allocating %lu*%lu bytes",
MALLOC_ERROR("overflow allocating %lu*%lu bytes",
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
}
@ -179,7 +175,7 @@ void *spice_realloc_n(void *mem, size_t n_blocks, size_t n_block_bytes)
if (SIZE_OVERFLOWS (n_blocks, n_block_bytes)) {
MALLOC_ERROR("spice_realloc_n: overflow allocating %lu*%lu bytes",
(unsigned long)n_blocks, (unsigned long)n_block_bytes);
}
}
return spice_realloc(mem, n_blocks * n_block_bytes);
}
@ -295,3 +291,25 @@ size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len)
buffer->offset -= len;
return len;
}
#ifdef SPICE_DEBUG_ALIGNMENT
void spice_alignment_warning(const char *loc, void *p, unsigned sz)
{
static const char *last_loc = NULL;
if (loc != last_loc) {
last_loc = loc;
spice_log(G_LOG_LEVEL_WARNING, loc, __FUNCTION__,
"Misaligned access at %p, alignment %u", p, sz);
}
}
void spice_alignment_debug(const char *loc, void *p, unsigned sz)
{
static const char *last_loc = NULL;
if (loc != last_loc) {
last_loc = loc;
spice_log(G_LOG_LEVEL_DEBUG, loc, __FUNCTION__,
"Expected misaligned access at %p, alignment %u", p, sz);
}
}
#endif // SPICE_DEBUG_ALIGNMENT

View File

@ -16,19 +16,14 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MEM
#define _H_MEM
#ifndef H_SPICE_COMMON_MEM
#define H_SPICE_COMMON_MEM
#include "log.h"
#include <stdlib.h>
#include <spice/macros.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
#ifdef STDC_HEADERS
# include <stdlib.h>
@ -118,7 +113,7 @@ size_t spice_strnlen(const char *str, size_t max_len);
__p; \
}))
# define _SPICE_RENEW(struct_type, mem, n_structs, func) \
(struct_type *) (__extension__ ({ \
(struct_type *) (__extension__ ({ \
size_t __n = (size_t) (n_structs); \
size_t __s = sizeof (struct_type); \
void *__p = (void *) (mem); \
@ -134,7 +129,6 @@ size_t spice_strnlen(const char *str, size_t max_len);
#else
/* Unoptimized version: always call the _n() function. */
#define _SPICE_NEW(struct_type, n_structs, func) \
((struct_type *) spice_##func##_n ((n_structs), sizeof (struct_type)))
#define _SPICE_RENEW(struct_type, mem, n_structs, func) \
@ -142,6 +136,46 @@ size_t spice_strnlen(const char *str, size_t max_len);
#endif
/* Cast to a type with stricter alignment constraints (to build with clang) */
/* Misaligned cast to a type with stricter alignment */
#ifndef SPICE_DEBUG_ALIGNMENT
#define SPICE_UNALIGNED_CAST(type, value) ((type)(void *)(value))
#define SPICE_ALIGNED_CAST(type, value) ((type)(void *)(value))
#else // SPICE_DEBUG_ALIGNMENT
#define SPICE_ALIGNED_CAST(type, value) \
((type)spice_alignment_check(G_STRLOC, \
(void *)(value), \
__alignof(*((type)0))))
#define SPICE_UNALIGNED_CAST(type, value) \
((type)spice_alignment_weak_check(G_STRLOC, \
(void *)(value), \
__alignof(*((type)0))))
extern void spice_alignment_warning(const char *loc, void *p, unsigned sz);
extern void spice_alignment_debug(const char *loc, void *p, unsigned sz);
static inline void *spice_alignment_check(const char *loc,
void *ptr, unsigned sz)
{
if (G_UNLIKELY(((uintptr_t) ptr & (sz-1U)) != 0))
spice_alignment_warning(loc, ptr, sz);
return ptr;
}
static inline void *spice_alignment_weak_check(const char *loc,
void *ptr, unsigned sz)
{
if (G_UNLIKELY(((uintptr_t) ptr & (sz-1U)) != 0))
spice_alignment_debug(loc, ptr, sz);
return ptr;
}
#endif // SPICE_DEBUG_ALIGNMENT
#define spice_new(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc)
#define spice_new0(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc0)
#define spice_renew(struct_type, mem, n_structs) _SPICE_RENEW(struct_type, mem, n_structs, realloc)
@ -156,7 +190,6 @@ void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len);
size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len);
size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

194
common/meson.build Normal file
View File

@ -0,0 +1,194 @@
#
# libspice-common
#
spice_common_sources = [
'agent.c',
'agent.h',
'backtrace.c',
'backtrace.h',
'canvas_utils.c',
'canvas_utils.h',
'demarshallers.h',
'draw.h',
'lines.c',
'lines.h',
'log.c',
'log.h',
'lz.c',
'lz.h',
'lz_common.h',
'lz_config.h',
'macros.h',
'marshaller.c',
'marshaller.h',
'mem.c',
'mem.h',
'messages.h',
'pixman_utils.c',
'pixman_utils.h',
'quic.c',
'quic.h',
'quic_config.h',
'rect.h',
'region.c',
'region.h',
'ring.h',
'rop3.c',
'rop3.h',
'snd_codec.c',
'snd_codec.h',
'utils.c',
'utils.h',
'udev.c',
'udev.h',
'verify.h',
'recorder.h'
]
if get_option('instrumentation') == 'recorder'
spice_common_sources += [
'recorder/recorder.c',
'recorder/recorder.h',
'recorder/recorder_ring.c',
'recorder/recorder_ring.h'
]
endif
if get_option('instrumentation') == 'agent'
spice_common_sources += [
'agent_interface.c',
'agent_interface.h'
]
endif
spice_common_lib = static_library('spice-common', spice_common_sources,
install : false,
include_directories : spice_common_include,
dependencies : spice_common_deps)
spice_common_dep = declare_dependency(link_with : spice_common_lib,
include_directories : spice_common_include,
dependencies : spice_common_deps)
# client_demarshallers
if spice_common_generate_client_code or spice_common_generate_server_code
codegen_cmd = [python, spice_codegen]
codegen_args = ['--generate-demarshallers',
'--client',
'--include', 'common/messages.h',
'--generated-declaration-file', '@OUTPUT1@',
'@INPUT@', '@OUTPUT0@']
client_demarshallers = custom_target('client_demarshallers',
input : [spice_proto],
output : ['generated_client_demarshallers.c', 'generated_messages.h'],
install : false,
command : [codegen_cmd, codegen_args],
depend_files : [spice_codegen_files, 'messages.h'])
endif
#
# libspice-common-client
#
if spice_common_generate_client_code
# client_marshallers
codegen_args = ['--generate-marshallers',
'--generate-header',
'-P',
'--client',
'--include', 'common/client_marshallers.h',
'@INPUT0@', '@OUTPUT0@']
client_marshallers = custom_target('client_marshallers',
input : [spice_proto, client_demarshallers],
output : ['generated_client_marshallers.c', 'generated_client_marshallers.h'],
install : false,
command : [codegen_cmd, codegen_args],
depend_files : [spice_codegen_files, 'client_marshallers.h'])
spice_common_client_sources = [
client_demarshallers,
client_marshallers,
'client_marshallers.h',
'ssl_verify.c',
'ssl_verify.h',
]
spice_common_client_lib = static_library('spice-common-client', spice_common_client_sources,
install : false,
dependencies : [spice_common_dep, gio2_deps])
spice_common_client_dep = declare_dependency(sources : client_marshallers[1],
link_with : spice_common_client_lib,
dependencies : [spice_common_dep, gio2_deps])
endif
#
# libspice-common-server
#
if spice_common_generate_server_code
structs_args = [
'-M', 'String',
'-M', 'Rect',
'-M', 'Point',
'-M', 'DisplayBase',
'-M', 'Fill',
'-M', 'Opaque',
'-M', 'Copy',
'-M', 'Blend',
'-M', 'Blackness',
'-M', 'Whiteness',
'-M', 'Invers',
'-M', 'Rop3',
'-M', 'Stroke',
'-M', 'Text',
'-M', 'Transparent',
'-M', 'AlphaBlend',
'-M', 'Composite',
]
targets = [
{ 'name' : 'server_demarshallers',
'input' : [ spice_proto, client_demarshallers ],
'output' : ['generated_server_demarshallers.c'],
'codegen_args' : ['--generate-demarshallers',
'--server',
'--include', 'common/messages.h',
'@INPUT0@', '@OUTPUT0@'],
},
{ 'name' : 'server_marshallers',
'input' : [ spice_proto, client_demarshallers ],
'output' : ['generated_server_marshallers.c', 'generated_server_marshallers.h'],
'codegen_args' : ['--generate-marshallers',
'--generate-header',
'--server',
structs_args,
'--include', 'common/messages.h',
'@INPUT0@', '@OUTPUT0@']
},
]
spice_common_server_sources = []
spice_common_server_dep_sources = []
foreach t : targets
target = custom_target(t['name'],
input : t['input'],
output : t['output'],
install : false,
command : [codegen_cmd, t['codegen_args']],
depend_files : [spice_codegen_files, 'messages.h'])
spice_common_server_sources += target
if t['output'].length() > 1
spice_common_server_dep_sources += target[1]
endif
endforeach
spice_common_server_lib = static_library('spice-common-server', spice_common_server_sources,
install : false,
dependencies : spice_common_dep)
spice_common_server_dep = declare_dependency(sources : spice_common_server_dep_sources,
link_with : spice_common_server_lib,
dependencies : spice_common_dep)
endif

View File

@ -28,498 +28,46 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _H_MESSAGES
#define _H_MESSAGES
#ifndef H_SPICE_COMMON_MESSAGES
#define H_SPICE_COMMON_MESSAGES
#include <spice/protocol.h>
#include "draw.h"
#include <spice/macros.h>
#ifdef __cplusplus
extern "C" {
#ifdef USE_SMARTCARD
#include <libcacard.h>
#endif
typedef struct SpiceMsgData {
uint32_t data_size;
uint8_t data[0];
} SpiceMsgData;
#include "draw.h"
typedef struct SpiceMsgEmpty {
} SpiceMsgEmpty;
SPICE_BEGIN_DECLS
typedef struct SpiceMsgInputsInit {
uint32_t keyboard_modifiers;
} SpiceMsgInputsInit;
typedef struct SpiceMsgInputsKeyModifiers {
uint32_t modifiers;
} SpiceMsgInputsKeyModifiers;
typedef struct SpiceMsgMainMultiMediaTime {
uint32_t time;
} SpiceMsgMainMultiMediaTime;
typedef struct SpiceMsgMainMigrationBegin {
uint16_t port;
uint16_t sport;
uint32_t host_size;
uint8_t *host_data;
uint16_t pub_key_type;
uint32_t pub_key_size;
uint8_t *pub_key_data;
uint32_t cert_subject_size;
uint8_t *cert_subject_data;
} SpiceMsgMainMigrationBegin;
typedef struct SpiceMsgMainMigrationSwitchHost {
uint16_t port;
uint16_t sport;
uint32_t host_size;
uint8_t *host_data;
uint32_t cert_subject_size;
uint8_t *cert_subject_data;
} SpiceMsgMainMigrationSwitchHost;
typedef struct SpiceMsgMigrate {
uint32_t flags;
} SpiceMsgMigrate;
typedef struct SpiceResourceID {
typedef struct SpiceMsgCompressedData {
uint8_t type;
uint64_t id;
} SpiceResourceID;
typedef struct SpiceResourceList {
uint16_t count;
SpiceResourceID resources[0];
} SpiceResourceList;
typedef struct SpiceMsgSetAck {
uint32_t generation;
uint32_t window;
} SpiceMsgSetAck;
typedef struct SpiceMsgcAckSync {
uint32_t generation;
} SpiceMsgcAckSync;
typedef struct SpiceWaitForChannel {
uint8_t channel_type;
uint8_t channel_id;
uint64_t message_serial;
} SpiceWaitForChannel;
typedef struct SpiceMsgWaitForChannels {
uint8_t wait_count;
SpiceWaitForChannel wait_list[0];
} SpiceMsgWaitForChannels;
typedef struct SpiceChannelId {
uint8_t type;
uint8_t id;
} SpiceChannelId;
typedef struct SpiceMsgMainInit {
uint32_t session_id;
uint32_t display_channels_hint;
uint32_t supported_mouse_modes;
uint32_t current_mouse_mode;
uint32_t agent_connected;
uint32_t agent_tokens;
uint32_t multi_media_time;
uint32_t ram_hint;
} SpiceMsgMainInit;
typedef struct SpiceMsgDisconnect {
uint64_t time_stamp;
uint32_t reason; // SPICE_ERR_?
} SpiceMsgDisconnect;
typedef struct SpiceMsgNotify {
uint64_t time_stamp;
uint32_t severity;
uint32_t visibilty;
uint32_t what;
uint32_t message_len;
uint8_t message[0];
} SpiceMsgNotify;
typedef struct SpiceMsgChannels {
uint32_t num_of_channels;
SpiceChannelId channels[0];
} SpiceMsgChannels;
typedef struct SpiceMsgMainName {
uint32_t name_len;
uint8_t name[0];
} SpiceMsgMainName;
typedef struct SpiceMsgMainUuid {
uint8_t uuid[16];
} SpiceMsgMainUuid;
typedef struct SpiceMsgMainMouseMode {
uint32_t supported_modes;
uint32_t current_mode;
} SpiceMsgMainMouseMode;
typedef struct SpiceMsgPing {
uint32_t id;
uint64_t timestamp;
void *data;
uint32_t data_len;
} SpiceMsgPing;
typedef struct SpiceMsgMainAgentDisconnect {
uint32_t error_code; // SPICE_ERR_?
} SpiceMsgMainAgentDisconnect;
uint32_t uncompressed_size;
uint32_t compressed_size;
uint8_t *compressed_data;
} SpiceMsgCompressedData;
#define SPICE_AGENT_MAX_DATA_SIZE 2048
typedef struct SpiceMsgMainAgentTokens {
uint32_t num_tokens;
} SpiceMsgMainAgentTokens, SpiceMsgcMainAgentTokens, SpiceMsgcMainAgentStart;
typedef struct SpiceMsgcClientInfo {
uint64_t cache_size;
} SpiceMsgcClientInfo;
typedef struct SpiceMsgcMainMouseModeRequest {
uint32_t mode;
} SpiceMsgcMainMouseModeRequest;
typedef struct SpiceCursor {
uint32_t flags;
SpiceCursorHeader header;
uint32_t data_size;
uint8_t *data;
} SpiceCursor;
typedef struct SpiceMsgDisplayMode {
uint32_t x_res;
uint32_t y_res;
uint32_t bits;
} SpiceMsgDisplayMode;
typedef struct SpiceMsgSurfaceCreate {
uint32_t surface_id;
uint32_t width;
uint32_t height;
uint32_t format;
uint32_t flags;
} SpiceMsgSurfaceCreate;
typedef struct SpiceMsgSurfaceDestroy {
uint32_t surface_id;
} SpiceMsgSurfaceDestroy;
typedef struct SpiceMsgDisplayBase {
uint32_t surface_id;
SpiceRect box;
SpiceClip clip;
} SpiceMsgDisplayBase;
typedef struct SpiceMsgDisplayDrawFill {
SpiceMsgDisplayBase base;
SpiceFill data;
} SpiceMsgDisplayDrawFill;
typedef struct SpiceMsgDisplayDrawOpaque {
SpiceMsgDisplayBase base;
SpiceOpaque data;
} SpiceMsgDisplayDrawOpaque;
typedef struct SpiceMsgDisplayDrawCopy {
SpiceMsgDisplayBase base;
SpiceCopy data;
} SpiceMsgDisplayDrawCopy;
typedef struct SpiceMsgDisplayDrawTransparent {
SpiceMsgDisplayBase base;
SpiceTransparent data;
} SpiceMsgDisplayDrawTransparent;
typedef struct SpiceMsgDisplayDrawAlphaBlend {
SpiceMsgDisplayBase base;
SpiceAlphaBlend data;
} SpiceMsgDisplayDrawAlphaBlend;
typedef struct SpiceMsgDisplayCopyBits {
SpiceMsgDisplayBase base;
SpicePoint src_pos;
} SpiceMsgDisplayCopyBits;
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
typedef struct SpiceMsgDisplayDrawRop3 {
SpiceMsgDisplayBase base;
SpiceRop3 data;
} SpiceMsgDisplayDrawRop3;
typedef struct SpiceMsgDisplayDrawBlackness {
SpiceMsgDisplayBase base;
SpiceBlackness data;
} SpiceMsgDisplayDrawBlackness;
typedef struct SpiceMsgDisplayDrawWhiteness {
SpiceMsgDisplayBase base;
SpiceWhiteness data;
} SpiceMsgDisplayDrawWhiteness;
typedef struct SpiceMsgDisplayDrawInvers {
SpiceMsgDisplayBase base;
SpiceInvers data;
} SpiceMsgDisplayDrawInvers;
typedef struct SpiceMsgDisplayDrawStroke {
SpiceMsgDisplayBase base;
SpiceStroke data;
} SpiceMsgDisplayDrawStroke;
typedef struct SpiceMsgDisplayDrawText {
SpiceMsgDisplayBase base;
SpiceText data;
} SpiceMsgDisplayDrawText;
typedef struct SpiceMsgDisplayInvalOne {
uint64_t id;
} SpiceMsgDisplayInvalOne;
typedef struct SpiceMsgDisplayStreamCreate {
uint32_t surface_id;
uint32_t id;
uint32_t flags;
uint32_t codec_type;
uint64_t stamp;
uint32_t stream_width;
uint32_t stream_height;
uint32_t src_width;
uint32_t src_height;
SpiceRect dest;
SpiceClip clip;
} SpiceMsgDisplayStreamCreate;
typedef struct SpiceMsgDisplayStreamData {
uint32_t id;
uint32_t multi_media_time;
uint32_t data_size;
#ifdef USE_SMARTCARD
typedef struct SpiceMsgSmartcard {
VSCMsgType type;
uint32_t length;
uint32_t reader_id;
uint8_t data[0];
} SpiceMsgDisplayStreamData;
typedef struct SpiceMsgDisplayStreamClip {
uint32_t id;
SpiceClip clip;
} SpiceMsgDisplayStreamClip;
typedef struct SpiceMsgDisplayStreamDestroy {
uint32_t id;
} SpiceMsgDisplayStreamDestroy;
typedef struct SpiceMsgCursorInit {
SpicePoint16 position;
uint16_t trail_length;
uint16_t trail_frequency;
uint8_t visible;
SpiceCursor cursor;
} SpiceMsgCursorInit;
typedef struct SpiceMsgCursorSet {
SpicePoint16 position;
uint8_t visible;
SpiceCursor cursor;
} SpiceMsgCursorSet;
typedef struct SpiceMsgCursorMove {
SpicePoint16 position;
} SpiceMsgCursorMove;
typedef struct SpiceMsgCursorTrail {
uint16_t length;
uint16_t frequency;
} SpiceMsgCursorTrail;
typedef struct SpiceMsgcDisplayInit {
uint8_t pixmap_cache_id;
int64_t pixmap_cache_size; //in pixels
uint8_t glz_dictionary_id;
int32_t glz_dictionary_window_size; // in pixels
} SpiceMsgcDisplayInit;
typedef struct SpiceMsgcKeyDown {
uint32_t code;
} SpiceMsgcKeyDown;
typedef struct SpiceMsgcKeyUp {
uint32_t code;
} SpiceMsgcKeyUp;
typedef struct SpiceMsgcKeyModifiers {
uint32_t modifiers;
} SpiceMsgcKeyModifiers;
typedef struct SpiceMsgcMouseMotion {
int32_t dx;
int32_t dy;
uint32_t buttons_state;
} SpiceMsgcMouseMotion;
typedef struct SpiceMsgcMousePosition {
uint32_t x;
uint32_t y;
uint32_t buttons_state;
uint8_t display_id;
} SpiceMsgcMousePosition;
typedef struct SpiceMsgcMousePress {
int32_t button;
int32_t buttons_state;
} SpiceMsgcMousePress;
typedef struct SpiceMsgcMouseRelease {
int32_t button;
int32_t buttons_state;
} SpiceMsgcMouseRelease;
typedef struct SpiceMsgAudioVolume {
uint8_t nchannels;
uint16_t volume[0];
} SpiceMsgAudioVolume;
typedef struct SpiceMsgAudioMute {
uint8_t mute;
} SpiceMsgAudioMute;
typedef struct SpiceMsgPlaybackMode {
uint32_t time;
uint32_t mode; //SPICE_AUDIO_DATA_MODE_?
uint8_t *data;
uint32_t data_size;
} SpiceMsgPlaybackMode, SpiceMsgcRecordMode;
typedef struct SpiceMsgPlaybackStart {
uint32_t channels;
uint32_t format; //SPICE_AUDIO_FMT_?
uint32_t frequency;
uint32_t time;
} SpiceMsgPlaybackStart;
typedef struct SpiceMsgPlaybackPacket {
uint32_t time;
uint8_t *data;
uint32_t data_size;
} SpiceMsgPlaybackPacket, SpiceMsgcRecordPacket;
typedef struct SpiceMsgRecordStart {
uint32_t channels;
uint32_t format; //SPICE_AUDIO_FMT_?
uint32_t frequency;
} SpiceMsgRecordStart;
typedef struct SpiceMsgcRecordStartMark {
uint32_t time;
} SpiceMsgcRecordStartMark;
typedef struct SpiceMsgTunnelInit {
uint16_t max_num_of_sockets;
uint32_t max_socket_data_size;
} SpiceMsgTunnelInit;
typedef uint8_t SpiceTunnelIPv4[4];
typedef struct SpiceMsgTunnelIpInfo {
uint16_t type;
union {
SpiceTunnelIPv4 ipv4;
} u;
uint8_t data[0];
} SpiceMsgTunnelIpInfo;
typedef struct SpiceMsgTunnelServiceIpMap {
uint32_t service_id;
SpiceMsgTunnelIpInfo virtual_ip;
} SpiceMsgTunnelServiceIpMap;
typedef struct SpiceMsgTunnelSocketOpen {
uint16_t connection_id;
uint32_t service_id;
uint32_t tokens;
} SpiceMsgTunnelSocketOpen;
/* connection id must be the first field in msgs directed to a specific connection */
typedef struct SpiceMsgTunnelSocketFin {
uint16_t connection_id;
} SpiceMsgTunnelSocketFin;
typedef struct SpiceMsgTunnelSocketClose {
uint16_t connection_id;
} SpiceMsgTunnelSocketClose;
typedef struct SpiceMsgTunnelSocketData {
uint16_t connection_id;
uint8_t data[0];
} SpiceMsgTunnelSocketData;
typedef struct SpiceMsgTunnelSocketTokens {
uint16_t connection_id;
uint32_t num_tokens;
} SpiceMsgTunnelSocketTokens;
typedef struct SpiceMsgTunnelSocketClosedAck {
uint16_t connection_id;
} SpiceMsgTunnelSocketClosedAck;
typedef struct SpiceMsgcTunnelAddGenericService {
uint32_t type;
uint32_t id;
uint32_t group;
uint32_t port;
uint64_t name;
uint64_t description;
union {
SpiceMsgTunnelIpInfo ip;
} u;
} SpiceMsgcTunnelAddGenericService;
typedef struct SpiceMsgcTunnelRemoveService {
uint32_t id;
} SpiceMsgcTunnelRemoveService;
/* connection id must be the first field in msgs directed to a specific connection */
typedef struct SpiceMsgcTunnelSocketOpenAck {
uint16_t connection_id;
uint32_t tokens;
} SpiceMsgcTunnelSocketOpenAck;
typedef struct SpiceMsgcTunnelSocketOpenNack {
uint16_t connection_id;
} SpiceMsgcTunnelSocketOpenNack;
typedef struct SpiceMsgcTunnelSocketData {
uint16_t connection_id;
uint8_t data[0];
} SpiceMsgcTunnelSocketData;
typedef struct SpiceMsgcTunnelSocketFin {
uint16_t connection_id;
} SpiceMsgcTunnelSocketFin;
typedef struct SpiceMsgcTunnelSocketClosed {
uint16_t connection_id;
} SpiceMsgcTunnelSocketClosed;
typedef struct SpiceMsgcTunnelSocketClosedAck {
uint16_t connection_id;
} SpiceMsgcTunnelSocketClosedAck;
typedef struct SpiceMsgcTunnelSocketTokens {
uint16_t connection_id;
uint32_t num_tokens;
} SpiceMsgcTunnelSocketTokens;
#ifdef __cplusplus
}
} SpiceMsgSmartcard;
#endif
#endif /* _H_SPICE_PROTOCOL */
#include <common/generated_messages.h>
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentTokens;
typedef SpiceMsgMainAgentTokens SpiceMsgcMainAgentStart;
typedef SpiceMsgDisplayDrawCopy SpiceMsgDisplayDrawBlend;
typedef SpiceMsgPlaybackMode SpiceMsgcRecordMode;
typedef SpiceMsgPlaybackPacket SpiceMsgcRecordPacket;
SPICE_END_DECLS
#endif // H_SPICE_COMMON_MESSAGES

View File

@ -1,44 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MUTEX
#define _H_MUTEX
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#include <windows.h>
typedef CRITICAL_SECTION mutex_t;
#define MUTEX_INIT(mutex) InitializeCriticalSection(&mutex)
#define MUTEX_LOCK(mutex) EnterCriticalSection(&mutex)
#define MUTEX_UNLOCK(mutex) LeaveCriticalSection(&mutex)
#else
#include <pthread.h>
typedef pthread_mutex_t mutex_t;
#define MUTEX_INIT(mutex) pthread_mutex_init(&mutex, NULL);
#define MUTEX_LOCK(mutex) pthread_mutex_lock(&mutex)
#define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
#endif
#ifdef __cplusplus
}
#endif
#endif // _H_MUTEX

View File

@ -1,251 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include "ogl_ctx.h"
#include "spice_common.h"
enum {
OGLCTX_TYPE_PBUF,
OGLCTX_TYPE_PIXMAP,
};
struct OGLCtx {
int type;
Display *x_display;
GLXContext glx_context;
GLXDrawable drawable;
};
typedef struct OGLPixmapCtx {
OGLCtx base;
Pixmap pixmap;
} OGLPixmapCtx;
const char *oglctx_type_str(OGLCtx *ctx)
{
static const char *pbuf_str = "pbuf";
static const char *pixmap_str = "pixmap";
static const char *invalid_str = "invalid";
switch (ctx->type) {
case OGLCTX_TYPE_PBUF:
return pbuf_str;
case OGLCTX_TYPE_PIXMAP:
return pixmap_str;
default:
return invalid_str;
}
}
void oglctx_make_current(OGLCtx *ctx)
{
if (!glXMakeCurrent(ctx->x_display, ctx->drawable, ctx->glx_context)) {
printf("%s: failed\n", __FUNCTION__);
}
}
OGLCtx *pbuf_create(int width, int heigth)
{
OGLCtx *ctx;
Display *x_display;
int num_configs;
GLXFBConfig *fb_config;
GLXPbuffer glx_pbuf;
GLXContext glx_context;
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_STENCIL_SIZE, 4,
0 };
int pbuf_attrib[] = { GLX_PRESERVED_CONTENTS, True,
GLX_PBUFFER_WIDTH, width,
GLX_PBUFFER_HEIGHT, heigth,
GLX_LARGEST_PBUFFER, False,
0, 0 };
if (!(ctx = calloc(1, sizeof(*ctx)))) {
printf("%s: alloc pbuf failed\n", __FUNCTION__);
return NULL;
}
if (!(x_display = XOpenDisplay(NULL))) {
printf("%s: open display failed\n", __FUNCTION__);
goto error_1;
}
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
!num_configs) {
printf("%s: choose fb config failed\n", __FUNCTION__);
goto error_2;
}
if (!(glx_pbuf = glXCreatePbuffer(x_display, fb_config[0], pbuf_attrib))) {
goto error_3;
}
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
printf("%s: create context failed\n", __FUNCTION__);
goto error_4;
}
XFree(fb_config);
ctx->type = OGLCTX_TYPE_PBUF;
ctx->drawable = glx_pbuf;
ctx->glx_context = glx_context;
ctx->x_display = x_display;
return ctx;
error_4:
glXDestroyPbuffer(x_display, glx_pbuf);
error_3:
XFree(fb_config);
error_2:
XCloseDisplay(x_display);
error_1:
free(ctx);
return NULL;
}
OGLCtx *pixmap_create(int width, int heigth)
{
Display *x_display;
int num_configs;
GLXFBConfig *fb_config;
GLXPixmap glx_pixmap;
GLXContext glx_context;
Pixmap pixmap;
int screen;
Window root_window;
OGLPixmapCtx *pix;
const int glx_attributes[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_STENCIL_SIZE, 4,
0 };
if (!(pix = calloc(1, sizeof(*pix)))) {
printf("%s: alloc pix failed\n", __FUNCTION__);
return NULL;
}
if (!(x_display = XOpenDisplay(NULL))) {
printf("%s: open display failed\n", __FUNCTION__);
goto error_1;
}
screen = DefaultScreen(x_display);
root_window = RootWindow(x_display, screen);
if (!(fb_config = glXChooseFBConfig(x_display, 0, glx_attributes, &num_configs)) ||
!num_configs) {
printf("%s: choose fb config failed\n", __FUNCTION__);
goto error_2;
}
if (!(pixmap = XCreatePixmap(x_display, root_window, width, heigth, 32 /*use fb config*/))) {
printf("%s: create x pixmap failed\n", __FUNCTION__);
goto error_3;
}
if (!(glx_pixmap = glXCreatePixmap(x_display, fb_config[0], pixmap, NULL))) {
printf("%s: create glx pixmap failed\n", __FUNCTION__);
goto error_4;
}
if (!(glx_context = glXCreateNewContext(x_display, fb_config[0], GLX_RGBA_TYPE, NULL, True))) {
printf("%s: create context failed\n", __FUNCTION__);
goto error_5;
}
XFree(fb_config);
pix->base.type = OGLCTX_TYPE_PIXMAP;
pix->base.x_display = x_display;
pix->base.drawable = glx_pixmap;
pix->base.glx_context = glx_context;
pix->pixmap = pixmap;
return &pix->base;
error_5:
glXDestroyPixmap(x_display, glx_pixmap);
error_4:
XFreePixmap(x_display, pixmap);
error_3:
XFree(fb_config);
error_2:
XCloseDisplay(x_display);
error_1:
free(pix);
return NULL;
}
void oglctx_destroy(OGLCtx *ctx)
{
if (!ctx) {
return;
}
// test is current ?
glXDestroyContext(ctx->x_display, ctx->glx_context);
switch (ctx->type) {
case OGLCTX_TYPE_PBUF:
glXDestroyPbuffer(ctx->x_display, ctx->drawable);
break;
case OGLCTX_TYPE_PIXMAP:
glXDestroyPixmap(ctx->x_display, ctx->drawable);
XFreePixmap(ctx->x_display, ((OGLPixmapCtx *)ctx)->pixmap);
break;
default:
PANIC("invalid ogl ctx type");
}
XCloseDisplay(ctx->x_display);
free(ctx);
}

View File

@ -15,22 +15,26 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pixman_utils.h"
#include "spice_common.h"
#include <spice/macros.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mem.h"
/*
* src is used for most OPs, hidden within _equation attribute. For some
* operations (such as "clear" and "noop") src is not used and then we have
* to add SPICE_GNUC_UNUSED, that's just a __attribute__((__unused__)), to
* make GCC happy.
* Also, according to GCC documentation [0], the unused attribute "(...) means
* that the variable is meant to be possibly unused. GCC does not produce a
* warning for this variable.". So, we are safe adding it, even if src is used
* for most OPs.
*/
#define SOLID_RASTER_OP(_name, _size, _type, _equation) \
static void \
solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, _type src) \
solid_rop_ ## _name ## _ ## _size (_type *ptr, int len, SPICE_GNUC_UNUSED _type src) \
{ \
while (len--) { \
_type dst = *ptr; \
@ -206,12 +210,12 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
depth = spice_pixman_image_get_bpp(dest);
/* stride is in bytes, depth in bits */
ASSERT(x >= 0);
ASSERT(y >= 0);
ASSERT(width > 0);
ASSERT(height > 0);
ASSERT(x + width <= pixman_image_get_width(dest));
ASSERT(y + height <= pixman_image_get_height(dest));
spice_assert(x >= 0);
spice_assert(y >= 0);
spice_assert(width > 0);
spice_assert(height > 0);
spice_assert(x + width <= pixman_image_get_width(dest));
spice_assert(y + height <= pixman_image_get_height(dest));
if (pixman_fill(bits,
stride / 4,
@ -231,7 +235,7 @@ void spice_pixman_fill_rect(pixman_image_t *dest,
byte_width = 2 * width;
value = (value & 0xffff) * 0x00010001;
} else {
ASSERT (depth == 32)
spice_assert (depth == 32);
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
byte_width = 4 * width;
}
@ -298,13 +302,13 @@ void spice_pixman_fill_rect_rop(pixman_image_t *dest,
depth = spice_pixman_image_get_bpp(dest);
/* stride is in bytes, depth in bits */
ASSERT(x >= 0);
ASSERT(y >= 0);
ASSERT(width > 0);
ASSERT(height > 0);
ASSERT(x + width <= pixman_image_get_width(dest));
ASSERT(y + height <= pixman_image_get_height(dest));
ASSERT(rop >= 0 && rop < 16);
spice_assert(x >= 0);
spice_assert(y >= 0);
spice_assert(width > 0);
spice_assert(height > 0);
spice_assert(x + width <= pixman_image_get_width(dest));
spice_assert(y + height <= pixman_image_get_height(dest));
spice_assert(rop < 16);
if (depth == 8) {
solid_rop_8_func_t rop_func = solid_rops_8[rop];
@ -358,13 +362,13 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
tile_width = pixman_image_get_width(tile);
tile_height = pixman_image_get_height(tile);
ASSERT(x >= 0);
ASSERT(y >= 0);
ASSERT(width > 0);
ASSERT(height > 0);
ASSERT(x + width <= pixman_image_get_width(dest));
ASSERT(y + height <= pixman_image_get_height(dest));
ASSERT(depth == spice_pixman_image_get_bpp(tile));
spice_assert(x >= 0);
spice_assert(y >= 0);
spice_assert(width > 0);
spice_assert(height > 0);
spice_assert(x + width <= pixman_image_get_width(dest));
spice_assert(y + height <= pixman_image_get_height(dest));
spice_assert(depth == spice_pixman_image_get_bpp(tile));
tile_start_x = (x - offset_x) % tile_width;
if (tile_start_x < 0) {
@ -406,7 +410,7 @@ void spice_pixman_tile_rect(pixman_image_t *dest,
}
}
} else {
ASSERT (depth == 32);
spice_assert (depth == 32);
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
@ -449,14 +453,14 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
tile_width = pixman_image_get_width(tile);
tile_height = pixman_image_get_height(tile);
ASSERT(x >= 0);
ASSERT(y >= 0);
ASSERT(width > 0);
ASSERT(height > 0);
ASSERT(x + width <= pixman_image_get_width(dest));
ASSERT(y + height <= pixman_image_get_height(dest));
ASSERT(rop >= 0 && rop < 16);
ASSERT(depth == spice_pixman_image_get_bpp(tile));
spice_assert(x >= 0);
spice_assert(y >= 0);
spice_assert(width > 0);
spice_assert(height > 0);
spice_assert(x + width <= pixman_image_get_width(dest));
spice_assert(y + height <= pixman_image_get_height(dest));
spice_assert(rop < 16);
spice_assert(depth == spice_pixman_image_get_bpp(tile));
tile_start_x = (x - offset_x) % tile_width;
if (tile_start_x < 0) {
@ -504,7 +508,7 @@ void spice_pixman_tile_rect_rop(pixman_image_t *dest,
} else {
tiled_rop_32_func_t rop_func = tiled_rops_32[rop];
ASSERT (depth == 32);
spice_assert (depth == 32);
byte_line = ((uint8_t *)bits) + stride * y + x * 4;
tile_line = ((uint8_t *)tile_bits) + tile_stride * tile_start_y + tile_start_x * 4;
@ -536,6 +540,11 @@ void spice_pixman_blit(pixman_image_t *dest,
uint8_t *src_line;
int byte_width;
if (!src) {
fprintf(stderr, "missing src!");
return;
}
bits = pixman_image_get_data(dest);
stride = pixman_image_get_stride(dest);
depth = spice_pixman_image_get_bpp(dest);
@ -569,17 +578,17 @@ void spice_pixman_blit(pixman_image_t *dest,
return;
}
ASSERT(src_x >= 0);
ASSERT(src_y >= 0);
ASSERT(dest_x >= 0);
ASSERT(dest_y >= 0);
ASSERT(width > 0);
ASSERT(height > 0);
ASSERT(dest_x + width <= pixman_image_get_width(dest));
ASSERT(dest_y + height <= pixman_image_get_height(dest));
ASSERT(src_x + width <= pixman_image_get_width(src));
ASSERT(src_y + height <= pixman_image_get_height(src));
ASSERT(depth == src_depth);
spice_assert(src_x >= 0);
spice_assert(src_y >= 0);
spice_assert(dest_x >= 0);
spice_assert(dest_y >= 0);
spice_assert(width > 0);
spice_assert(height > 0);
spice_assert(dest_x + width <= pixman_image_get_width(dest));
spice_assert(dest_y + height <= pixman_image_get_height(dest));
spice_assert(src_x + width <= pixman_image_get_width(src));
spice_assert(src_y + height <= pixman_image_get_height(src));
spice_assert(depth == src_depth);
if (pixman_blt(src_bits,
bits,
@ -601,7 +610,7 @@ void spice_pixman_blit(pixman_image_t *dest,
byte_width = width * 2;
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 2;
} else {
ASSERT (depth == 32);
spice_assert (depth == 32);
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
byte_width = width * 4;
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
@ -660,17 +669,17 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
return;
}
ASSERT(src_x >= 0);
ASSERT(src_y >= 0);
ASSERT(dest_x >= 0);
ASSERT(dest_y >= 0);
ASSERT(width > 0);
ASSERT(height > 0);
ASSERT(dest_x + width <= pixman_image_get_width(dest));
ASSERT(dest_y + height <= pixman_image_get_height(dest));
ASSERT(src_x + width <= pixman_image_get_width(src));
ASSERT(src_y + height <= pixman_image_get_height(src));
ASSERT(depth == src_depth);
spice_assert(src_x >= 0);
spice_assert(src_y >= 0);
spice_assert(dest_x >= 0);
spice_assert(dest_y >= 0);
spice_assert(width > 0);
spice_assert(height > 0);
spice_assert(dest_x + width <= pixman_image_get_width(dest));
spice_assert(dest_y + height <= pixman_image_get_height(dest));
spice_assert(src_x + width <= pixman_image_get_width(src));
spice_assert(src_y + height <= pixman_image_get_height(src));
spice_assert(depth == src_depth);
if (depth == 8) {
copy_rop_8_func_t rop_func = copy_rops_8[rop];
@ -697,7 +706,7 @@ void spice_pixman_blit_rop (pixman_image_t *dest,
} else {
copy_rop_32_func_t rop_func = copy_rops_32[rop];
ASSERT (depth == 32);
spice_assert (depth == 32);
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
@ -756,17 +765,17 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
return;
}
ASSERT(src_x >= 0);
ASSERT(src_y >= 0);
ASSERT(dest_x >= 0);
ASSERT(dest_y >= 0);
ASSERT(width > 0);
ASSERT(height > 0);
ASSERT(dest_x + width <= pixman_image_get_width(dest));
ASSERT(dest_y + height <= pixman_image_get_height(dest));
ASSERT(src_x + width <= pixman_image_get_width(src));
ASSERT(src_y + height <= pixman_image_get_height(src));
ASSERT(depth == spice_pixman_image_get_bpp(src));
spice_assert(src_x >= 0);
spice_assert(src_y >= 0);
spice_assert(dest_x >= 0);
spice_assert(dest_y >= 0);
spice_assert(width > 0);
spice_assert(height > 0);
spice_assert(dest_x + width <= pixman_image_get_width(dest));
spice_assert(dest_y + height <= pixman_image_get_height(dest));
spice_assert(src_x + width <= pixman_image_get_width(src));
spice_assert(src_y + height <= pixman_image_get_height(src));
spice_assert(depth == spice_pixman_image_get_bpp(src));
if (depth == 8) {
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x;
@ -806,7 +815,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
src_line += src_stride;
}
} else {
ASSERT (depth == 32);
spice_assert (depth == 32);
byte_line = ((uint8_t *)bits) + stride * dest_y + dest_x * 4;
src_line = ((uint8_t *)src_bits) + src_stride * src_y + src_x * 4;
@ -924,8 +933,7 @@ pixman_format_code_t spice_surface_format_to_pixman(uint32_t surface_format)
case SPICE_SURFACE_FMT_32_ARGB:
return PIXMAN_a8r8g8b8;
default:
printf("Unknown surface format %d\n", surface_format);
abort();
g_error("Unknown surface format %d\n", surface_format);
break;
}
return (pixman_format_code_t)0; /* Not reached */
@ -958,10 +966,12 @@ pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format,
case SPICE_BITMAP_FMT_RGBA:
return PIXMAN_a8r8g8b8;
case SPICE_BITMAP_FMT_8BIT_A:
return PIXMAN_a8;
case SPICE_BITMAP_FMT_INVALID:
default:
printf("Unknown bitmap format %d\n", bitmap_format);
abort();
g_error("Unknown bitmap format %d\n", bitmap_format);
return PIXMAN_a8r8g8b8;
}
}
@ -985,25 +995,13 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
switch (src_format) {
case SPICE_BITMAP_FMT_32BIT:
#ifdef WORDS_BIGENDIAN
pixman_format = PIXMAN_b8g8r8x8;
#else
pixman_format = PIXMAN_x8r8g8b8;
#endif
pixman_format = PIXMAN_LE_x8r8g8b8;
break;
case SPICE_BITMAP_FMT_RGBA:
#ifdef WORDS_BIGENDIAN
pixman_format = PIXMAN_b8g8r8a8;
#else
pixman_format = PIXMAN_a8r8g8b8;
#endif
pixman_format = PIXMAN_LE_a8r8g8b8;
break;
case SPICE_BITMAP_FMT_24BIT:
#ifdef WORDS_BIGENDIAN
pixman_format = PIXMAN_b8g8r8;
#else
pixman_format = PIXMAN_r8g8b8;
#endif
pixman_format = PIXMAN_LE_r8g8b8;
break;
case SPICE_BITMAP_FMT_16BIT:
#ifdef WORDS_BIGENDIAN
@ -1037,26 +1035,6 @@ pixman_image_t *spice_bitmap_try_as_pixman(int src_format,
#define UINT32_FROM_LE(x) (x)
#endif
static INLINE uint32_t rgb_16_555_to_32(uint16_t color)
{
uint32_t ret;
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
return ret;
}
static INLINE uint16_t rgb_32_to_16_555(uint32_t color)
{
return
(((color) >> 3) & 0x001f) |
(((color) >> 6) & 0x03e0) |
(((color) >> 9) & 0x7c00);
}
static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
uint8_t* src, int src_stride,
int width, uint8_t* end)
@ -1078,6 +1056,15 @@ static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
#endif
}
static void bitmap_8_to_8(uint8_t* dest, int dest_stride,
uint8_t* src, int src_stride,
int width, uint8_t* end)
{
for (; src != end; src += src_stride, dest += dest_stride) {
memcpy(dest, src, width);
}
}
static void bitmap_24_to_32(uint8_t* dest, int dest_stride,
uint8_t* src, int src_stride,
int width, uint8_t* end)
@ -1131,7 +1118,7 @@ static void bitmap_8_32_to_32(uint8_t *dest, int dest_stride,
#endif
if (!palette) {
PANIC("No palette");
spice_error("No palette");
return;
}
@ -1177,7 +1164,7 @@ static void bitmap_8_16_to_16_555(uint8_t *dest, int dest_stride,
#endif
if (!palette) {
PANIC("No palette");
spice_error("No palette");
return;
}
@ -1223,7 +1210,7 @@ static void bitmap_4be_32_to_32(uint8_t* dest, int dest_stride,
#endif
if (!palette) {
PANIC("No palette");
spice_error("No palette");
return;
}
@ -1273,7 +1260,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
#endif
if (!palette) {
PANIC("No palette");
spice_error("No palette");
return;
}
@ -1310,7 +1297,7 @@ static void bitmap_4be_16_to_16_555(uint8_t* dest, int dest_stride,
}
}
static INLINE int test_bit_be(void* addr, int bit)
static inline int test_bit_be(void* addr, int bit)
{
return !!(((uint8_t*)addr)[bit >> 3] & (0x80 >> (bit & 0x07)));
}
@ -1323,7 +1310,7 @@ static void bitmap_1be_32_to_32(uint8_t* dest, int dest_stride,
uint32_t fore_color;
uint32_t back_color;
ASSERT(palette != NULL);
spice_assert(palette != NULL);
if (!palette) {
return;
@ -1355,7 +1342,7 @@ static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
uint16_t fore_color;
uint16_t back_color;
ASSERT(palette != NULL);
spice_assert(palette != NULL);
if (!palette) {
return;
@ -1380,6 +1367,25 @@ static void bitmap_1be_16_to_16_555(uint8_t* dest, int dest_stride,
#ifdef NOT_USED_ATM
static inline uint32_t rgb_16_555_to_32(uint16_t color)
{
uint32_t ret;
ret = ((color & 0x001f) << 3) | ((color & 0x001c) >> 2);
ret |= ((color & 0x03e0) << 6) | ((color & 0x0380) << 1);
ret |= ((color & 0x7c00) << 9) | ((color & 0x7000) << 4);
return ret;
}
static inline uint16_t rgb_32_to_16_555(uint32_t color)
{
return
(((color) >> 3) & 0x001f) |
(((color) >> 6) & 0x03e0) |
(((color) >> 9) & 0x7c00);
}
static void bitmap_16_to_32(uint8_t* dest, int dest_stride,
uint8_t* src, int src_stride,
int width, uint8_t* end)
@ -1461,7 +1467,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
dest = (uint8_t *)pixman_image_get_data(dest_image);
dest_stride = pixman_image_get_stride(dest_image);
if (!(flags & SPICE_BITMAP_FLAGS_TOP_DOWN)) {
ASSERT(height > 0);
spice_assert(height > 0);
dest += dest_stride * (height - 1);
dest_stride = -dest_stride;
}
@ -1472,6 +1478,9 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
case SPICE_BITMAP_FMT_RGBA:
bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
break;
case SPICE_BITMAP_FMT_8BIT_A:
bitmap_8_to_8(dest, dest_stride, src, src_stride, width, end);
break;
case SPICE_BITMAP_FMT_24BIT:
bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
break;
@ -1485,7 +1494,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
bitmap_8_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
} else {
PANIC("Unsupported palette format");
spice_error("Unsupported palette format");
}
break;
case SPICE_BITMAP_FMT_4BIT_BE:
@ -1495,7 +1504,7 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
bitmap_4be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
} else {
PANIC("Unsupported palette format");
spice_error("Unsupported palette format");
}
break;
case SPICE_BITMAP_FMT_1BIT_BE:
@ -1505,11 +1514,11 @@ pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
} else if (palette_surface_format == SPICE_SURFACE_FMT_16_555) {
bitmap_1be_16_to_16_555(dest, dest_stride, src, src_stride, width, end, palette);
} else {
PANIC("Unsupported palette format");
spice_error("Unsupported palette format");
}
break;
default:
PANIC("Unsupported bitmap format");
spice_error("Unsupported bitmap format");
break;
}

View File

@ -16,20 +16,29 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H__PIXMAN_UTILS
#define _H__PIXMAN_UTILS
#ifndef H_SPICE_COMMON_PIXMAN_UTILS
#define H_SPICE_COMMON_PIXMAN_UTILS
#include <spice/types.h>
#include <spice/macros.h>
#include <stdlib.h>
#define PIXMAN_DONT_DEFINE_STDINT
#include <pixman.h>
#include "draw.h"
#ifdef __cplusplus
extern "C" {
#ifdef WORDS_BIGENDIAN
# define PIXMAN_LE_x8r8g8b8 PIXMAN_b8g8r8x8
# define PIXMAN_LE_a8r8g8b8 PIXMAN_b8g8r8a8
# define PIXMAN_LE_r8g8b8 PIXMAN_b8g8r8
#else
# define PIXMAN_LE_x8r8g8b8 PIXMAN_x8r8g8b8
# define PIXMAN_LE_a8r8g8b8 PIXMAN_a8r8g8b8
# define PIXMAN_LE_r8g8b8 PIXMAN_r8g8b8
#endif
SPICE_BEGIN_DECLS
/* This lists all possible 2 argument binary raster ops.
* This enum has the same values as the X11 GXcopy type
* and same as the GL constants (GL_AND etc) if you
@ -129,8 +138,6 @@ void spice_pixman_copy_rect(pixman_image_t *image,
int w, int h,
int dest_x, int dest_y);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif /* _H__PIXMAN_UTILS */
#endif // H_SPICE_COMMON_PIXMAN_UTILS

File diff suppressed because it is too large Load Diff

View File

@ -16,14 +16,13 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __QUIC_H
#define __QUIC_H
#ifndef H_SPICE_COMMON_QUIC
#define H_SPICE_COMMON_QUIC
#include "quic_config.h"
#include <spice/macros.h>
#include "macros.h"
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
typedef enum {
QUIC_IMAGE_TYPE_INVALID,
@ -41,9 +40,10 @@ typedef void *QuicContext;
typedef struct QuicUsrContext QuicUsrContext;
struct QuicUsrContext {
void (*error)(QuicUsrContext *usr, const char *fmt, ...);
void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
void (*info)(QuicUsrContext *usr, const char *fmt, ...);
SPICE_GNUC_NORETURN
SPICE_GNUC_PRINTF(2, 3) void (*error)(QuicUsrContext *usr, const char *fmt, ...);
SPICE_GNUC_PRINTF(2, 3) void (*warn)(QuicUsrContext *usr, const char *fmt, ...);
SPICE_GNUC_PRINTF(2, 3) void (*info)(QuicUsrContext *usr, const char *fmt, ...);
void *(*malloc)(QuicUsrContext *usr, int size);
void (*free)(QuicUsrContext *usr, void *ptr);
int (*more_space)(QuicUsrContext *usr, uint32_t **io_ptr, int rows_completed);
@ -63,10 +63,6 @@ int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride)
QuicContext *quic_create(QuicUsrContext *usr);
void quic_destroy(QuicContext *quic);
void quic_init(void);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

View File

@ -16,15 +16,13 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __QUIC_CONFIG_H
#define __QUIC_CONFIG_H
#ifndef H_SPICE_COMMON_QUIC_CONFIG
#define H_SPICE_COMMON_QUIC_CONFIG
#include <spice/types.h>
#include <spice/macros.h>
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
#ifdef __GNUC__
#include <string.h>
@ -41,8 +39,6 @@ extern "C" {
#endif // QXLDD
#endif //__GNUC__
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

View File

@ -15,9 +15,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef QUIC_FAMILY_8BPC
#undef QUIC_FAMILY_8BPC
@ -34,26 +32,19 @@
#define BPC 5
#endif
static unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
static inline unsigned int FNAME(golomb_code)(const BYTE n, const unsigned int l)
{
if (n < VNAME(family).nGRcodewords[l]) {
return (n >> l) + 1 + l;
} else {
return VNAME(family).notGRcwlen[l];
}
return VNAME(family).golomb_code[n][l];
}
static void FNAME(golomb_coding)(const BYTE n, const unsigned int l, unsigned int * const codeword,
unsigned int * const codewordlen)
static inline unsigned int FNAME(golomb_code_len)(const BYTE n, const unsigned int l)
{
if (n < VNAME(family).nGRcodewords[l]) {
(*codeword) = bitat[l] | (n & bppmask[l]);
(*codewordlen) = (n >> l) + l + 1;
} else {
(*codeword) = n - VNAME(family).nGRcodewords[l];
(*codewordlen) = VNAME(family).notGRcwlen[l];
}
return VNAME(family).golomb_code_len[n][l];
}
static void FNAME(golomb_coding)(Encoder *encoder, const BYTE n, const unsigned int l)
{
encode(encoder, FNAME(golomb_code)(n, l), FNAME(golomb_code_len)(n, l));
}
static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned int bits,
@ -74,13 +65,16 @@ static unsigned int FNAME(golomb_decoding)(const unsigned int l, const unsigned
/* update the bucket using just encoded curval */
static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
const BYTE curval, unsigned int bpp)
const BYTE curval)
{
SPICE_VERIFY(BPC >= 1);
spice_return_if_fail (bucket != NULL);
const unsigned int bpp = BPC;
COUNTER * const pcounters = bucket->pcounters;
unsigned int i;
unsigned int bestcode;
unsigned int bestcodelen;
//unsigned int bpp = encoder->bpp;
/* update counters, find minimum */
@ -107,9 +101,14 @@ static void FNAME(update_model)(CommonState *state, s_bucket * const bucket,
static s_bucket *FNAME(find_bucket)(Channel *channel, const unsigned int val)
{
ASSERT(channel->encoder->usr, val < (0x1U << BPC));
spice_extra_assert(val < (0x1U << BPC));
return channel->_buckets_ptrs[val];
/* The and (&) here is to avoid buffer overflows in case of garbage or malicious
* attempts. Is much faster then using comparisons and save us from such situations.
* Note that on normal build the check above won't be compiled as this code path
* is pretty hot and would cause speed regressions.
*/
return channel->_buckets_ptrs[val & ((1U << BPC) - 1)];
}
#undef FNAME

View File

@ -1,765 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef QUIC_RGB32
#undef QUIC_RGB32
#define PIXEL rgb32_pixel_t
#define FNAME(name) quic_rgb32_##name
#define golomb_coding golomb_coding_8bpc
#define golomb_decoding golomb_decoding_8bpc
#define update_model update_model_8bpc
#define find_bucket find_bucket_8bpc
#define family family_8bpc
#define BPC 8
#define BPC_MASK 0xffU
#define COMPRESS_IMP
#define SET_r(pix, val) ((pix)->r = val)
#define GET_r(pix) ((pix)->r)
#define SET_g(pix, val) ((pix)->g = val)
#define GET_g(pix) ((pix)->g)
#define SET_b(pix, val) ((pix)->b = val)
#define GET_b(pix) ((pix)->b)
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
#endif
#ifdef QUIC_RGB24
#undef QUIC_RGB24
#define PIXEL rgb24_pixel_t
#define FNAME(name) quic_rgb24_##name
#define golomb_coding golomb_coding_8bpc
#define golomb_decoding golomb_decoding_8bpc
#define update_model update_model_8bpc
#define find_bucket find_bucket_8bpc
#define family family_8bpc
#define BPC 8
#define BPC_MASK 0xffU
#define COMPRESS_IMP
#define SET_r(pix, val) ((pix)->r = val)
#define GET_r(pix) ((pix)->r)
#define SET_g(pix, val) ((pix)->g = val)
#define GET_g(pix) ((pix)->g)
#define SET_b(pix, val) ((pix)->b = val)
#define GET_b(pix) ((pix)->b)
#define UNCOMPRESS_PIX_START(pix)
#endif
#ifdef QUIC_RGB16
#undef QUIC_RGB16
#define PIXEL rgb16_pixel_t
#define FNAME(name) quic_rgb16_##name
#define golomb_coding golomb_coding_5bpc
#define golomb_decoding golomb_decoding_5bpc
#define update_model update_model_5bpc
#define find_bucket find_bucket_5bpc
#define family family_5bpc
#define BPC 5
#define BPC_MASK 0x1fU
#define COMPRESS_IMP
#define SET_r(pix, val) (*(pix) = (*(pix) & ~(0x1f << 10)) | ((val) << 10))
#define GET_r(pix) ((*(pix) >> 10) & 0x1f)
#define SET_g(pix, val) (*(pix) = (*(pix) & ~(0x1f << 5)) | ((val) << 5))
#define GET_g(pix) ((*(pix) >> 5) & 0x1f)
#define SET_b(pix, val) (*(pix) = (*(pix) & ~0x1f) | (val))
#define GET_b(pix) (*(pix) & 0x1f)
#define UNCOMPRESS_PIX_START(pix) (*(pix) = 0)
#endif
#ifdef QUIC_RGB16_TO_32
#undef QUIC_RGB16_TO_32
#define PIXEL rgb32_pixel_t
#define FNAME(name) quic_rgb16_to_32_##name
#define golomb_coding golomb_coding_5bpc
#define golomb_decoding golomb_decoding_5bpc
#define update_model update_model_5bpc
#define find_bucket find_bucket_5bpc
#define family family_5bpc
#define BPC 5
#define BPC_MASK 0x1fU
#define SET_r(pix, val) ((pix)->r = ((val) << 3) | (((val) & 0x1f) >> 2))
#define GET_r(pix) ((pix)->r >> 3)
#define SET_g(pix, val) ((pix)->g = ((val) << 3) | (((val) & 0x1f) >> 2))
#define GET_g(pix) ((pix)->g >> 3)
#define SET_b(pix, val) ((pix)->b = ((val) << 3) | (((val) & 0x1f) >> 2))
#define GET_b(pix) ((pix)->b >> 3)
#define UNCOMPRESS_PIX_START(pix) ((pix)->pad = 0)
#endif
#define SAME_PIXEL(p1, p2) \
(GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \
GET_b(p1) == GET_b(p2))
#define _PIXEL_A(channel, curr) ((unsigned int)GET_##channel((curr) - 1))
#define _PIXEL_B(channel, prev) ((unsigned int)GET_##channel(prev))
#define _PIXEL_C(channel, prev) ((unsigned int)GET_##channel((prev) - 1))
/* a */
#define DECORELATE_0(channel, curr, bpc_mask)\
family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)_PIXEL_A(channel, curr)) & bpc_mask]
#define CORELATE_0(channel, curr, correlate, bpc_mask)\
((family.xlatL2U[correlate] + _PIXEL_A(channel, curr)) & bpc_mask)
#ifdef PRED_1
/* (a+b)/2 */
#define DECORELATE(channel, prev, curr, bpc_mask, r) \
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - (int)((_PIXEL_A(channel, curr) + \
_PIXEL_B(channel, prev)) >> 1)) & bpc_mask]
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) \
SET_##channel(r, ((family.xlatL2U[correlate] + \
(int)((_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev)) >> 1)) & bpc_mask))
#endif
#ifdef PRED_2
/* .75a+.75b-.5c */
#define DECORELATE(channel, prev, curr, bpc_mask, r) { \
int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
(int)(_PIXEL_C(channel, prev) << 1)) >> 2; \
if (p < 0) { \
p = 0; \
} else if ((unsigned)p > bpc_mask) { \
p = bpc_mask; \
} \
r = family.xlatU2L[(unsigned)((int)GET_##channel(curr) - p) & bpc_mask]; \
}
#define CORELATE(channel, prev, curr, correlate, bpc_mask, r) { \
const int p = ((int)(3 * (_PIXEL_A(channel, curr) + _PIXEL_B(channel, prev))) - \
(int)(_PIXEL_C(channel, prev) << 1) ) >> 2; \
const unsigned int s = family.xlatL2U[correlate]; \
if (!(p & ~bpc_mask)) { \
SET_##channel(r, (s + (unsigned)p) & bpc_mask); \
} else if (p < 0) { \
SET_##channel(r, s); \
} else { \
SET_##channel(r, (s + bpc_mask) & bpc_mask); \
} \
}
#endif
#define COMPRESS_ONE_ROW0_0(channel) \
correlate_row_##channel[0] = family.xlatU2L[GET_##channel(cur_row)]; \
golomb_coding(correlate_row_##channel[0], find_bucket(channel_##channel, \
correlate_row_##channel[-1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
#define COMPRESS_ONE_ROW0(channel, index) \
correlate_row_##channel[index] = DECORELATE_0(channel, &cur_row[index], bpc_mask); \
golomb_coding(correlate_row_##channel[index], find_bucket(channel_##channel, \
correlate_row_##channel[index -1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
#define UPDATE_MODEL(index) \
update_model(&encoder->rgb_state, find_bucket(channel_r, correlate_row_r[index - 1]), \
correlate_row_r[index], bpc); \
update_model(&encoder->rgb_state, find_bucket(channel_g, correlate_row_g[index - 1]), \
correlate_row_g[index], bpc); \
update_model(&encoder->rgb_state, find_bucket(channel_b, correlate_row_b[index - 1]), \
correlate_row_b[index], bpc);
#ifdef RLE_PRED_1
#define RLE_PRED_1_IMP \
if (SAME_PIXEL(&cur_row[i - 1], &prev_row[i])) { \
if (run_index != i && SAME_PIXEL(&prev_row[i - 1], &prev_row[i]) && \
i + 1 < end && SAME_PIXEL(&prev_row[i], &prev_row[i + 1])) { \
goto do_run; \
} \
}
#else
#define RLE_PRED_1_IMP
#endif
#ifdef RLE_PRED_2
#define RLE_PRED_2_IMP \
if (SAME_PIXEL(&prev_row[i - 1], &prev_row[i])) { \
if (run_index != i && i > 2 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2])) { \
goto do_run; \
} \
}
#else
#define RLE_PRED_2_IMP
#endif
#ifdef RLE_PRED_3
#define RLE_PRED_3_IMP \
if (i > 1 && SAME_PIXEL(&cur_row[i - 1], &cur_row[i - 2]) && i != run_index) { \
goto do_run; \
}
#else
#define RLE_PRED_3_IMP
#endif
#ifdef COMPRESS_IMP
static void FNAME(compress_row0_seg)(Encoder *encoder, int i,
const PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
int stopidx;
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_ROW0_0(r);
COMPRESS_ONE_ROW0_0(g);
COMPRESS_ONE_ROW0_0(b);
if (encoder->rgb_state.waitcnt) {
encoder->rgb_state.waitcnt--;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_ROW0(r, i);
COMPRESS_ONE_ROW0(g, i);
COMPRESS_ONE_ROW0(b, i);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_ROW0(r, i);
COMPRESS_ONE_ROW0(g, i);
COMPRESS_ONE_ROW0(b, i);
}
encoder->rgb_state.waitcnt = stopidx - end;
}
static void FNAME(compress_row0)(Encoder *encoder, const PIXEL *cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + encoder->rgb_state.wmileft,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
width -= encoder->rgb_state.wmileft;
pos += encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(compress_row0_seg)(encoder, pos, cur_row, pos + width,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#define COMPRESS_ONE_0(channel) \
correlate_row_##channel[0] = family.xlatU2L[(unsigned)((int)GET_##channel(cur_row) - \
(int)GET_##channel(prev_row) ) & bpc_mask]; \
golomb_coding(correlate_row_##channel[0], \
find_bucket(channel_##channel, correlate_row_##channel[-1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
#define COMPRESS_ONE(channel, index) \
DECORELATE(channel, &prev_row[index], &cur_row[index],bpc_mask, \
correlate_row_##channel[index]); \
golomb_coding(correlate_row_##channel[index], \
find_bucket(channel_##channel, correlate_row_##channel[index - 1])->bestcode, \
&codeword, &codewordlen); \
encode(encoder, codeword, codewordlen);
static void FNAME(compress_row_seg)(Encoder *encoder, int i,
const PIXEL * const prev_row,
const PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
int stopidx;
#ifdef RLE
int run_index = 0;
int run_size;
#endif
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codeword, codewordlen;
COMPRESS_ONE_0(r);
COMPRESS_ONE_0(g);
COMPRESS_ONE_0(b);
if (encoder->rgb_state.waitcnt) {
encoder->rgb_state.waitcnt--;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
for (;;) {
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codeword, codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
COMPRESS_ONE(r, i);
COMPRESS_ONE(g, i);
COMPRESS_ONE(b, i);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codeword, codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
COMPRESS_ONE(r, i);
COMPRESS_ONE(g, i);
COMPRESS_ONE(b, i);
}
encoder->rgb_state.waitcnt = stopidx - end;
return;
#ifdef RLE
do_run:
run_index = i;
encoder->rgb_state.waitcnt = stopidx - i;
run_size = 0;
while (SAME_PIXEL(&cur_row[i], &cur_row[i - 1])) {
run_size++;
if (++i == end) {
encode_run(encoder, run_size);
return;
}
}
encode_run(encoder, run_size);
stopidx = i + encoder->rgb_state.waitcnt;
#endif
}
}
static void FNAME(compress_row)(Encoder *encoder,
const PIXEL * const prev_row,
const PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
unsigned int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row,
pos + encoder->rgb_state.wmileft,
bppmask[encoder->rgb_state.wmidx],
bpc, bpc_mask);
width -= encoder->rgb_state.wmileft;
pos += encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(compress_row_seg)(encoder, pos, prev_row, cur_row, pos + width,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#endif
#define UNCOMPRESS_ONE_ROW0_0(channel) \
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[-1])->bestcode, \
encoder->io_word, &codewordlen); \
SET_##channel(&cur_row[0], (BYTE)family.xlatL2U[correlate_row_##channel[0]]); \
decode_eatbits(encoder, codewordlen);
#define UNCOMPRESS_ONE_ROW0(channel) \
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[i - 1])->bestcode, \
encoder->io_word, \
&codewordlen); \
SET_##channel(&cur_row[i], CORELATE_0(channel, &cur_row[i], correlate_row_##channel[i], \
bpc_mask)); \
decode_eatbits(encoder, codewordlen);
static void FNAME(uncompress_row0_seg)(Encoder *encoder, int i,
PIXEL * const cur_row,
const int end,
const unsigned int waitmask,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
int stopidx;
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_ROW0_0(r);
UNCOMPRESS_ONE_ROW0_0(g);
UNCOMPRESS_ONE_ROW0_0(b);
if (encoder->rgb_state.waitcnt) {
--encoder->rgb_state.waitcnt;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_ROW0(r);
UNCOMPRESS_ONE_ROW0(g);
UNCOMPRESS_ONE_ROW0(b);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_ROW0(r);
UNCOMPRESS_ONE_ROW0(g);
UNCOMPRESS_ONE_ROW0(b);
}
encoder->rgb_state.waitcnt = stopidx - end;
}
static void FNAME(uncompress_row0)(Encoder *encoder,
PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
unsigned int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(uncompress_row0_seg)(encoder, pos, cur_row,
pos + encoder->rgb_state.wmileft,
bppmask[encoder->rgb_state.wmidx],
bpc, bpc_mask);
pos += encoder->rgb_state.wmileft;
width -= encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(uncompress_row0_seg)(encoder, pos, cur_row, pos + width,
bppmask[encoder->rgb_state.wmidx], bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#define UNCOMPRESS_ONE_0(channel) \
correlate_row_##channel[0] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[-1])->bestcode, \
encoder->io_word, &codewordlen); \
SET_##channel(&cur_row[0], (family.xlatL2U[correlate_row_##channel[0]] + \
GET_##channel(prev_row)) & bpc_mask); \
decode_eatbits(encoder, codewordlen);
#define UNCOMPRESS_ONE(channel) \
correlate_row_##channel[i] = (BYTE)golomb_decoding(find_bucket(channel_##channel, \
correlate_row_##channel[i - 1])->bestcode, \
encoder->io_word, \
&codewordlen); \
CORELATE(channel, &prev_row[i], &cur_row[i], correlate_row_##channel[i], bpc_mask, \
&cur_row[i]); \
decode_eatbits(encoder, codewordlen);
static void FNAME(uncompress_row_seg)(Encoder *encoder,
const PIXEL * const prev_row,
PIXEL * const cur_row,
int i,
const int end,
const unsigned int bpc,
const unsigned int bpc_mask)
{
Channel * const channel_r = encoder->channels;
Channel * const channel_g = channel_r + 1;
Channel * const channel_b = channel_g + 1;
BYTE * const correlate_row_r = channel_r->correlate_row;
BYTE * const correlate_row_g = channel_g->correlate_row;
BYTE * const correlate_row_b = channel_b->correlate_row;
const unsigned int waitmask = bppmask[encoder->rgb_state.wmidx];
int stopidx;
#ifdef RLE
int run_index = 0;
int run_end;
#endif
ASSERT(encoder->usr, end - i > 0);
if (!i) {
unsigned int codewordlen;
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE_0(r);
UNCOMPRESS_ONE_0(g);
UNCOMPRESS_ONE_0(b);
if (encoder->rgb_state.waitcnt) {
--encoder->rgb_state.waitcnt;
} else {
encoder->rgb_state.waitcnt = (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
UPDATE_MODEL(0);
}
stopidx = ++i + encoder->rgb_state.waitcnt;
} else {
stopidx = i + encoder->rgb_state.waitcnt;
}
for (;;) {
while (stopidx < end) {
for (; i <= stopidx; i++) {
unsigned int codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE(r);
UNCOMPRESS_ONE(g);
UNCOMPRESS_ONE(b);
}
UPDATE_MODEL(stopidx);
stopidx = i + (tabrand(&encoder->rgb_state.tabrand_seed) & waitmask);
}
for (; i < end; i++) {
unsigned int codewordlen;
#ifdef RLE
RLE_PRED_1_IMP;
RLE_PRED_2_IMP;
RLE_PRED_3_IMP;
#endif
UNCOMPRESS_PIX_START(&cur_row[i]);
UNCOMPRESS_ONE(r);
UNCOMPRESS_ONE(g);
UNCOMPRESS_ONE(b);
}
encoder->rgb_state.waitcnt = stopidx - end;
return;
#ifdef RLE
do_run:
encoder->rgb_state.waitcnt = stopidx - i;
run_index = i;
run_end = i + decode_run(encoder);
for (; i < run_end; i++) {
UNCOMPRESS_PIX_START(&cur_row[i]);
SET_r(&cur_row[i], GET_r(&cur_row[i - 1]));
SET_g(&cur_row[i], GET_g(&cur_row[i - 1]));
SET_b(&cur_row[i], GET_b(&cur_row[i - 1]));
}
if (i == end) {
return;
}
stopidx = i + encoder->rgb_state.waitcnt;
#endif
}
}
static void FNAME(uncompress_row)(Encoder *encoder,
const PIXEL * const prev_row,
PIXEL * const cur_row,
unsigned int width)
{
const unsigned int bpc = BPC;
const unsigned int bpc_mask = BPC_MASK;
unsigned int pos = 0;
while ((wmimax > (int)encoder->rgb_state.wmidx) && (encoder->rgb_state.wmileft <= width)) {
if (encoder->rgb_state.wmileft) {
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
pos + encoder->rgb_state.wmileft, bpc, bpc_mask);
pos += encoder->rgb_state.wmileft;
width -= encoder->rgb_state.wmileft;
}
encoder->rgb_state.wmidx++;
set_wm_trigger(&encoder->rgb_state);
encoder->rgb_state.wmileft = wminext;
}
if (width) {
FNAME(uncompress_row_seg)(encoder, prev_row, cur_row, pos,
pos + width, bpc, bpc_mask);
if (wmimax > (int)encoder->rgb_state.wmidx) {
encoder->rgb_state.wmileft -= width;
}
}
ASSERT(encoder->usr, (int)encoder->rgb_state.wmidx <= wmimax);
ASSERT(encoder->usr, encoder->rgb_state.wmidx <= 32);
ASSERT(encoder->usr, wminext > 0);
}
#undef PIXEL
#undef FNAME
#undef _PIXEL_A
#undef _PIXEL_B
#undef _PIXEL_C
#undef SAME_PIXEL
#undef RLE_PRED_1_IMP
#undef RLE_PRED_2_IMP
#undef RLE_PRED_3_IMP
#undef UPDATE_MODEL
#undef DECORELATE_0
#undef DECORELATE
#undef COMPRESS_ONE_ROW0_0
#undef COMPRESS_ONE_ROW0
#undef COMPRESS_ONE_0
#undef COMPRESS_ONE
#undef CORELATE_0
#undef CORELATE
#undef UNCOMPRESS_ONE_ROW0_0
#undef UNCOMPRESS_ONE_ROW0
#undef UNCOMPRESS_ONE_0
#undef UNCOMPRESS_ONE
#undef golomb_coding
#undef golomb_decoding
#undef update_model
#undef find_bucket
#undef family
#undef BPC
#undef BPC_MASK
#undef COMPRESS_IMP
#undef SET_r
#undef GET_r
#undef SET_g
#undef GET_g
#undef SET_b
#undef GET_b
#undef UNCOMPRESS_PIX_START

File diff suppressed because it is too large Load Diff

1
common/recorder Submodule

@ -0,0 +1 @@
Subproject commit d5cbf6caba60d580401c72d0cd18c316cf1be211

106
common/recorder.h Normal file
View File

@ -0,0 +1,106 @@
/*
Copyright (C) 2018 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* This file include recorder library headers or if disabled provide
* replacement declarations */
#ifdef ENABLE_RECORDER
#include <common/recorder/recorder.h>
#elif defined(ENABLE_AGENT_INTERFACE)
#include <common/agent_interface.h>
#else
#include <stdio.h>
#include <stdint.h>
#include <spice/macros.h>
/* Replacement declarations.
* There declarations should generate no code (beside when no optimization are
* selected) but catch some possible programming warnings/errors at
* compile/link time like:
* - usage of undeclared recorders;
* - recording formats and arguments;
* - matching RECORD_TIMING_BEGIN and RECORD_TIMING_END.
* The only exceptions are tweaks which just generate a variable to hold the
* value.
*/
typedef struct SpiceEmptyStruct {
char dummy[0];
} SpiceEmptyStruct;
typedef struct SpiceDummyTweak {
intptr_t tweak_value;
} SpiceDummyTweak;
#define RECORDER_DECLARE(rec) \
extern const SpiceEmptyStruct spice_recorder_ ## rec
#define RECORDER(rec, num_rings, comment) \
RECORDER_DEFINE(rec, num_rings, comment)
#define RECORDER_DEFINE(rec, num_rings, comment) \
const SpiceEmptyStruct SPICE_GNUC_UNUSED spice_recorder_ ## rec = {}
#define RECORDER_TRACE(rec) \
(sizeof(spice_recorder_ ## rec) != sizeof(SpiceEmptyStruct))
#define RECORDER_TWEAK_DECLARE(rec) \
extern const SpiceDummyTweak spice_recorder_tweak_ ## rec
#define RECORDER_TWEAK_DEFINE(rec, value, comment) \
const SpiceDummyTweak spice_recorder_tweak_ ## rec = { (value) }
#define RECORDER_TWEAK(rec) \
((spice_recorder_tweak_ ## rec).tweak_value)
#define RECORD(rec, ...) do { \
if (sizeof((spice_recorder_ ## rec).dummy)) printf(__VA_ARGS__); \
} while(0)
#define RECORD_TIMING_BEGIN(rec) \
do { RECORD(rec, "begin");
#define RECORD_TIMING_END(rec, op, name, value) \
RECORD(rec, "end" op name); \
} while(0)
#define record(...) \
RECORD(__VA_ARGS__)
static inline void
recorder_dump_on_common_signals(unsigned add, unsigned remove)
{
}
#endif
#if !defined(ENABLE_AGENT_INTERFACE)
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/* Stubs for Agent-Interface specific definitions */
static inline void
agent_interface_start(unsigned int port)
{
}
typedef void (*forward_quality_cb_t)(void *, const char *);
static inline void
agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data)
{
}
typedef int (*on_connect_cb_t)(void *);
static inline void
agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data)
{
}
#ifdef __cplusplus
}
#endif // __cplusplus
#endif

View File

@ -16,17 +16,16 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RECT
#define _H_RECT
#ifndef H_SPICE_COMMON_RECT
#define H_SPICE_COMMON_RECT
#include "draw.h"
#include <spice/macros.h>
#include "draw.h"
#include "log.h"
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
static INLINE void rect_sect(SpiceRect* r, const SpiceRect* bounds)
static inline void rect_sect(SpiceRect* r, const SpiceRect* bounds)
{
r->left = MAX(r->left, bounds->left);
r->right = MIN(r->right, bounds->right);
@ -37,7 +36,7 @@ static INLINE void rect_sect(SpiceRect* r, const SpiceRect* bounds)
r->bottom = MAX(r->top, r->bottom);
}
static INLINE void rect_offset(SpiceRect* r, int dx, int dy)
static inline void rect_offset(SpiceRect* r, int dx, int dy)
{
r->left += dx;
r->right += dx;
@ -45,24 +44,24 @@ static INLINE void rect_offset(SpiceRect* r, int dx, int dy)
r->bottom += dy;
}
static INLINE int rect_is_empty(const SpiceRect* r)
static inline int rect_is_empty(const SpiceRect* r)
{
return r->top == r->bottom || r->left == r->right;
}
static INLINE int rect_intersects(const SpiceRect* r1, const SpiceRect* r2)
static inline int rect_intersects(const SpiceRect* r1, const SpiceRect* r2)
{
return r1->left < r2->right && r1->right > r2->left &&
r1->top < r2->bottom && r1->bottom > r2->top;
}
static INLINE int rect_is_equal(const SpiceRect *r1, const SpiceRect *r2)
static inline int rect_is_equal(const SpiceRect *r1, const SpiceRect *r2)
{
return r1->top == r2->top && r1->left == r2->left &&
r1->bottom == r2->bottom && r1->right == r2->right;
}
static INLINE void rect_union(SpiceRect *dest, const SpiceRect *r)
static inline void rect_union(SpiceRect *dest, const SpiceRect *r)
{
dest->top = MIN(dest->top, r->top);
dest->left = MIN(dest->left, r->left);
@ -70,15 +69,29 @@ static INLINE void rect_union(SpiceRect *dest, const SpiceRect *r)
dest->right = MAX(dest->right, r->right);
}
static INLINE int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
static inline int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
{
return r1->right - r1->left == r2->right - r2->left &&
r1->bottom - r1->top == r2->bottom - r2->top;
}
#ifdef __cplusplus
static inline int rect_contains(const SpiceRect *big_rect, const SpiceRect *small_rect)
{
return big_rect->left <= small_rect->left && big_rect->right >= small_rect->right &&
big_rect->top <= small_rect->top && big_rect->bottom >= small_rect->bottom;
}
#endif
static inline int rect_get_area(const SpiceRect *r)
{
return (r->right - r->left) * (r->bottom - r->top);
}
static inline void rect_debug(const SpiceRect *r)
{
spice_debug("(%d, %d) (%d, %d)", r->left, r->top, r->right, r->bottom);
}
SPICE_END_DECLS
#ifdef __cplusplus
@ -117,6 +130,21 @@ static inline int rect_is_same_size(const SpiceRect& r1, const SpiceRect& r2)
return rect_is_same_size(&r1, &r2);
}
#endif
static inline int rect_contains(const SpiceRect& big_rect, const SpiceRect& small_rect)
{
return rect_contains(&big_rect, &small_rect);
}
static inline int rect_get_area(const SpiceRect& r)
{
return rect_get_area(&r);
}
static inline void rect_debug(const SpiceRect &r)
{
rect_debug(&r);
}
#endif /* __cplusplus */
#endif

View File

@ -15,9 +15,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
@ -386,6 +384,17 @@ void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects)
}
}
void region_extents(const QRegion *rgn, SpiceRect *r)
{
pixman_box32_t *extents;
extents = pixman_region32_extents((pixman_region32_t *)rgn);
r->left = extents->x1;
r->top = extents->y1;
r->right = extents->x2;
r->bottom = extents->y2;
}
int region_is_equal(const QRegion *rgn1, const QRegion *rgn2)
{
@ -409,7 +418,7 @@ int region_bounds_intersects(const QRegion *rgn1, const QRegion *rgn2)
pixman_box32_t *extents1, *extents2;
extents1 = pixman_region32_extents((pixman_region32_t *)rgn1);
extents2 = pixman_region32_extents((pixman_region32_t *)rgn1);
extents2 = pixman_region32_extents((pixman_region32_t *)rgn2);
return EXTENTCHECK(extents1, extents2);
}
@ -441,6 +450,7 @@ void region_xor(QRegion *rgn, const QRegion *other_rgn)
{
pixman_region32_t intersection;
pixman_region32_init(&intersection);
pixman_region32_copy(&intersection, rgn);
pixman_region32_intersect(&intersection,
&intersection,
@ -510,381 +520,3 @@ void region_dump(const QRegion *rgn, const char *prefix)
rects[i].y2);
}
}
#ifdef REGION_TEST
static int slow_region_test(const QRegion *rgn, const QRegion *other_rgn, int query)
{
pixman_region32_t intersection;
int res;
pixman_region32_init(&intersection);
pixman_region32_intersect(&intersection,
(pixman_region32_t *)rgn,
(pixman_region32_t *)other_rgn);
res = 0;
if (query & REGION_TEST_SHARED &&
pixman_region32_not_empty(&intersection)) {
res |= REGION_TEST_SHARED;
}
if (query & REGION_TEST_LEFT_EXCLUSIVE &&
!pixman_region32_equal(&intersection, (pixman_region32_t *)rgn)) {
res |= REGION_TEST_LEFT_EXCLUSIVE;
}
if (query & REGION_TEST_RIGHT_EXCLUSIVE &&
!pixman_region32_equal(&intersection, (pixman_region32_t *)other_rgn)) {
res |= REGION_TEST_RIGHT_EXCLUSIVE;
}
pixman_region32_fini(&intersection);
return res;
}
static int rect_is_valid(const SpiceRect *r)
{
if (r->top > r->bottom || r->left > r->right) {
printf("%s: invalid rect\n", __FUNCTION__);
return FALSE;
}
return TRUE;
}
static void rect_set(SpiceRect *r, int32_t top, int32_t left, int32_t bottom, int32_t right)
{
r->top = top;
r->left = left;
r->bottom = bottom;
r->right = right;
ASSERT(rect_is_valid(r));
}
static void random_region(QRegion *reg)
{
int i;
int num_rects;
int x, y, w, h;
SpiceRect _r;
SpiceRect *r = &_r;
region_clear(reg);
num_rects = rand() % 20;
for (i = 0; i < num_rects; i++) {
x = rand()%100;
y = rand()%100;
w = rand()%100;
h = rand()%100;
rect_set(r,
x, y,
x+w, y+h);
region_add(reg, r);
}
}
static void test(const QRegion *r1, const QRegion *r2, int *expected)
{
printf("r1 is_empty %s [%s]\n",
region_is_empty(r1) ? "TRUE" : "FALSE",
(region_is_empty(r1) == *(expected++)) ? "OK" : "ERR");
printf("r2 is_empty %s [%s]\n",
region_is_empty(r2) ? "TRUE" : "FALSE",
(region_is_empty(r2) == *(expected++)) ? "OK" : "ERR");
printf("is_equal %s [%s]\n",
region_is_equal(r1, r2) ? "TRUE" : "FALSE",
(region_is_equal(r1, r2) == *(expected++)) ? "OK" : "ERR");
printf("intersects %s [%s]\n",
region_intersects(r1, r2) ? "TRUE" : "FALSE",
(region_intersects(r1, r2) == *(expected++)) ? "OK" : "ERR");
printf("contains %s [%s]\n",
region_contains(r1, r2) ? "TRUE" : "FALSE",
(region_contains(r1, r2) == *(expected++)) ? "OK" : "ERR");
}
enum {
EXPECT_R1_EMPTY,
EXPECT_R2_EMPTY,
EXPECT_EQUAL,
EXPECT_SECT,
EXPECT_CONT,
};
int main(void)
{
QRegion _r1, _r2, _r3;
QRegion *r1 = &_r1;
QRegion *r2 = &_r2;
QRegion *r3 = &_r3;
SpiceRect _r;
SpiceRect *r = &_r;
int expected[5];
int i, j;
region_init(r1);
region_init(r2);
printf("dump r1 empty rgn [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = TRUE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clone(r3, r1);
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
region_dump(r3, "");
expected[EXPECT_R1_EMPTY] = TRUE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r3, expected);
region_destroy(r3);
printf("\n");
rect_set(r, 0, 0, 100, 100);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r1);
rect_set(r, 0, 0, 0, 0);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = TRUE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
rect_set(r, -100, -100, 0, 0);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r1);
rect_set(r, -100, -100, 100, 100);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r1);
region_clear(r2);
rect_set(r, 100, 100, 200, 200);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
rect_set(r, 300, 300, 400, 400);
region_add(r1, r);
printf("dump r1 [%s]\n", region_is_valid(r1) ? "VALID" : "INVALID");
region_dump(r1, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = TRUE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
rect_set(r, 500, 500, 600, 600);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 100, 100, 200, 200);
region_add(r2, r);
rect_set(r, 300, 300, 400, 400);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 100, 100, 200, 200);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, -2000, -2000, -1000, -1000);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = FALSE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, -2000, -2000, 1000, 1000);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 150, 150, 175, 175);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r2, expected);
printf("\n");
region_clear(r2);
rect_set(r, 150, 150, 350, 350);
region_add(r2, r);
printf("dump r2 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = FALSE;
test(r1, r2, expected);
printf("\n");
region_and(r2, r1);
printf("dump r2 and r1 [%s]\n", region_is_valid(r2) ? "VALID" : "INVALID");
region_dump(r2, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = FALSE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = FALSE;
test(r2, r1, expected);
printf("\n");
region_clone(r3, r1);
printf("dump r3 clone rgn [%s]\n", region_is_valid(r3) ? "VALID" : "INVALID");
region_dump(r3, "");
expected[EXPECT_R1_EMPTY] = FALSE;
expected[EXPECT_R2_EMPTY] = FALSE;
expected[EXPECT_EQUAL] = TRUE;
expected[EXPECT_SECT] = TRUE;
expected[EXPECT_CONT] = TRUE;
test(r1, r3, expected);
printf("\n");
j = 0;
for (i = 0; i < 1000000; i++) {
int res1, res2, test;
int tests[] = {
REGION_TEST_LEFT_EXCLUSIVE,
REGION_TEST_RIGHT_EXCLUSIVE,
REGION_TEST_SHARED,
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE,
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_SHARED,
REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED,
REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED
};
random_region(r1);
random_region(r2);
for (test = 0; test < 7; test++) {
res1 = region_test(r1, r2, tests[test]);
res2 = slow_region_test(r1, r2, tests[test]);
if (res1 != res2) {
printf ("Error in region_test %d, got %d, expected %d, query=%d\n",
j, res1, res2, tests[test]);
printf ("r1:\n");
region_dump(r1, "");
printf ("r2:\n");
region_dump(r2, "");
}
j++;
}
}
region_destroy(r3);
region_destroy(r1);
region_destroy(r2);
return 0;
}
#endif

View File

@ -16,21 +16,24 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_REGION
#define _H_REGION
#ifndef H_SPICE_COMMON_REGION
#define H_SPICE_COMMON_REGION
#include <stdint.h>
#include "draw.h"
#include <pixman_utils.h>
#include <spice/macros.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "draw.h"
#include "pixman_utils.h"
SPICE_BEGIN_DECLS
typedef pixman_region32_t QRegion;
/* the left region is not contained entirely within the right region */
#define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
/* the right region is not contained entirely within the left region */
#define REGION_TEST_RIGHT_EXCLUSIVE (1 << 1)
/* the regions overlap */
#define REGION_TEST_SHARED (1 << 2)
#define REGION_TEST_ALL \
(REGION_TEST_LEFT_EXCLUSIVE | REGION_TEST_RIGHT_EXCLUSIVE | REGION_TEST_SHARED)
@ -41,6 +44,7 @@ void region_destroy(QRegion *rgn);
void region_clone(QRegion *dest, const QRegion *src);
SpiceRect *region_dup_rects(const QRegion *rgn, uint32_t *num_rects);
void region_ret_rects(const QRegion *rgn, SpiceRect *rects, uint32_t num_rects);
void region_extents(const QRegion *rgn, SpiceRect *r);
int region_test(const QRegion *rgn, const QRegion *other_rgn, int query);
int region_is_valid(const QRegion *rgn);
@ -61,10 +65,9 @@ void region_remove(QRegion *rgn, const SpiceRect *r);
void region_offset(QRegion *rgn, int32_t dx, int32_t dy);
void region_dump(const QRegion *rgn, const char *prefix);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

View File

@ -16,14 +16,12 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RING2
#define _H_RING2
#ifndef H_SPICE_COMMON_RING
#define H_SPICE_COMMON_RING
#include "spice_common.h"
#include "log.h"
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
typedef struct Ring RingItem;
typedef struct Ring {
@ -48,14 +46,14 @@ static inline int ring_item_is_linked(RingItem *item)
static inline int ring_is_empty(Ring *ring)
{
ASSERT(ring->next != NULL && ring->prev != NULL);
spice_assert(ring->next != NULL && ring->prev != NULL);
return ring == ring->next;
}
static inline void ring_add(Ring *ring, RingItem *item)
{
ASSERT(ring->next != NULL && ring->prev != NULL);
ASSERT(item->next == NULL && item->prev == NULL);
spice_assert(ring->next != NULL && ring->prev != NULL);
spice_assert(item->next == NULL && item->prev == NULL);
item->next = ring->next;
item->prev = ring;
@ -72,54 +70,43 @@ static inline void ring_add_before(RingItem *item, RingItem *pos)
ring_add(pos->prev, item);
}
static inline void __ring_remove(RingItem *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
item->prev = item->next = 0;
}
static inline void ring_remove(RingItem *item)
{
ASSERT(item->next != NULL && item->prev != NULL);
ASSERT(item->next != item);
spice_assert(item->next != NULL && item->prev != NULL);
spice_assert(item->next != item);
__ring_remove(item);
item->next->prev = item->prev;
item->prev->next = item->next;
item->prev = item->next = NULL;
}
static inline RingItem *ring_get_head(Ring *ring)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
spice_assert(ring->next != NULL && ring->prev != NULL);
if (ring_is_empty(ring)) {
return NULL;
}
ret = ring->next;
return ret;
return ring->next;
}
static inline RingItem *ring_get_tail(Ring *ring)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
spice_assert(ring->next != NULL && ring->prev != NULL);
if (ring_is_empty(ring)) {
return NULL;
}
ret = ring->prev;
return ret;
return ring->prev;
}
static inline RingItem *ring_next(Ring *ring, RingItem *pos)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
ASSERT(pos);
ASSERT(pos->next != NULL && pos->prev != NULL);
spice_assert(ring->next != NULL && ring->prev != NULL);
spice_assert(pos);
spice_assert(pos->next != NULL && pos->prev != NULL);
ret = pos->next;
return (ret == ring) ? NULL : ret;
}
@ -128,9 +115,9 @@ static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
{
RingItem *ret;
ASSERT(ring->next != NULL && ring->prev != NULL);
ASSERT(pos);
ASSERT(pos->next != NULL && pos->prev != NULL);
spice_assert(ring->next != NULL && ring->prev != NULL);
spice_assert(pos);
spice_assert(pos->next != NULL && pos->prev != NULL);
ret = pos->prev;
return (ret == ring) ? NULL : ret;
}
@ -157,16 +144,12 @@ static inline unsigned int ring_get_length(Ring *ring)
RingItem *i;
unsigned int ret = 0;
for (i = ring_get_head(ring);
i != NULL;
i = ring_next(ring, i))
RING_FOREACH(i, ring)
ret++;
return ret;
}
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

View File

@ -15,14 +15,9 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include "rop3.h"
#include "spice_common.h"
typedef void (*rop3_with_pattern_handler_t)(pixman_image_t *d, pixman_image_t *s,
SpicePoint *src_pos, pixman_image_t *p,
@ -43,17 +38,21 @@ static rop3_test_handler_t rop3_test_handlers_32[ROP3_NUM_OPS];
static rop3_test_handler_t rop3_test_handlers_16[ROP3_NUM_OPS];
static void default_rop3_with_pattern_handler(pixman_image_t *d, pixman_image_t *s,
SpicePoint *src_pos, pixman_image_t *p,
SpicePoint *pat_pos)
static void default_rop3_with_pattern_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
SPICE_GNUC_UNUSED pixman_image_t *s,
SPICE_GNUC_UNUSED SpicePoint *src_pos,
SPICE_GNUC_UNUSED pixman_image_t *p,
SPICE_GNUC_UNUSED SpicePoint *pat_pos)
{
WARN("not implemented");
spice_critical("not implemented");
}
static void default_rop3_withe_color_handler(pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
uint32_t rgb)
static void default_rop3_withe_color_handler(SPICE_GNUC_UNUSED pixman_image_t *d,
SPICE_GNUC_UNUSED pixman_image_t *s,
SPICE_GNUC_UNUSED SpicePoint *src_pos,
SPICE_GNUC_UNUSED uint32_t rgb)
{
WARN("not implemented");
spice_critical("not implemented");
}
static void default_rop3_test_handler(void)
@ -374,16 +373,10 @@ ROP3_HANDLERS(DPSoo, *src | *pat | *dest, 0xfe);
rop3_test_handlers_32[index] = rop3_test32_##op; \
rop3_test_handlers_16[index] = rop3_test16_##op;
void rop3_init(void)
SPICE_CONSTRUCTOR_FUNC(rop3_global_init)
{
static int need_init = 1;
int i;
if (!need_init) {
return;
}
need_init = 0;
for (i = 0; i < ROP3_NUM_OPS; i++) {
rop3_with_pattern_handlers_32[i] = default_rop3_with_pattern_handler;
rop3_with_pattern_handlers_16[i] = default_rop3_with_pattern_handler;
@ -624,8 +617,8 @@ void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, Sp
int bpp;
bpp = spice_pixman_image_get_bpp(d);
ASSERT (bpp == spice_pixman_image_get_bpp(s));
ASSERT (bpp == spice_pixman_image_get_bpp(p));
spice_assert(bpp == spice_pixman_image_get_bpp(s));
spice_assert(bpp == spice_pixman_image_get_bpp(p));
if (bpp == 32) {
rop3_with_pattern_handlers_32[rop3](d, s, src_pos, p, pat_pos);
@ -640,7 +633,7 @@ void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, Spic
int bpp;
bpp = spice_pixman_image_get_bpp(d);
ASSERT (bpp == spice_pixman_image_get_bpp(s));
spice_assert(bpp == spice_pixman_image_get_bpp(s));
if (bpp == 32) {
rop3_with_color_handlers_32[rop3](d, s, src_pos, rgb);

View File

@ -16,27 +16,22 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_ROP3
#define _H_ROP3
#ifndef H_SPICE_COMMON_ROP3
#define H_SPICE_COMMON_ROP3
#include <stdint.h>
#include <spice/macros.h>
#include "draw.h"
#include "pixman_utils.h"
#ifdef __cplusplus
extern "C" {
#endif
SPICE_BEGIN_DECLS
void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
pixman_image_t *p, SpicePoint *pat_pos);
void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
uint32_t rgb);
void rop3_init(void);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

276
common/snd_codec.c Normal file
View File

@ -0,0 +1,276 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2013 Jeremy White
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* snd_codec.c
General purpose sound codec routines for use by Spice.
These routines abstract the work of picking a codec and
encoding and decoding the buffers.
See below for documentation of the public routines.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#if HAVE_OPUS
#include <opus.h>
#endif
#include <spice/macros.h>
#include <spice/enums.h>
#include "snd_codec.h"
#include "mem.h"
#include "log.h"
typedef struct SndCodecInternal
{
SpiceAudioDataMode mode;
int frequency;
#if HAVE_OPUS
OpusEncoder *opus_encoder;
OpusDecoder *opus_decoder;
#endif
} SndCodecInternal;
/* Opus support routines */
#if HAVE_OPUS
static void snd_codec_destroy_opus(SndCodecInternal *codec)
{
if (codec->opus_decoder) {
opus_decoder_destroy(codec->opus_decoder);
codec->opus_decoder = NULL;
}
if (codec->opus_encoder) {
opus_encoder_destroy(codec->opus_encoder);
codec->opus_encoder = NULL;
}
}
static SndCodecResult snd_codec_create_opus(SndCodecInternal *codec, int purpose)
{
int opus_error;
if (purpose & SND_CODEC_ENCODE) {
codec->opus_encoder = opus_encoder_create(codec->frequency,
SND_CODEC_PLAYBACK_CHAN,
OPUS_APPLICATION_AUDIO, &opus_error);
if (! codec->opus_encoder) {
g_warning("create opus encoder failed; error %d", opus_error);
goto error;
}
}
if (purpose & SND_CODEC_DECODE) {
codec->opus_decoder = opus_decoder_create(codec->frequency,
SND_CODEC_PLAYBACK_CHAN, &opus_error);
if (! codec->opus_decoder) {
g_warning("create opus decoder failed; error %d", opus_error);
goto error;
}
}
codec->mode = SPICE_AUDIO_DATA_MODE_OPUS;
return SND_CODEC_OK;
error:
snd_codec_destroy_opus(codec);
return SND_CODEC_UNAVAILABLE;
}
static SndCodecResult
snd_codec_encode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size,
uint8_t *out_ptr, int *out_size)
{
int n;
if (in_size != SND_CODEC_OPUS_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2)
return SND_CODEC_INVALID_ENCODE_SIZE;
n = opus_encode(codec->opus_encoder, (opus_int16 *) in_ptr, SND_CODEC_OPUS_FRAME_SIZE, out_ptr, *out_size);
if (n < 0) {
g_warning("opus_encode failed %d", n);
return SND_CODEC_ENCODE_FAILED;
}
*out_size = n;
return SND_CODEC_OK;
}
static SndCodecResult
snd_codec_decode_opus(SndCodecInternal *codec, uint8_t *in_ptr, int in_size,
uint8_t *out_ptr, int *out_size)
{
int n;
n = opus_decode(codec->opus_decoder, in_ptr, in_size, (opus_int16 *) out_ptr,
*out_size / SND_CODEC_PLAYBACK_CHAN / 2, 0);
if (n < 0) {
g_warning("opus_decode failed %d", n);
return SND_CODEC_DECODE_FAILED;
}
*out_size = n * SND_CODEC_PLAYBACK_CHAN * 2 /* 16 fmt */;
return SND_CODEC_OK;
}
#endif
/*----------------------------------------------------------------------------
** PUBLIC INTERFACE
**--------------------------------------------------------------------------*/
/*
snd_codec_is_capable
Returns true if the current spice implementation can
use the given codec, false otherwise.
mode must be a SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h
*/
bool snd_codec_is_capable(SpiceAudioDataMode mode, int frequency)
{
#if HAVE_OPUS
if (mode == SPICE_AUDIO_DATA_MODE_OPUS &&
(frequency == SND_CODEC_ANY_FREQUENCY ||
frequency == 48000 || frequency == 24000 ||
frequency == 16000 || frequency == 12000 ||
frequency == 8000) )
return true;
#endif
return false;
}
/*
snd_codec_create
Create a codec control. Required for most functions in this library.
Parameters:
1. codec Pointer to preallocated codec control
2. mode SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h
3. encode TRUE if encoding is desired
4. decode TRUE if decoding is desired
Returns:
SND_CODEC_OK if all went well; a different code if not.
snd_codec_destroy is the obvious partner of snd_codec_create.
*/
SndCodecResult
snd_codec_create(SndCodec *codec, SpiceAudioDataMode mode, int frequency, int purpose)
{
SndCodecResult rc = SND_CODEC_UNAVAILABLE;
SndCodecInternal **c = codec;
*c = spice_new0(SndCodecInternal, 1);
(*c)->frequency = frequency;
#if HAVE_OPUS
if (mode == SPICE_AUDIO_DATA_MODE_OPUS)
rc = snd_codec_create_opus(*c, purpose);
#endif
return rc;
}
/*
snd_codec_destroy
The obvious companion to snd_codec_create
*/
void snd_codec_destroy(SndCodec *codec)
{
SndCodecInternal **c = codec;
if (! c || ! *c)
return;
#if HAVE_OPUS
snd_codec_destroy_opus(*c);
#endif
free(*c);
*c = NULL;
}
/*
snd_codec_frame_size
Returns the size, in frames, of the raw PCM frame buffer
required by this codec. To get bytes, you'll need
to multiply by channels and sample width.
*/
int snd_codec_frame_size(SndCodec codec)
{
#if HAVE_OPUS
SndCodecInternal *c = codec;
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
return SND_CODEC_OPUS_FRAME_SIZE;
#endif
return SND_CODEC_MAX_FRAME_SIZE;
}
/*
snd_codec_encode
Encode a block of data to a compressed buffer.
Parameters:
1. codec Pointer to codec control previously allocated + created
2. in_ptr Pointer to uncompressed PCM data
3. in_size Input size
4. out_ptr Pointer to area to write encoded data
5. out_size On input, the maximum size of the output buffer; on
successful return, it will hold the number of bytes
returned.
Returns:
SND_CODEC_OK if all went well
*/
SndCodecResult
snd_codec_encode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
{
#if HAVE_OPUS
SndCodecInternal *c = codec;
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
return snd_codec_encode_opus(c, in_ptr, in_size, out_ptr, out_size);
#endif
return SND_CODEC_ENCODER_UNAVAILABLE;
}
/*
snd_codec_decode
Decode a block of data from a compressed buffer.
Parameters:
1. codec Pointer to codec control previously allocated + created
2. in_ptr Pointer to compressed data
3. in_size Input size
4. out_ptr Pointer to area to write decoded data
5. out_size On input, the maximum size of the output buffer; on
successful return, it will hold the number of bytes
returned.
Returns:
SND_CODEC_OK if all went well
*/
SndCodecResult
snd_codec_decode(SndCodec codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size)
{
#if HAVE_OPUS
SndCodecInternal *c = codec;
if (c && c->mode == SPICE_AUDIO_DATA_MODE_OPUS)
return snd_codec_decode_opus(c, in_ptr, in_size, out_ptr, out_size);
#endif
return SND_CODEC_DECODER_UNAVAILABLE;
}

69
common/snd_codec.h Normal file
View File

@ -0,0 +1,69 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2013 Jeremy White <jwhite@codeweavers.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef H_SPICE_COMMON_SND_CODEC
#define H_SPICE_COMMON_SND_CODEC
#include <stdbool.h>
#include <spice/enums.h>
#define SND_CODEC_OPUS_FRAME_SIZE 480
#define SND_CODEC_OPUS_PLAYBACK_FREQ 48000
#define SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES 480
#define SND_CODEC_PLAYBACK_CHAN 2
#define SND_CODEC_MAX_FRAME_SIZE SND_CODEC_OPUS_FRAME_SIZE
#define SND_CODEC_MAX_FRAME_BYTES (SND_CODEC_MAX_FRAME_SIZE * SND_CODEC_PLAYBACK_CHAN * 2 /* FMT_S16 */)
#define SND_CODEC_MAX_COMPRESSED_BYTES SND_CODEC_OPUS_COMPRESSED_FRAME_BYTES
#define SND_CODEC_ANY_FREQUENCY -1
#define SND_CODEC_ENCODE 0x0001
#define SND_CODEC_DECODE 0x0002
SPICE_BEGIN_DECLS
typedef enum {
SND_CODEC_OK,
SND_CODEC_UNAVAILABLE,
SND_CODEC_ENCODER_UNAVAILABLE,
SND_CODEC_DECODER_UNAVAILABLE,
SND_CODEC_ENCODE_FAILED,
SND_CODEC_DECODE_FAILED,
SND_CODEC_INVALID_ENCODE_SIZE,
} SndCodecResult;
typedef struct SndCodecInternal * SndCodec;
bool snd_codec_is_capable(SpiceAudioDataMode mode, int frequency);
SndCodecResult snd_codec_create(SndCodec *codec,
SpiceAudioDataMode mode, int frequency, int purpose);
void snd_codec_destroy(SndCodec *codec);
int snd_codec_frame_size(SndCodec codec);
SndCodecResult snd_codec_encode(SndCodec codec, uint8_t *in_ptr, int in_size,
uint8_t *out_ptr, int *out_size);
SndCodecResult snd_codec_decode(SndCodec codec, uint8_t *in_ptr, int in_size,
uint8_t *out_ptr, int *out_size);
SPICE_END_DECLS
#endif

View File

@ -1,78 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef H_SPICE_COMMON
#define H_SPICE_COMMON
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <stdlib.h>
#include "backtrace.h"
#define ASSERT(x) if (!(x)) { \
printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \
spice_backtrace(); \
abort(); \
}
#define PANIC(format, ...) do { \
printf("%s: panic: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
abort(); \
} while (0)
#define PANIC_ON(x) if ((x)) { \
printf("%s: panic %s\n", __FUNCTION__, #x); \
abort(); \
}
#define red_error(format, ...) do { \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
abort(); \
} while (0)
#define red_printf(format, ...) \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ )
#define red_printf_once(format, ...) do { \
static int do_print = TRUE; \
if (do_print) { \
do_print = FALSE; \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
} \
} while (0)
#define WARN(format, ...) red_printf("warning: "format, ##__VA_ARGS__ );
#define WARN_ONCE red_printf_once
#define red_printf_some(every, format, ...) do { \
static int count = 0; \
if (count++ % (every) == 0) { \
printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ); \
} \
} while (0)
#define red_printf_debug(debug, prefix, format, ...) do { \
static int debug_level = -1; \
if (debug_level == -1) { \
debug_level = getenv("SPICE_DEBUG_LEVEL") != NULL ? atoi(getenv("SPICE_DEBUG_LEVEL")) : 0; \
} \
if (debug <= debug_level) { \
printf("%s: %s: " format "\n", prefix, __FUNCTION__, ## __VA_ARGS__ ); \
} \
} while(0)
#endif

View File

@ -16,12 +16,11 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mem.h"
#include "ssl_verify.h"
#include "log.h"
#ifndef WIN32
#include <sys/socket.h>
@ -29,21 +28,14 @@
#include <arpa/inet.h>
#endif
#include <ctype.h>
#include <string.h>
#include <gio/gio.h>
#ifndef SPICE_DEBUG
# define SPICE_DEBUG(format, ...)
#endif
#ifdef WIN32
static int inet_aton(const char* ip, struct in_addr* in_addr)
#if OPENSSL_VERSION_NUMBER < 0x10100000 || \
(defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000)
static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
{
unsigned long addr = inet_addr(ip);
if (addr == INADDR_NONE) {
return 0;
}
in_addr->S_un.S_addr = addr;
return 1;
return M_ASN1_STRING_data(asn1);
}
#endif
@ -58,36 +50,41 @@ static int verify_pubkey(X509* cert, const char *key, size_t key_size)
return 0;
if (!cert) {
SPICE_DEBUG("warning: no cert!");
spice_debug("warning: no cert!");
return 0;
}
cert_pubkey = X509_get_pubkey(cert);
if (!cert_pubkey) {
SPICE_DEBUG("warning: reading public key from certificate failed");
spice_debug("warning: reading public key from certificate failed");
goto finish;
}
bio = BIO_new_mem_buf((void*)key, key_size);
if (!bio) {
SPICE_DEBUG("creating BIO failed");
spice_debug("creating BIO failed");
goto finish;
}
orig_pubkey = d2i_PUBKEY_bio(bio, NULL);
if (!orig_pubkey) {
SPICE_DEBUG("reading pubkey from bio failed");
spice_debug("reading pubkey from bio failed");
goto finish;
}
#if OPENSSL_VERSION_NUMBER >= 0x30000000
ret = EVP_PKEY_eq(orig_pubkey, cert_pubkey);
#else
ret = EVP_PKEY_cmp(orig_pubkey, cert_pubkey);
#endif
if (ret == 1)
SPICE_DEBUG("public keys match");
else if (ret == 0)
SPICE_DEBUG("public keys mismatch");
else
SPICE_DEBUG("public keys types mismatch");
if (ret == 1) {
spice_debug("public keys match");
} else if (ret == 0) {
spice_debug("public keys mismatch");
} else {
spice_debug("public keys types mismatch");
}
finish:
if (bio)
@ -162,19 +159,14 @@ static int verify_hostname(X509* cert, const char *hostname)
{
GENERAL_NAMES* subject_alt_names;
int found_dns_name = 0;
struct in_addr addr;
int addr_len = 0;
int cn_match = 0;
X509_NAME* subject;
if (!cert) {
SPICE_DEBUG("warning: no cert!");
return 0;
}
spice_return_val_if_fail(hostname != NULL, 0);
// only IpV4 supported
if (inet_aton(hostname, &addr)) {
addr_len = sizeof(struct in_addr);
if (!cert) {
spice_debug("warning: no cert!");
return 0;
}
/* try matching against:
@ -200,30 +192,56 @@ static int verify_hostname(X509* cert, const char *hostname)
const GENERAL_NAME* name = sk_GENERAL_NAME_value(subject_alt_names, i);
if (name->type == GEN_DNS) {
found_dns_name = 1;
if (_gnutls_hostname_compare((char *)ASN1_STRING_data(name->d.dNSName),
if (_gnutls_hostname_compare((const char *)ASN1_STRING_get0_data(name->d.dNSName),
ASN1_STRING_length(name->d.dNSName),
hostname)) {
SPICE_DEBUG("alt name match=%s", ASN1_STRING_data(name->d.dNSName));
spice_debug("alt name match=%s", ASN1_STRING_get0_data(name->d.dNSName));
GENERAL_NAMES_free(subject_alt_names);
return 1;
}
} else if (name->type == GEN_IPADD) {
int alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
GInetAddress * ip;
const guint8 * ip_binary;
int alt_ip_len;
int ip_len;
found_dns_name = 1;
if ((addr_len == alt_ip_len)&&
!memcmp(ASN1_STRING_data(name->d.iPAddress), &addr, addr_len)) {
SPICE_DEBUG("alt name IP match=%s",
inet_ntoa(*((struct in_addr*)ASN1_STRING_data(name->d.dNSName))));
ip = g_inet_address_new_from_string(hostname);
if (ip == NULL) {
spice_warning("Could not parse hostname: %s", hostname);
continue;
}
ip_len = g_inet_address_get_native_size(ip);
ip_binary = g_inet_address_to_bytes(ip);
alt_ip_len = ASN1_STRING_length(name->d.iPAddress);
if ((ip_len == alt_ip_len) &&
(memcmp(ASN1_STRING_get0_data(name->d.iPAddress), ip_binary, ip_len)) == 0) {
GInetAddress * alt_ip = NULL;
gchar * alt_ip_string = NULL;
alt_ip = g_inet_address_new_from_bytes(ASN1_STRING_get0_data(name->d.iPAddress),
g_inet_address_get_family(ip));
alt_ip_string = g_inet_address_to_string(alt_ip);
spice_debug("alt name IP match=%s", alt_ip_string);
g_free(alt_ip_string);
g_object_unref(alt_ip);
g_object_unref(ip);
GENERAL_NAMES_free(subject_alt_names);
return 1;
}
g_object_unref(ip);
}
}
GENERAL_NAMES_free(subject_alt_names);
}
if (found_dns_name) {
SPICE_DEBUG("warning: SubjectAltName mismatch");
spice_debug("warning: SubjectAltName mismatch");
return 0;
}
@ -244,38 +262,41 @@ static int verify_hostname(X509* cert, const char *hostname)
continue;
}
if (_gnutls_hostname_compare((char*)ASN1_STRING_data(cn_asn1),
if (_gnutls_hostname_compare((const char*)ASN1_STRING_get0_data(cn_asn1),
ASN1_STRING_length(cn_asn1),
hostname)) {
SPICE_DEBUG("common name match=%s", (char*)ASN1_STRING_data(cn_asn1));
spice_debug("common name match=%s", (char*)ASN1_STRING_get0_data(cn_asn1));
cn_match = 1;
break;
}
}
}
if (!cn_match)
SPICE_DEBUG("warning: common name mismatch");
if (!cn_match) {
spice_debug("warning: common name mismatch");
}
return cn_match;
}
X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
static X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
{
X509_NAME* in_subject;
const char *p;
char *key, *val, *k, *v = NULL;
char *key, *val = NULL, *k, *v = NULL;
enum {
KEY,
VALUE
} state;
key = (char*)alloca(strlen(subject));
val = (char*)alloca(strlen(subject));
spice_return_val_if_fail(subject != NULL, NULL);
spice_return_val_if_fail(nentries != NULL, NULL);
key = (char*)alloca(strlen(subject)+1);
in_subject = X509_NAME_new();
if (!in_subject || !key || !val) {
SPICE_DEBUG("failed to allocate");
if (!in_subject || !key) {
spice_debug("failed to allocate");
return NULL;
}
@ -288,7 +309,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
if (*p == '\\') {
++p;
if (*p != '\\' && *p != ',') {
SPICE_DEBUG("Invalid character after \\");
spice_debug("Invalid character after \\");
goto fail;
}
escape = 1;
@ -307,6 +328,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
} else if (*p == '=' && !escape) {
state = VALUE;
*k = 0;
val = k + 1;
v = val;
} else
*k++ = *p;
@ -322,7 +344,7 @@ X509_NAME* subject_to_x509_name(const char *subject, int *nentries)
MBSTRING_UTF8,
(const unsigned char*)val,
-1, -1, 0)) {
SPICE_DEBUG("warning: failed to add entry %s=%s to X509_NAME",
spice_debug("warning: failed to add entry %s=%s to X509_NAME",
key, val);
goto fail;
}
@ -349,89 +371,145 @@ fail:
return NULL;
}
int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
static int verify_subject(X509* cert, SpiceOpenSSLVerify* verify)
{
X509_NAME *cert_subject = NULL;
X509_NAME* in_subject;
int ret;
int in_entries;
if (!cert) {
SPICE_DEBUG("warning: no cert!");
spice_debug("warning: no cert!");
return 0;
}
cert_subject = X509_get_subject_name(cert);
if (!cert_subject) {
SPICE_DEBUG("warning: reading certificate subject failed");
spice_debug("warning: reading certificate subject failed");
return 0;
}
if (!verify->in_subject) {
verify->in_subject = subject_to_x509_name(verify->subject, &in_entries);
if (!verify->in_subject) {
SPICE_DEBUG("warning: no in_subject!");
return 0;
}
in_subject = subject_to_x509_name(verify->subject, &in_entries);
if (!in_subject) {
spice_debug("warning: no in_subject!");
return 0;
}
/* Note: this check is redundant with the pre-condition in X509_NAME_cmp */
if (X509_NAME_entry_count(cert_subject) != in_entries) {
SPICE_DEBUG("subject mismatch: #entries cert=%d, input=%d",
spice_debug("subject mismatch: #entries cert=%d, input=%d",
X509_NAME_entry_count(cert_subject), in_entries);
X509_NAME_free(in_subject);
return 0;
}
ret = X509_NAME_cmp(cert_subject, verify->in_subject);
ret = X509_NAME_cmp(cert_subject, in_subject);
if (ret == 0)
SPICE_DEBUG("subjects match");
else
SPICE_DEBUG("subjects mismatch");
if (ret == 0) {
spice_debug("subjects match");
} else {
char *p;
spice_debug("subjects mismatch");
p = X509_NAME_oneline(cert_subject, NULL, 0);
spice_debug("cert_subject: %s", p);
free(p);
p = X509_NAME_oneline(in_subject, NULL, 0);
spice_debug("in_subject: %s", p);
free(p);
}
X509_NAME_free(in_subject);
return !ret;
}
static int openssl_verify(int preverify_ok, X509_STORE_CTX *ctx)
{
int depth;
int depth, err;
SpiceOpenSSLVerify *v;
SSL *ssl;
X509* cert;
char buf[256];
unsigned int failed_verifications;
ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
v = (SpiceOpenSSLVerify*)SSL_get_app_data(ssl);
cert = X509_STORE_CTX_get_current_cert(ctx);
X509_NAME_oneline(X509_get_subject_name(cert), buf, 256);
depth = X509_STORE_CTX_get_error_depth(ctx);
err = X509_STORE_CTX_get_error(ctx);
if (depth > 0) {
if (!preverify_ok) {
SPICE_DEBUG("openssl verify failed at depth=%d", depth);
spice_warning("Error in certificate chain verification: %s (num=%d:depth%d:%s)",
X509_verify_cert_error_string(err), err, depth, buf);
v->all_preverify_ok = 0;
/* if certificate verification failed, we can still authorize the server */
/* if its public key matches the one we hold in the peer_connect_options. */
if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN &&
v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY)
return 1;
if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
spice_debug("server certificate not being signed by the provided CA");
return 0;
} else
return 1;
}
/* depth == 0 */
cert = X509_STORE_CTX_get_current_cert(ctx);
if (!cert) {
SPICE_DEBUG("failed to get server certificate");
spice_debug("failed to get server certificate");
return 0;
}
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY &&
verify_pubkey(cert, v->pubkey, v->pubkey_size))
return 1;
failed_verifications = 0;
if (v->verifyop & SPICE_SSL_VERIFY_OP_PUBKEY) {
if (verify_pubkey(cert, v->pubkey, v->pubkey_size))
return 1;
else
failed_verifications |= SPICE_SSL_VERIFY_OP_PUBKEY;
}
if (!v->all_preverify_ok || !preverify_ok)
if (!preverify_ok) {
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
spice_warning("Error in server certificate verification: %s (num=%d:depth%d:%s)",
X509_verify_cert_error_string(err), err, depth, buf);
return 0;
}
if (!v->all_preverify_ok) {
return 0;
}
if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME &&
verify_hostname(cert, v->hostname))
return 1;
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT) {
if (verify_subject(cert, v))
return 1;
else
failed_verifications |= SPICE_SSL_VERIFY_OP_SUBJECT;
} else if (v->verifyop & SPICE_SSL_VERIFY_OP_HOSTNAME) {
if (verify_hostname(cert, v->hostname))
return 1;
else
failed_verifications |= SPICE_SSL_VERIFY_OP_HOSTNAME;
}
if (v->verifyop & SPICE_SSL_VERIFY_OP_SUBJECT &&
verify_subject(cert, v))
return 1;
/* If we reach this code, this means all the tests failed, thus
* verification failed
*/
if (failed_verifications & SPICE_SSL_VERIFY_OP_PUBKEY)
spice_warning("ssl: pubkey verification failed");
if (failed_verifications & SPICE_SSL_VERIFY_OP_HOSTNAME)
spice_warning("ssl: hostname '%s' verification failed", v->hostname);
if (failed_verifications & SPICE_SSL_VERIFY_OP_SUBJECT)
spice_warning("ssl: subject '%s' verification failed", v->subject);
spice_warning("ssl: verification failed");
return 0;
}
@ -473,9 +551,6 @@ void spice_openssl_verify_free(SpiceOpenSSLVerify* verify)
free(verify->subject);
free(verify->hostname);
if (verify->in_subject)
X509_NAME_free(verify->in_subject);
if (verify->ssl)
SSL_set_app_data(verify->ssl, NULL);
free(verify);

View File

@ -16,12 +16,16 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SSL_VERIFY_H
#define SSL_VERIFY_H
#ifndef H_SPICE_COMMON_SSL_VERIFY
#define H_SPICE_COMMON_SSL_VERIFY
#if defined(WIN32) && !defined(__MINGW32__)
#if defined(WIN32)
#include <windows.h>
#include <wincrypt.h>
#ifdef X509_NAME
/* wincrypt.h has already a different define... */
#undef X509_NAME
#endif
#endif
#include <openssl/rsa.h>
@ -29,12 +33,11 @@
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#undef X509_NAME
#include <openssl/x509v3.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <spice/macros.h>
SPICE_BEGIN_DECLS
typedef enum {
SPICE_SSL_VERIFY_OP_NONE = 0,
@ -51,7 +54,6 @@ typedef struct {
char *pubkey;
size_t pubkey_size;
char *subject;
X509_NAME *in_subject;
} SpiceOpenSSLVerify;
SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop,
@ -60,7 +62,6 @@ SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verif
const char *subject);
void spice_openssl_verify_free(SpiceOpenSSLVerify* verify);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SSL_VERIFY_H
SPICE_END_DECLS
#endif // H_SPICE_COMMON_SSL_VERIFY

View File

@ -15,21 +15,13 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#ifdef __MINGW32__
#undef HAVE_STDLIB_H
#endif
#include <config.h>
#endif
#ifndef SPICE_CANVAS_INTERNAL
#error "This file shouldn't be compiled directly"
#endif
#include <math.h>
#include "sw_canvas.h"
#define CANVAS_USE_PIXMAN
#define CANVAS_SINGLE_INSTANCE
#include "canvas_base.c"
#include "rect.h"
#include "region.h"
@ -83,15 +75,33 @@ static pixman_image_t *canvas_get_pixman_brush(SwCanvas *canvas,
case SPICE_BRUSH_TYPE_NONE:
return NULL;
default:
CANVAS_ERROR("invalid brush type");
spice_warn_if_reached();
return NULL;
}
return NULL;
}
static pixman_image_t *get_image(SpiceCanvas *canvas)
static pixman_image_t *get_image(SpiceCanvas *canvas, int force_opaque)
{
SwCanvas *sw_canvas = (SwCanvas *)canvas;
pixman_format_code_t format;
pixman_image_ref(sw_canvas->image);
spice_pixman_image_get_format(sw_canvas->image, &format);
if (force_opaque && PIXMAN_FORMAT_A (format) != 0) {
uint32_t *data;
int stride;
int width, height;
/* Remove alpha bits from format */
format = (pixman_format_code_t)(((uint32_t)format) & ~(0xf << 12));
data = pixman_image_get_data(sw_canvas->image);
stride = pixman_image_get_stride(sw_canvas->image);
width = pixman_image_get_width(sw_canvas->image);
height = pixman_image_get_height(sw_canvas->image);
return pixman_image_create_bits(format, width, height, data, stride);
} else {
pixman_image_ref(sw_canvas->image);
}
return sw_canvas->image;
}
@ -343,8 +353,8 @@ static void clear_dest_alpha(pixman_image_t *dest,
}
stride = pixman_image_get_stride(dest);
data = (uint32_t *) (
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
data = SPICE_ALIGNED_CAST(uint32_t *,
(uint8_t *)pixman_image_get_data(dest) + y * stride + 4 * x);
if ((*data & 0xff000000U) == 0xff000000U) {
spice_pixman_fill_rect_rop(dest,
@ -472,13 +482,13 @@ static void __scale_image(SpiceCanvas *spice_canvas,
pixman_transform_init_scale(&transform, fsx, fsy);
pixman_transform_translate(&transform, NULL,
pixman_int_to_fixed (src_x),
pixman_int_to_fixed (src_y));
pixman_int_to_fixed(src_x),
pixman_int_to_fixed(src_y));
pixman_image_set_transform(src, &transform);
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
pixman_image_set_filter(src,
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
@ -539,11 +549,13 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
pixman_box32_t *rects;
int n_rects, i;
pixman_fixed_t fsx, fsy;
pixman_format_code_t format;
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
scaled = pixman_image_create_bits(spice_pixman_image_get_format(src),
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
scaled = pixman_image_create_bits(format,
dest_width,
dest_height,
NULL, 0);
@ -553,13 +565,13 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas,
pixman_transform_init_scale(&transform, fsx, fsy);
pixman_transform_translate(&transform, NULL,
pixman_int_to_fixed (src_x),
pixman_int_to_fixed (src_y));
pixman_int_to_fixed(src_x),
pixman_int_to_fixed(src_y));
pixman_image_set_transform(src, &transform);
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
pixman_image_set_filter(src,
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
@ -659,7 +671,7 @@ static void __blend_image(SpiceCanvas *spice_canvas,
mask = NULL;
if (overall_alpha != 0xff) {
pixman_color_t color = { 0 };
pixman_color_t color = { 0, 0, 0, 0 };
color.alpha = overall_alpha * 0x101;
mask = pixman_image_create_solid_fill(&color);
}
@ -747,20 +759,20 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas,
pixman_transform_init_scale(&transform, fsx, fsy);
pixman_transform_translate(&transform, NULL,
pixman_int_to_fixed (src_x),
pixman_int_to_fixed (src_y));
pixman_int_to_fixed(src_x),
pixman_int_to_fixed(src_y));
mask = NULL;
if (overall_alpha != 0xff) {
pixman_color_t color = { 0 };
pixman_color_t color = { 0, 0, 0, 0 };
color.alpha = overall_alpha * 0x101;
mask = pixman_image_create_solid_fill(&color);
}
pixman_image_set_transform(src, &transform);
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
ASSERT(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
spice_return_if_fail(scale_mode == SPICE_IMAGE_SCALE_MODE_INTERPOLATE ||
scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST);
pixman_image_set_filter(src,
(scale_mode == SPICE_IMAGE_SCALE_MODE_NEAREST) ?
PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD,
@ -895,11 +907,13 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
pixman_box32_t *rects;
int n_rects, i;
pixman_fixed_t fsx, fsy;
pixman_format_code_t format;
fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width;
fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height;
scaled = pixman_image_create_bits(spice_pixman_image_get_format (src),
spice_return_if_fail(spice_pixman_image_get_format(src, &format));
scaled = pixman_image_create_bits(format,
dest_width,
dest_height,
NULL, 0);
@ -909,8 +923,8 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas,
pixman_transform_init_scale(&transform, fsx, fsy);
pixman_transform_translate(&transform, NULL,
pixman_int_to_fixed (src_x),
pixman_int_to_fixed (src_y));
pixman_int_to_fixed(src_x),
pixman_int_to_fixed(src_y));
pixman_image_set_transform(src, &transform);
pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE);
@ -977,9 +991,6 @@ static void colorkey_scale_image_from_surface(SpiceCanvas *spice_canvas,
}
static void canvas_put_image(SpiceCanvas *spice_canvas,
#ifdef WIN32
HDC dc,
#endif
const SpiceRect *dest, const uint8_t *src_data,
uint32_t src_width, uint32_t src_height, int src_stride,
const QRegion *clip)
@ -994,7 +1005,7 @@ static void canvas_put_image(SpiceCanvas *spice_canvas,
src = pixman_image_create_bits(PIXMAN_x8r8g8b8,
src_width,
src_height,
(uint32_t*)src_data,
SPICE_ALIGNED_CAST(uint32_t*,src_data),
src_stride);
@ -1042,7 +1053,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
pixman_region32_t dest_region;
pixman_image_t *str_mask, *brush;
SpiceString *str;
SpicePoint pos;
SpicePoint pos = { 0, 0 };
int depth;
pixman_region32_init_rect(&dest_region,
@ -1064,7 +1075,7 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
/* Nothing else makes sense for text and we should deprecate it
* and actually it means OVER really */
ASSERT(text->fore_mode == SPICE_ROPD_OP_PUT);
spice_return_if_fail(text->fore_mode == SPICE_ROPD_OP_PUT);
pixman_region32_init_rect(&back_region,
text->back_area.left,
@ -1087,10 +1098,10 @@ static void canvas_draw_text(SpiceCanvas *spice_canvas, SpiceRect *bbox,
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A4) {
depth = 4;
} else if (str->flags & SPICE_STRING_FLAGS_RASTER_A8) {
WARN("untested path A8 glyphs");
spice_warning("untested path A8 glyphs");
depth = 8;
} else {
WARN("unsupported path vector glyphs");
spice_warning("unsupported path vector glyphs");
pixman_region32_fini (&dest_region);
return;
}
@ -1133,7 +1144,7 @@ static void canvas_read_bits(SpiceCanvas *spice_canvas, uint8_t *dest,
uint8_t *dest_end;
int bpp;
ASSERT(canvas && area);
spice_return_if_fail(canvas && area);
surface = canvas->image;
@ -1170,47 +1181,37 @@ static void canvas_destroy(SpiceCanvas *spice_canvas)
free(canvas);
}
static int need_init = 1;
static SpiceCanvasOps sw_canvas_ops;
static SpiceCanvas *canvas_create_common(pixman_image_t *image,
uint32_t format
uint32_t format,
SpiceImageCache *bits_cache,
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
SpicePaletteCache *palette_cache,
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
)
SpiceImageSurfaces *surfaces,
SpiceGlzDecoder *glz_decoder,
SpiceJpegDecoder *jpeg_decoder,
SpiceZlibDecoder *zlib_decoder)
{
SwCanvas *canvas;
if (need_init) {
return NULL;
}
spice_pixman_image_set_format(image,
spice_surface_format_to_pixman (format));
spice_surface_format_to_pixman(format));
canvas = spice_new0(SwCanvas, 1);
canvas_base_init(&canvas->base, &sw_canvas_ops,
pixman_image_get_width (image),
pixman_image_get_height (image),
format
pixman_image_get_width(image),
pixman_image_get_height(image),
format,
bits_cache,
#ifdef SW_CANVAS_CACHE
, bits_cache
, palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, bits_cache
palette_cache,
#endif
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
);
surfaces,
glz_decoder,
jpeg_decoder,
zlib_decoder);
canvas->private_data = NULL;
canvas->private_data_size = 0;
@ -1219,78 +1220,37 @@ static SpiceCanvas *canvas_create_common(pixman_image_t *image,
return (SpiceCanvas *)canvas;
}
SpiceCanvas *canvas_create(int width, int height, uint32_t format
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
)
{
pixman_image_t *image;
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
width, height, NULL, 0);
return canvas_create_common(image, format
#ifdef SW_CANVAS_CACHE
, bits_cache
, palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, bits_cache
#endif
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
);
}
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
uint8_t *data, int stride
uint8_t *data, int stride,
SpiceImageCache *bits_cache,
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
SpicePaletteCache *palette_cache,
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
)
SpiceImageSurfaces *surfaces,
SpiceGlzDecoder *glz_decoder,
SpiceJpegDecoder *jpeg_decoder,
SpiceZlibDecoder *zlib_decoder)
{
pixman_image_t *image;
image = pixman_image_create_bits(spice_surface_format_to_pixman (format),
width, height, (uint32_t *)data, stride);
image = pixman_image_create_bits(spice_surface_format_to_pixman(format),
width, height,
SPICE_ALIGNED_CAST(uint32_t *,data),
stride);
return canvas_create_common(image, format
return canvas_create_common(image, format,
bits_cache,
#ifdef SW_CANVAS_CACHE
, bits_cache
, palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, bits_cache
palette_cache,
#endif
, surfaces
, glz_decoder
, jpeg_decoder
, zlib_decoder
);
surfaces,
glz_decoder,
jpeg_decoder,
zlib_decoder);
}
void sw_canvas_init(void) //unsafe global function
SPICE_CONSTRUCTOR_FUNC(sw_canvas_global_init) //unsafe global function
{
if (!need_init) {
return;
}
need_init = 0;
canvas_base_init_ops(&sw_canvas_ops);
sw_canvas_ops.draw_text = canvas_draw_text;
sw_canvas_ops.put_image = canvas_put_image;
@ -1323,5 +1283,4 @@ void sw_canvas_init(void) //unsafe global function
sw_canvas_ops.colorkey_scale_image_from_surface = colorkey_scale_image_from_surface;
sw_canvas_ops.copy_region = copy_region;
sw_canvas_ops.get_image = get_image;
rop3_init();
}

View File

@ -16,43 +16,23 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H__CANVAS
#define _H__CANVAS
#ifndef SPICE_CANVAS_INTERNAL
#error "This header shouldn't be included directly"
#endif
#ifndef H_SPICE_COMMON_SW_CANVAS
#define H_SPICE_COMMON_SW_CANVAS
#include <stdint.h>
#include <spice/macros.h>
#include "draw.h"
#include "pixman_utils.h"
#include "canvas_base.h"
#include "region.h"
#ifdef __cplusplus
extern "C" {
#endif
SpiceCanvas *canvas_create(int width, int height, uint32_t format
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
, SpiceJpegDecoder *jpeg_decoder
, SpiceZlibDecoder *zlib_decoder
);
SPICE_BEGIN_DECLS
SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint8_t *data, int stride
, SpiceImageCache *bits_cache
#ifdef SW_CANVAS_CACHE
, SpiceImageCache *bits_cache
, SpicePaletteCache *palette_cache
#elif defined(SW_CANVAS_IMAGE_CACHE)
, SpiceImageCache *bits_cache
#endif
, SpiceImageSurfaces *surfaces
, SpiceGlzDecoder *glz_decoder
@ -61,10 +41,6 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint
);
void sw_canvas_init(void);
#ifdef __cplusplus
}
#endif
SPICE_END_DECLS
#endif

78
common/udev.c Normal file
View File

@ -0,0 +1,78 @@
/*
Copyright (C) 2023 Intel Corporation.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "udev.h"
#ifdef HAVE_UDEV
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
GpuVendor spice_udev_detect_gpu(int gpu_vendor)
{
struct udev *udev;
struct udev_device *drm_dev, *pci_dev;
struct udev_enumerate *udev_enum;
struct udev_list_entry *entry, *devices;
const char *path, *vendor_id;
GpuVendor vendor = VENDOR_GPU_NOTDETECTED;
udev = udev_new();
if (!udev) {
return VENDOR_GPU_UNKNOWN;
}
udev_enum = udev_enumerate_new(udev);
if (udev_enum) {
udev_enumerate_add_match_subsystem(udev_enum, "drm");
udev_enumerate_add_match_sysname(udev_enum, "card[0-9]");
udev_enumerate_scan_devices(udev_enum);
devices = udev_enumerate_get_list_entry(udev_enum);
udev_list_entry_foreach(entry, devices) {
path = udev_list_entry_get_name(entry);
drm_dev = udev_device_new_from_syspath(udev, path);
if (!drm_dev) {
continue;
}
pci_dev = udev_device_get_parent_with_subsystem_devtype(drm_dev,
"pci", NULL);
if (pci_dev) {
vendor_id = udev_device_get_sysattr_value(pci_dev, "vendor");
if (vendor_id && strtol(vendor_id, NULL, 16) == gpu_vendor) {
vendor = VENDOR_GPU_DETECTED;
udev_device_unref(drm_dev);
break;
}
}
udev_device_unref(drm_dev);
}
udev_enumerate_unref(udev_enum);
}
udev_unref(udev);
return vendor;
}
#else
GpuVendor spice_udev_detect_gpu(int gpu_vendor)
{
return VENDOR_GPU_UNKNOWN;
}
#endif

33
common/udev.h Normal file
View File

@ -0,0 +1,33 @@
/*
Copyright (C) 2023 Intel Corporation.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <spice/macros.h>
#define INTEL_VENDOR_ID 0x8086
typedef enum {
VENDOR_GPU_UNKNOWN,
VENDOR_GPU_DETECTED,
VENDOR_GPU_NOTDETECTED,
} GpuVendor;
SPICE_BEGIN_DECLS
GpuVendor spice_udev_detect_gpu(int gpu_vendor);
SPICE_END_DECLS

66
common/utils.c Normal file
View File

@ -0,0 +1,66 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010, 2011, 2018 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "utils.h"
/* These 2 functions come from
* libvirt-glib/libvirt-gconfig/libvirt-gconfig-helpers.c
* Copyright (C) 2010, 2011 Red Hat, Inc.
* LGPLv2.1+ licensed */
const char *
spice_genum_get_nick(GType enum_type, gint value)
{
GEnumClass *enum_class;
GEnumValue *enum_value;
g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), NULL);
enum_class = g_type_class_ref(enum_type);
enum_value = g_enum_get_value(enum_class, value);
g_type_class_unref(enum_class);
if (enum_value != NULL) {
return enum_value->value_nick;
}
g_return_val_if_reached(NULL);
}
int
spice_genum_get_value(GType enum_type, const char *nick,
gint default_value)
{
GEnumClass *enum_class;
GEnumValue *enum_value;
g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), default_value);
g_return_val_if_fail(nick != NULL, default_value);
enum_class = g_type_class_ref(enum_type);
enum_value = g_enum_get_value_by_nick(enum_class, nick);
g_type_class_unref(enum_class);
if (enum_value != NULL) {
return enum_value->value;
}
g_return_val_if_reached(default_value);
}

57
common/utils.h Normal file
View File

@ -0,0 +1,57 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010, 2011, 2018 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef H_SPICE_COMMON_UTILS
#define H_SPICE_COMMON_UTILS
#include <glib.h>
#include <glib-object.h>
#include <stdint.h>
G_BEGIN_DECLS
const char *spice_genum_get_nick(GType enum_type, gint value);
int spice_genum_get_value(GType enum_type, const char *nick,
gint default_value);
#define BIT_BYTE(nr) ((nr) / 8)
#define BIT_MASK(nr) (1 << ((nr) % 8))
/**
* set_bitmap - Set a bit in memory
* @nr: the bit to set
* @addr: the address to start counting from
*/
static inline void set_bitmap(uint32_t nr, uint8_t *addr)
{
addr[BIT_BYTE(nr)] |= BIT_MASK(nr);
}
/**
* test_bitmap - Determine whether a bit is set
* @nr: bit number to test
* @addr: Address to start counting from
*/
static inline int test_bitmap(uint32_t nr, const uint8_t *addr)
{
return 1 & (addr[BIT_BYTE(nr)] >> (nr % 8));
}
G_END_DECLS
#endif //H_SPICE_COMMON_UTILS

283
common/verify.h Normal file
View File

@ -0,0 +1,283 @@
/* Compile-time assert-like macros.
Copyright (C) 2005-2006, 2009-2019 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
#ifndef _GL_VERIFY_H
#define _GL_VERIFY_H
/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert works as per C11.
This is supported by GCC 4.6.0 and later, in C mode, and its use
here generates easier-to-read diagnostics when verify (R) fails.
Define _GL_HAVE_STATIC_ASSERT to 1 if static_assert works as per C++11.
This is supported by GCC 6.1.0 and later, in C++ mode.
Use this only with GCC. If we were willing to slow 'configure'
down we could also use it with other compilers, but since this
affects only the quality of diagnostics, why bother? */
#if (4 < __GNUC__ + (6 <= __GNUC_MINOR__) \
&& (201112L <= __STDC_VERSION__ || !defined __STRICT_ANSI__) \
&& !defined __cplusplus)
# define _GL_HAVE__STATIC_ASSERT 1
#endif
#if (6 <= __GNUC__) && defined __cplusplus
# define _GL_HAVE_STATIC_ASSERT 1
#endif
/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
system headers, defines a conflicting _Static_assert that is no
better than ours; override it. */
#ifndef _GL_HAVE_STATIC_ASSERT
# include <stddef.h>
# undef _Static_assert
#endif
/* Each of these macros verifies that its argument R is nonzero. To
be portable, R should be an integer constant expression. Unlike
assert (R), there is no run-time overhead.
If _Static_assert works, verify (R) uses it directly. Similarly,
_GL_VERIFY_TRUE works by packaging a _Static_assert inside a struct
that is an operand of sizeof.
The code below uses several ideas for C++ compilers, and for C
compilers that do not support _Static_assert:
* The first step is ((R) ? 1 : -1). Given an expression R, of
integral or boolean or floating-point type, this yields an
expression of integral type, whose value is later verified to be
constant and nonnegative.
* Next this expression W is wrapped in a type
struct _gl_verify_type {
unsigned int _gl_verify_error_if_negative: W;
}.
If W is negative, this yields a compile-time error. No compiler can
deal with a bit-field of negative size.
One might think that an array size check would have the same
effect, that is, that the type struct { unsigned int dummy[W]; }
would work as well. However, inside a function, some compilers
(such as C++ compilers and GNU C) allow local parameters and
variables inside array size expressions. With these compilers,
an array size check would not properly diagnose this misuse of
the verify macro:
void function (int n) { verify (n < 0); }
* For the verify macro, the struct _gl_verify_type will need to
somehow be embedded into a declaration. To be portable, this
declaration must declare an object, a constant, a function, or a
typedef name. If the declared entity uses the type directly,
such as in
struct dummy {...};
typedef struct {...} dummy;
extern struct {...} *dummy;
extern void dummy (struct {...} *);
extern struct {...} *dummy (void);
two uses of the verify macro would yield colliding declarations
if the entity names are not disambiguated. A workaround is to
attach the current line number to the entity name:
#define _GL_CONCAT0(x, y) x##y
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
extern struct {...} * _GL_CONCAT (dummy, __LINE__);
But this has the problem that two invocations of verify from
within the same macro would collide, since the __LINE__ value
would be the same for both invocations. (The GCC __COUNTER__
macro solves this problem, but is not portable.)
A solution is to use the sizeof operator. It yields a number,
getting rid of the identity of the type. Declarations like
extern int dummy [sizeof (struct {...})];
extern void dummy (int [sizeof (struct {...})]);
extern int (*dummy (void)) [sizeof (struct {...})];
can be repeated.
* Should the implementation use a named struct or an unnamed struct?
Which of the following alternatives can be used?
extern int dummy [sizeof (struct {...})];
extern int dummy [sizeof (struct _gl_verify_type {...})];
extern void dummy (int [sizeof (struct {...})]);
extern void dummy (int [sizeof (struct _gl_verify_type {...})]);
extern int (*dummy (void)) [sizeof (struct {...})];
extern int (*dummy (void)) [sizeof (struct _gl_verify_type {...})];
In the second and sixth case, the struct type is exported to the
outer scope; two such declarations therefore collide. GCC warns
about the first, third, and fourth cases. So the only remaining
possibility is the fifth case:
extern int (*dummy (void)) [sizeof (struct {...})];
* GCC warns about duplicate declarations of the dummy function if
-Wredundant-decls is used. GCC 4.3 and later have a builtin
__COUNTER__ macro that can let us generate unique identifiers for
each dummy function, to suppress this warning.
* This implementation exploits the fact that older versions of GCC,
which do not support _Static_assert, also do not warn about the
last declaration mentioned above.
* GCC warns if -Wnested-externs is enabled and verify() is used
within a function body; but inside a function, you can always
arrange to use verify_expr() instead.
* In C++, any struct definition inside sizeof is invalid.
Use a template type to work around the problem. */
/* Concatenate two preprocessor tokens. */
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
#define _GL_CONCAT0(x, y) x##y
/* _GL_COUNTER is an integer, preferably one that changes each time we
use it. Use __COUNTER__ if it works, falling back on __LINE__
otherwise. __LINE__ isn't perfect, but it's better than a
constant. */
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
# define _GL_COUNTER __COUNTER__
#else
# define _GL_COUNTER __LINE__
#endif
/* Generate a symbol with the given prefix, making it unique if
possible. */
#define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
/* Verify requirement R at compile-time, as an integer constant expression
that returns 1. If R is false, fail at compile-time, preferably
with a diagnostic that includes the string-literal DIAGNOSTIC. */
#define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \
(!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC)))
#ifdef __cplusplus
# if !GNULIB_defined_struct__gl_verify_type
template <int w>
struct _gl_verify_type {
unsigned int _gl_verify_error_if_negative: w;
};
# define GNULIB_defined_struct__gl_verify_type 1
# endif
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
_gl_verify_type<(R) ? 1 : -1>
#elif defined _GL_HAVE__STATIC_ASSERT
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
struct { \
_Static_assert (R, DIAGNOSTIC); \
int _gl_dummy; \
}
#else
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; }
#endif
/* Verify requirement R at compile-time, as a declaration without a
trailing ';'. If R is false, fail at compile-time, preferably
with a diagnostic that includes the string-literal DIAGNOSTIC.
Unfortunately, unlike C11, this implementation must appear as an
ordinary declaration, and cannot appear inside struct { ... }. */
#ifdef _GL_HAVE__STATIC_ASSERT
# define _GL_VERIFY _Static_assert
#else
# define _GL_VERIFY(R, DIAGNOSTIC) \
extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
[_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
#endif
/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */
#ifdef _GL_STATIC_ASSERT_H
# if !defined _GL_HAVE__STATIC_ASSERT && !defined _Static_assert
# define _Static_assert(R, DIAGNOSTIC) _GL_VERIFY (R, DIAGNOSTIC)
# endif
# if !defined _GL_HAVE_STATIC_ASSERT && !defined static_assert
# define static_assert _Static_assert /* C11 requires this #define. */
# endif
#endif
/* @assert.h omit start@ */
/* Each of these macros verifies that its argument R is nonzero. To
be portable, R should be an integer constant expression. Unlike
assert (R), there is no run-time overhead.
There are two macros, since no single macro can be used in all
contexts in C. verify_true (R) is for scalar contexts, including
integer constant expression contexts. verify (R) is for declaration
contexts, e.g., the top level. */
/* Verify requirement R at compile-time, as an integer constant expression.
Return 1. This is equivalent to verify_expr (R, 1).
verify_true is obsolescent; please use verify_expr instead. */
#define verify_true(R) _GL_VERIFY_TRUE (R, "verify_true (" #R ")")
/* Verify requirement R at compile-time. Return the value of the
expression E. */
#define verify_expr(R, E) \
(_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E))
/* Verify requirement R at compile-time, as a declaration without a
trailing ';'. */
#ifdef __GNUC__
# define verify(R) _GL_VERIFY (R, "verify (" #R ")")
#else
/* PGI barfs if R is long. Play it safe. */
# define verify(R) _GL_VERIFY (R, "verify (...)")
#endif
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
/* Assume that R always holds. This lets the compiler optimize
accordingly. R should not have side-effects; it may or may not be
evaluated. Behavior is undefined if R is false. */
#if (__has_builtin (__builtin_unreachable) \
|| 4 < __GNUC__ + (5 <= __GNUC_MINOR__))
# define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
#elif 1200 <= _MSC_VER
# define assume(R) __assume (R)
#elif ((defined GCC_LINT || defined lint) \
&& (__has_builtin (__builtin_trap) \
|| 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))))
/* Doing it this way helps various packages when configured with
--enable-gcc-warnings, which compiles with -Dlint. It's nicer
when 'assume' silences warnings even with older GCCs. */
# define assume(R) ((R) ? (void) 0 : __builtin_trap ())
#else
/* Some tools grok NOTREACHED, e.g., Oracle Studio 12.6. */
# define assume(R) ((R) ? (void) 0 : /*NOTREACHED*/ (void) 0)
#endif
/* @assert.h omit end@ */
#endif

View File

@ -1 +0,0 @@
SUBDIRS = my_getopt-1.5

View File

@ -1,22 +0,0 @@
2006-12-09 Benjamin C. W. Sittler <bsittler@>
* my_getopt.c: add my_getopt_reset to reset the argument parser
* README: updated email address, updated for version 1.5
2002-07-26 Benjamin C. W. Sittler <bsittler@knownow.com>
* README: updated for version 1.4
* my_getopt.c: now we include <sys/types.h> explicitly for those
systems that narrowly (mis-)interpret ANSI C and POSIX
(_my_getopt_internal): added an explicit cast to size_t to make
g++ happy
* getopt.h, my_getopt.h: added extern "C" { ... } for C++
compilation (thanks to Jeff Lawson <bovine@ud.com> and others)
2001-08-20 Benjamin C. W. Sittler <bsittler@knownow.com>
* getopt.h (getopt_long_only): fixed typo (thanks to Justin Lee
<justin_lee@ud.com>)

View File

@ -1,22 +0,0 @@
my_getopt - a command-line argument parser
Copyright 1997-2001, Benjamin Sittler
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,14 +0,0 @@
NULL =
EXTRA_DIST = \
ChangeLog \
getopt.3 \
getopt.h \
getopt.txt \
LICENSE \
main.c \
Makefile \
my_getopt.c \
my_getopt.h \
README \
$(NULL)

View File

@ -1,26 +0,0 @@
all: copy
# Compiler options
#CCOPTS = -g -O3 -Wall -Werror
CCOPTS =
# Compiler
CC = gcc -Wall -Werror
#CC = cc
# Linker
LD = $(CC)
# Utility to remove a file
RM = rm
OBJS = main.o my_getopt.o
copy: $(OBJS)
$(LD) -o $@ $(OBJS)
clean:
$(RM) -f copy $(OBJS) *~
%.o: %.c getopt.h my_getopt.h
$(CC) $(CCOPTS) -o $@ -c $<

View File

@ -1,140 +0,0 @@
my_getopt - a command-line argument parser
Copyright 1997-2006, Benjamin Sittler
The author can be reached by sending email to <bsittler@gmail.com>.
The version of my_getopt in this package (1.5) has a BSD-like license;
see the file LICENSE for details. Version 1.0 of my_getopt was similar
to the GPL'ed version of my_getopt included with SMOKE-16 Version 1,
Release 19990717. SMOKE-16 packages are available from:
http://geocities.com/bsittler/#smoke16
OVERVIEW OF THE ARGUMENT PARSER
===============================
The getopt(), getopt_long() and getopt_long_only() functions parse
command line arguments. The argc and argv parameters passed to these
functions correspond to the argument count and argument list passed to
your program's main() function at program start-up. Element 0 of the
argument list conventionally contains the name of your program. Any
remaining arguments starting with "-" (except for "-" or "--" by
themselves) are option arguments, some of include option values. This
family of getopt() functions allows intermixed option and non-option
arguments anywhere in the argument list, except that "--" by itself
causes the remaining elements of the argument list to be treated as
non-option arguments.
[ See the parts of this document labeled "DOCUMENTATION" and
"WHY RE-INVENT THE WHEEL?" for a more information. ]
FILES
=====
The following four files constitute the my_getopt package:
LICENSE - license and warranty information for my_getopt
my_getopt.c - implementation of my getopt replacement
my_getopt.h - interface for my getopt replacement
getopt.h - a header file to make my getopt look like GNU getopt
USAGE
=====
To use my_getopt in your application, include the following line to
your main program source:
#include "getopt.h"
This line should appear after your standard system header files to
avoid conflicting with your system's built-in getopt.
Then compile my_getopt.c into my_getopt.o, and link my_getopt.o into
your application:
$ cc -c my_getopt.c
$ ld -o app app.o ... my_getopt.o
To avoid conflicting with standard library functions, the function
names and global variables used by my_getopt all begin with `my_'. To
ensure compatibility with existing C programs, the `getopt.h' header
file uses the C preprocessor to redefine names like getopt, optarg,
optind, and so forth to my_getopt, my_optarg, my_optind, etc.
SAMPLE PROGRAM
==============
There is also a public-domain sample program:
main.c - main() for a sample program using my_getopt
Makefile - build script for the sample program (called `copy')
To build and test the sample program:
$ make
$ ./copy -help
$ ./copy -version
The sample program bears a slight resemblance to the UNIX `cat'
utility, but can be used rot13-encode streams, and can redirect output
to a file.
DOCUMENTATION
=============
There is not yet any real documentation for my_getopt. For the moment,
use the Linux manual page for getopt. It has its own copyright and
license; view the file `getopt.3' in a text editor for more details.
getopt.3 - the manual page for GNU getopt
getopt.txt - preformatted copy of the manual page for GNU getopt,
for your convenience
WHY RE-INVENT THE WHEEL?
========================
I re-implemented getopt, getopt_long, and getopt_long_only because
there were noticable bugs in several versions of the GNU
implementations, and because the GNU versions aren't always available
on some systems (*BSD, for example.) Other systems don't include any
sort of standard argument parser (Win32 with Microsoft tools, for
example, has no getopt.)
These should do all the expected Unix- and GNU-style argument
parsing, including permution, bunching, long options with single or
double dashes (double dashes are required if you use
my_getopt_long,) and optional arguments for both long and short
options. A word with double dashes all by themselves halts argument
parsing. A required long option argument can be in the same word as
the option name, separated by '=', or in the next word. An optional
long option argument must be in the same word as the option name,
separated by '='.
As with the GNU versions, a '+' prefix to the short option
specification (or the POSIXLY_CORRECT environment variable) disables
permution, a '-' prefix to the short option specification returns 1
for non-options, ':' after a short option indicates a required
argument, and '::' after a short option specification indicates an
optional argument (which must appear in the same word.) If you'd like
to recieve ':' instead of '?' for missing option arguments, prefix the
short option specification with ':'.
The original intent was to re-implement the documented behavior of
the GNU versions, but I have found it necessary to emulate some of
the undocumented behavior as well. Some programs depend on it.
KNOWN BUGS
==========
The GNU versions support POSIX-style -W "name=value" long
options. Currently, my_getopt does not support these, because I
don't have any documentation on them (other than the fact that they
are enabled by "W;" in the short option specification.) As a
temporary workaround, my_getopt treats "W;" in the short option
string identically to "W:".
The GNU versions support internationalized/localized
messages. Currently, my_getopt does not.
There should be re-entrant versions of all these functions so that
multiple threads can parse arguments simultaneously.

View File

@ -1,288 +0,0 @@
.\" (c) 1993 by Thomas Koenig (ig25@rz.uni-karlsruhe.de)
.\"
.\" Permission is granted to make and distribute verbatim copies of this
.\" manual provided the copyright notice and this permission notice are
.\" preserved on all copies.
.\"
.\" Permission is granted to copy and distribute modified versions of this
.\" manual under the conditions for verbatim copying, provided that the
.\" entire resulting derived work is distributed under the terms of a
.\" permission notice identical to this one
.\"
.\" Since the Linux kernel and libraries are constantly changing, this
.\" manual page may be incorrect or out-of-date. The author(s) assume no
.\" responsibility for errors or omissions, or for damages resulting from
.\" the use of the information contained herein. The author(s) may not
.\" have taken the same level of care in the production of this manual,
.\" which is licensed free of charge, as they might when working
.\" professionally.
.\"
.\" Formatted or processed versions of this manual, if unaccompanied by
.\" the source, must acknowledge the copyright and authors of this work.
.\" License.
.\" Modified Sat Jul 24 19:27:50 1993 by Rik Faith (faith@cs.unc.edu)
.\" Modified Mon Aug 30 22:02:34 1995 by Jim Van Zandt <jrv@vanzandt.mv.com>
.\" longindex is a pointer, has_arg can take 3 values, using consistent
.\" names for optstring and longindex, "\n" in formats fixed. Documenting
.\" opterr and getopt_long_only. Clarified explanations (borrowing heavily
.\" from the source code).
.TH GETOPT 3 "Aug 30, 1995" "GNU" "Linux Programmer's Manual"
.SH NAME
getopt \- Parse command line options
.SH SYNOPSIS
.nf
.B #include <unistd.h>
.sp
.BI "int getopt(int " argc ", char * const " argv[] ","
.BI " const char *" optstring ");"
.sp
.BI "extern char *" optarg ;
.BI "extern int " optind ", " opterr ", " optopt ;
.sp
.B #include <getopt.h>
.sp
.BI "int getopt_long(int " argc ", char * const " argv[] ",
.BI " const char *" optstring ,
.BI " const struct option *" longopts ", int *" longindex ");"
.sp
.BI "int getopt_long_only(int " argc ", char * const " argv[] ",
.BI " const char *" optstring ,
.BI " const struct option *" longopts ", int *" longindex ");"
.fi
.SH DESCRIPTION
The
.B getopt()
function parses the command line arguments. Its arguments
.I argc
and
.I argv
are the argument count and array as passed to the
.B main()
function on program invocation.
An element of \fIargv\fP that starts with `-' (and is not exactly "-" or "--")
is an option element. The characters of this element
(aside from the initial `-') are option characters. If \fBgetopt()\fP
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
.PP
If \fBgetopt()\fP finds another option character, it returns that
character, updating the external variable \fIoptind\fP and a static
variable \fInextchar\fP so that the next call to \fBgetopt()\fP can
resume the scan with the following option character or
\fIargv\fP-element.
.PP
If there are no more option characters, \fBgetopt()\fP returns
\fBEOF\fP. Then \fIoptind\fP is the index in \fIargv\fP of the first
\fIargv\fP-element that is not an option.
.PP
.I optstring
is a string containing the legitimate option characters. If such a
character is followed by a colon, the option requires an argument, so
\fBgetopt\fP places a pointer to the following text in the same
\fIargv\fP-element, or the text of the following \fIargv\fP-element, in
.IR optarg .
Two colons mean an option takes
an optional arg; if there is text in the current \fIargv\fP-element,
it is returned in \fIoptarg\fP, otherwise \fIoptarg\fP is set to zero.
.PP
By default, \fBgetargs()\fP permutes the contents of \fIargv\fP as it
scans, so that eventually all the non-options are at the end. Two
other modes are also implemented. If the first character of
\fIoptstring\fP is `+' or the environment variable POSIXLY_CORRECT is
set, then option processing stops as soon as a non-option argument is
encountered. If the first character of \fIoptstring\fP is `-', then
each non-option \fIargv\fP-element is handled as if it were the argument of
an option with character code 1. (This is used by programs that were
written to expect options and other \fIargv\fP-elements in any order
and that care about the ordering of the two.)
The special argument `--' forces an end of option-scanning regardless
of the scanning mode.
.PP
If \fBgetopt()\fP does not recognize an option character, it prints an
error message to stderr, stores the character in \fIoptopt\fP, and
returns `?'. The calling program may prevent the error message by
setting \fIopterr\fP to 0.
.PP
The
.B getopt_long()
function works like
.B getopt()
except that it also accepts long options, started out by two dashes.
Long option names may be abbreviated if the abbreviation is
unique or is an exact match for some defined option. A long option
may take a parameter, of the form
.B --arg=param
or
.BR "--arg param" .
.PP
.I longopts
is a pointer to the first element of an array of
.B struct option
declared in
.B <getopt.h>
as
.nf
.sp
.in 10
struct option {
.in 14
const char *name;
int has_arg;
int *flag;
int val;
.in 10
};
.fi
.PP
The meanings of the different fields are:
.TP
.I name
is the name of the long option.
.TP
.I has_arg
is:
\fBno_argument\fP (or 0) if the option does not take an argument,
\fBrequired_argument\fP (or 1) if the option requires an argument, or
\fBoptional_argument\fP (or 2) if the option takes an optional argument.
.TP
.I flag
specifies how results are returned for a long option. If \fIflag\fP
is \fBNULL\fP, then \fBgetopt_long()\fP returns \fIval\fP. (For
example, the calling program may set \fIval\fP to the equivalent short
option character.) Otherwise, \fBgetopt_long()\fP returns 0, and
\fIflag\fP points to a variable which is set to \fIval\fP if the
option is found, but left unchanged if the option is not found.
.TP
\fIval\fP
is the value to return, or to load into the variable pointed
to by \fIflag\fP.
.PP
The last element of the array has to be filled with zeroes.
.PP
If \fIlongindex\fP is not \fBNULL\fP, it
points to a variable which is set to the index of the long option relative to
.IR longopts .
.PP
\fBgetopt_long_only()\fP is like \fBgetopt_long()\fP, but `-' as well
as `--' can indicate a long option. If an option that starts with `-'
(not `--') doesn't match a long option, but does match a short option,
it is parsed as a short option instead.
.SH "RETURN VALUE"
The
.B getopt()
function returns the option character if the option was found
successfully, `:' if there was a missing parameter for one of the
options, `?' for an unknown option character, or \fBEOF\fP
for the end of the option list.
.PP
\fBgetopt_long()\fP and \fBgetopt_long_only()\fP also return the option
character when a short option is recognized. For a long option, they
return \fIval\fP if \fIflag\fP is \fBNULL\fP, and 0 otherwise. Error
and EOF returns are the same as for \fBgetopt()\fP, plus `?' for an
ambiguous match or an extraneous parameter.
.SH "ENVIRONMENT VARIABLES"
.TP
.SM
.B POSIXLY_CORRECT
If this is set, then option processing stops as soon as a non-option
argument is encountered.
.SH "EXAMPLE"
The following example program, from the source code, illustrates the
use of
.BR getopt_long()
with most of its features.
.nf
.sp
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 1, 0, 'c'},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\\n");
break;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\\n");
digit_optind = this_option_optind;
printf ("option %c\\n", c);
break;
case 'a':
printf ("option a\\n");
break;
case 'b':
printf ("option b\\n");
break;
case 'c':
printf ("option c with value `%s'\\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\\n");
}
exit (0);
}
.fi
.SH "BUGS"
This manpage is confusing.
.SH "CONFORMING TO"
.TP
\fBgetopt()\fP:
POSIX.1, provided the environment variable POSIXLY_CORRECT is set.
Otherwise, the elements of \fIargv\fP aren't really const, because we
permute them. We pretend they're const in the prototype to be
compatible with other systems.

View File

@ -1,56 +0,0 @@
/*
* getopt.h - cpp wrapper for my_getopt to make it look like getopt.
* Copyright 1997, 2000, 2001, 2002, Benjamin Sittler
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef MY_WRAPPER_GETOPT_H_INCLUDED
#define MY_WRAPPER_GETOPT_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include "my_getopt.h"
#undef getopt
#define getopt my_getopt
#undef getopt_long
#define getopt_long my_getopt_long
#undef getopt_long_only
#define getopt_long_only my_getopt_long_only
#undef _getopt_internal
#define _getopt_internal _my_getopt_internal
#undef opterr
#define opterr my_opterr
#undef optind
#define optind my_optind
#undef optopt
#define optopt my_optopt
#undef optarg
#define optarg my_optarg
#ifdef __cplusplus
}
#endif
#endif /* MY_WRAPPER_GETOPT_H_INCLUDED */

View File

@ -1,330 +0,0 @@
GETOPT(3) Linux Programmer's Manual GETOPT(3)
NAME
getopt - Parse command line options
SYNOPSIS
#include <unistd.h>
int getopt(int argc, char * const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#include <getopt.h>
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
int getopt_long_only(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
DESCRIPTION
The getopt() function parses the command line arguments.
Its arguments argc and argv are the argument count and
array as passed to the main() function on program invoca-
tion. An element of argv that starts with `-' (and is not
exactly "-" or "--") is an option element. The characters
of this element (aside from the initial `-') are option
characters. If getopt() is called repeatedly, it returns
successively each of the option characters from each of
the option elements.
If getopt() finds another option character, it returns
that character, updating the external variable optind and
a static variable nextchar so that the next call to
getopt() can resume the scan with the following option
character or argv-element.
If there are no more option characters, getopt() returns
EOF. Then optind is the index in argv of the first argv-
element that is not an option.
optstring is a string containing the legitimate option
characters. If such a character is followed by a colon,
the option requires an argument, so getopt places a
pointer to the following text in the same argv-element, or
the text of the following argv-element, in optarg. Two
colons mean an option takes an optional arg; if there is
text in the current argv-element, it is returned in
optarg, otherwise optarg is set to zero.
By default, getargs() permutes the contents of argv as it
scans, so that eventually all the non-options are at the
GNU Aug 30, 1995 1
GETOPT(3) Linux Programmer's Manual GETOPT(3)
end. Two other modes are also implemented. If the first
character of optstring is `+' or the environment variable
POSIXLY_CORRECT is set, then option processing stops as
soon as a non-option argument is encountered. If the
first character of optstring is `-', then each non-option
argv-element is handled as if it were the argument of an
option with character code 1. (This is used by programs
that were written to expect options and other argv-ele-
ments in any order and that care about the ordering of the
two.) The special argument `--' forces an end of option-
scanning regardless of the scanning mode.
If getopt() does not recognize an option character, it
prints an error message to stderr, stores the character in
optopt, and returns `?'. The calling program may prevent
the error message by setting opterr to 0.
The getopt_long() function works like getopt() except that
it also accepts long options, started out by two dashes.
Long option names may be abbreviated if the abbreviation
is unique or is an exact match for some defined option. A
long option may take a parameter, of the form --arg=param
or --arg param.
longopts is a pointer to the first element of an array of
struct option declared in <getopt.h> as
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
The meanings of the different fields are:
name is the name of the long option.
has_arg
is: no_argument (or 0) if the option does not take
an argument, required_argument (or 1) if the option
requires an argument, or optional_argument (or 2)
if the option takes an optional argument.
flag specifies how results are returned for a long
option. If flag is NULL, then getopt_long()
returns val. (For example, the calling program may
set val to the equivalent short option character.)
Otherwise, getopt_long() returns 0, and flag points
to a variable which is set to val if the option is
found, but left unchanged if the option is not
found.
val is the value to return, or to load into the
GNU Aug 30, 1995 2
GETOPT(3) Linux Programmer's Manual GETOPT(3)
variable pointed to by flag.
The last element of the array has to be filled with
zeroes.
If longindex is not NULL, it points to a variable which is
set to the index of the long option relative to longopts.
getopt_long_only() is like getopt_long(), but `-' as well
as `--' can indicate a long option. If an option that
starts with `-' (not `--') doesn't match a long option,
but does match a short option, it is parsed as a short
option instead.
RETURN VALUE
The getopt() function returns the option character if the
option was found successfully, `:' if there was a missing
parameter for one of the options, `?' for an unknown
option character, or EOF for the end of the option list.
getopt_long() and getopt_long_only() also return the
option character when a short option is recognized. For a
long option, they return val if flag is NULL, and 0 other-
wise. Error and EOF returns are the same as for getopt(),
plus `?' for an ambiguous match or an extraneous parame-
ter.
ENVIRONMENT VARIABLES
POSIXLY_CORRECT
If this is set, then option processing stops as
soon as a non-option argument is encountered.
EXAMPLE
The following example program, from the source code,
illustrates the use of getopt_long() with most of its fea-
tures.
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
GNU Aug 30, 1995 3
GETOPT(3) Linux Programmer's Manual GETOPT(3)
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 1, 0, 'c'},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
GNU Aug 30, 1995 4
GETOPT(3) Linux Programmer's Manual GETOPT(3)
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
BUGS
This manpage is confusing.
CONFORMING TO
getopt():
POSIX.1, provided the environment variable
POSIXLY_CORRECT is set. Otherwise, the elements of
argv aren't really const, because we permute them.
We pretend they're const in the prototype to be
compatible with other systems.
GNU Aug 30, 1995 5

View File

@ -1,387 +0,0 @@
/*
* copy - test program for my getopt() re-implementation
*
* This program is in the public domain.
*/
#define VERSION \
"0.3"
#define COPYRIGHT \
"This program is in the public domain."
/* for isprint(), printf(), fopen(), perror(), getenv(), strcmp(), etc. */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* for my getopt() re-implementation */
#include "getopt.h"
/* the default verbosity level is 0 (no verbose reporting) */
static unsigned verbose = 0;
/* print version and copyright information */
static void
version(char *progname)
{
printf("%s version %s\n"
"%s\n",
progname,
VERSION,
COPYRIGHT);
}
/* print a help summary */
static void
help(char *progname)
{
printf("Usage: %s [options] [FILE]...\n"
"Options:\n"
"-h or -help show this message and exit\n"
"-append append to the output file\n"
"-o FILE or\n"
"-output FILE send output to FILE (default is stdout)\n"
"-r or --rotate rotate letters 13 positions (rot13)\n"
"-rNUM or\n"
"--rotate=NUM rotate letters NUM positions\n"
"-truncate truncate the output file "
"(this is the default)\n"
"-v or -verbose increase the level of verbosity by 1"
"(the default is 0)\n"
"-vNUM or\n"
"-verbose=NUM set the level of verbosity to NUM\n"
"-V or -version print program version and exit\n"
"\n"
"This program reads the specified FILEs "
"(or stdin if none are given)\n"
"and writes their bytes to the specified output FILE "
"(or stdout if none is\n"
"given.) It can optionally rotate letters.\n",
progname);
}
/* print usage information to stderr */
static void
usage(char *progname)
{
fprintf(stderr,
"Summary: %s [-help] [-version] [options] [FILE]...\n",
progname);
}
/* input file handler -- returns nonzero or exit()s on failure */
static int
handle(char *progname,
FILE *infile, char *infilename,
FILE *outfile, char *outfilename,
int rotate)
{
int c;
unsigned long bytes_copied = 0;
if (verbose > 2)
{
fprintf(stderr,
"%s: copying from `%s' to `%s'\n",
progname,
infilename,
outfilename);
}
while ((c = getc(infile)) != EOF)
{
if (rotate && isalpha(c))
{
const char *letters = "abcdefghijklmnopqrstuvwxyz";
char *match;
if ((match = strchr(letters, tolower(c))))
{
char rc = letters[(match - letters + rotate) % 26];
if (isupper(c))
rc = toupper(rc);
c = rc;
}
}
if (putc(c, outfile) == EOF)
{
perror(outfilename);
exit(1);
}
bytes_copied ++;
}
if (! feof(infile))
{
perror(infilename);
return 1;
}
if (verbose > 2)
{
fprintf(stderr,
"%s: %lu bytes copied from `%s' to `%s'\n",
progname,
bytes_copied,
infilename,
outfilename);
}
return 0;
}
/* argument parser and dispatcher */
int
main(int argc, char * argv[])
{
/* the program name */
char *progname = argv[0];
/* during argument parsing, opt contains the return value from getopt() */
int opt;
/* the output filename is initially 0 (a.k.a. stdout) */
char *outfilename = 0;
/* the default return value is initially 0 (success) */
int retval = 0;
/* initially we truncate */
int append = 0;
/* initially we don't rotate letters */
int rotate = 0;
/* short options string */
char *shortopts = "Vho:r::v::";
/* long options list */
struct option longopts[] =
{
/* name, has_arg, flag, val */ /* longind */
{ "append", no_argument, 0, 0 }, /* 0 */
{ "truncate", no_argument, 0, 0 }, /* 1 */
{ "version", no_argument, 0, 'V' }, /* 3 */
{ "help", no_argument, 0, 'h' }, /* 4 */
{ "output", required_argument, 0, 'o' }, /* 5 */
{ "rotate", optional_argument, 0, 'r' }, /* 6 */
{ "verbose", optional_argument, 0, 'v' }, /* 7 */
/* end-of-list marker */
{ 0, 0, 0, 0 }
};
/* long option list index */
int longind = 0;
/*
* print a warning when the POSIXLY_CORRECT environment variable will
* interfere with argument placement
*/
if (getenv("POSIXLY_CORRECT"))
{
fprintf(stderr,
"%s: "
"Warning: implicit argument reordering disallowed by "
"POSIXLY_CORRECT\n",
progname);
}
/* parse all options from the command line */
while ((opt =
getopt_long_only(argc, argv, shortopts, longopts, &longind)) != -1)
switch (opt)
{
case 0: /* a long option without an equivalent short option */
switch (longind)
{
case 0: /* -append */
append = 1;
break;
case 1: /* -truncate */
append = 0;
break;
default: /* something unexpected has happened */
fprintf(stderr,
"%s: "
"getopt_long_only unexpectedly returned %d for `--%s'\n",
progname,
opt,
longopts[longind].name);
return 1;
}
break;
case 'V': /* -version */
version(progname);
return 0;
case 'h': /* -help */
help(progname);
return 0;
case 'r': /* -rotate[=NUM] */
if (optarg)
{
/* we use this while trying to parse a numeric argument */
char ignored;
if (sscanf(optarg,
"%d%c",
&rotate,
&ignored) != 1)
{
fprintf(stderr,
"%s: "
"rotation `%s' is not a number\n",
progname,
optarg);
usage(progname);
return 2;
}
/* normalize rotation */
while (rotate < 0)
{
rotate += 26;
}
rotate %= 26;
}
else
rotate = 13;
break;
case 'o': /* -output=FILE */
outfilename = optarg;
/* we allow "-" as a synonym for stdout here */
if (! strcmp(optarg, "-"))
{
outfilename = 0;
}
break;
case 'v': /* -verbose[=NUM] */
if (optarg)
{
/* we use this while trying to parse a numeric argument */
char ignored;
if (sscanf(optarg,
"%u%c",
&verbose,
&ignored) != 1)
{
fprintf(stderr,
"%s: "
"verbosity level `%s' is not a number\n",
progname,
optarg);
usage(progname);
return 2;
}
}
else
verbose ++;
break;
case '?': /* getopt_long_only noticed an error */
usage(progname);
return 2;
default: /* something unexpected has happened */
fprintf(stderr,
"%s: "
"getopt_long_only returned an unexpected value (%d)\n",
progname,
opt);
return 1;
}
/* re-open stdout to outfilename, if requested */
if (outfilename)
{
if (! freopen(outfilename, (append ? "a" : "w"), stdout))
{
perror(outfilename);
return 1;
}
}
else
{
/* make a human-readable version of the output filename "-" */
outfilename = "stdout";
/* you can't truncate stdout */
append = 1;
}
if (verbose)
{
fprintf(stderr,
"%s: verbosity level is %u; %s `%s'; rotation %d\n",
progname,
verbose,
(append ? "appending to" : "truncating"),
outfilename,
rotate);
}
if (verbose > 1)
{
fprintf(stderr,
"%s: %d input file(s) were given\n",
progname,
((argc > optind) ? (argc - optind) : 0));
}
if (verbose > 3)
{
fprintf(stderr,
"\topterr: %d\n\toptind: %d\n\toptopt: %d (%c)\n\toptarg: %s\n",
opterr,
optind,
optopt, optopt,
optarg ? optarg : "(null)");
}
/* handle each of the input files (or stdin, if no files were given) */
if (optind < argc)
{
int argindex;
for (argindex = optind; argindex < argc; argindex ++)
{
char *infilename = argv[argindex];
FILE *infile;
/* we allow "-" as a synonym for stdin here */
if (! strcmp(infilename, "-"))
{
infile = stdin;
infilename = "stdin";
}
else if (! (infile = fopen(infilename, "r")))
{
perror(infilename);
retval = 1;
continue;
}
if (handle(progname,
infile, argv[optind],
stdout, outfilename,
rotate))
{
retval = 1;
fclose(infile);
continue;
}
if ((infile != stdin) && fclose(infile))
{
perror(infilename);
retval = 1;
}
}
}
else
{
retval =
handle(progname,
stdin, "stdin",
stdout, outfilename,
rotate);
}
/* close stdout */
if (fclose(stdout))
{
perror(outfilename);
return 1;
}
if (verbose > 3)
{
fprintf(stderr,
"%s: normal return, exit code is %d\n",
progname,
retval);
}
return retval;
}

View File

@ -1,281 +0,0 @@
/*
* my_getopt.c - my re-implementation of getopt.
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "my_getopt.h"
int my_optind=1, my_opterr=1, my_optopt=0;
char *my_optarg=0;
/* reset argument parser to start-up values */
int my_getopt_reset(void)
{
my_optind = 1;
my_opterr = 1;
my_optopt = 0;
my_optarg = 0;
return 0;
}
/* this is the plain old UNIX getopt, with GNU-style extensions. */
/* if you're porting some piece of UNIX software, this is all you need. */
/* this supports GNU-style permution and optional arguments */
int my_getopt(int argc, char * argv[], const char *opts)
{
static int charind=0;
char mode, colon_mode;
int off = 0, opt = -1;
if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
else {
if((colon_mode = *opts) == ':') off ++;
if(((mode = opts[off]) == '+') || (mode == '-')) {
off++;
if((colon_mode != ':') && ((colon_mode = opts[off]) == ':'))
off ++;
}
}
my_optarg = 0;
if(charind) {
const char *s;
my_optopt = argv[my_optind][charind];
for(s=opts+off; *s; s++) if(my_optopt == *s) {
charind++;
if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) {
if(argv[my_optind][charind]) {
my_optarg = &(argv[my_optind++][charind]);
charind = 0;
} else if(*(++s) != ':') {
charind = 0;
if(++my_optind >= argc) {
if(my_opterr) fprintf(stderr,
"%s: option requires an argument -- %c\n",
argv[0], my_optopt);
opt = (colon_mode == ':') ? ':' : '?';
goto my_getopt_ok;
}
my_optarg = argv[my_optind++];
}
}
opt = my_optopt;
goto my_getopt_ok;
}
if(my_opterr) fprintf(stderr,
"%s: illegal option -- %c\n",
argv[0], my_optopt);
opt = '?';
if(argv[my_optind][++charind] == '\0') {
my_optind++;
charind = 0;
}
my_getopt_ok:
if(charind && ! argv[my_optind][charind]) {
my_optind++;
charind = 0;
}
} else if((my_optind >= argc) ||
((argv[my_optind][0] == '-') &&
(argv[my_optind][1] == '-') &&
(argv[my_optind][2] == '\0'))) {
my_optind++;
opt = -1;
} else if((argv[my_optind][0] != '-') ||
(argv[my_optind][1] == '\0')) {
char *tmp;
int i, j, k;
if(mode == '+') opt = -1;
else if(mode == '-') {
my_optarg = argv[my_optind++];
charind = 0;
opt = 1;
} else {
for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
(argv[i][1] != '\0')) {
my_optind=i;
opt=my_getopt(argc, argv, opts);
while(i > j) {
tmp=argv[--i];
for(k=i; k+1<my_optind; k++) argv[k]=argv[k+1];
argv[--my_optind]=tmp;
}
break;
}
if(i == argc) opt = -1;
}
} else {
charind++;
opt = my_getopt(argc, argv, opts);
}
if (my_optind > argc) my_optind = argc;
return opt;
}
/* this is the extended getopt_long{,_only}, with some GNU-like
* extensions. Implements _getopt_internal in case any programs
* expecting GNU libc getopt call it.
*/
int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
const struct option *longopts, int *longind,
int long_only)
{
char mode, colon_mode = *shortopts;
int shortoff = 0, opt = -1;
if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
else {
if((colon_mode = *shortopts) == ':') shortoff ++;
if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) {
shortoff++;
if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':'))
shortoff ++;
}
}
my_optarg = 0;
if((my_optind >= argc) ||
((argv[my_optind][0] == '-') &&
(argv[my_optind][1] == '-') &&
(argv[my_optind][2] == '\0'))) {
my_optind++;
opt = -1;
} else if((argv[my_optind][0] != '-') ||
(argv[my_optind][1] == '\0')) {
char *tmp;
int i, j, k;
opt = -1;
if(mode == '+') return -1;
else if(mode == '-') {
my_optarg = argv[my_optind++];
return 1;
}
for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
(argv[i][1] != '\0')) {
my_optind=i;
opt=_my_getopt_internal(argc, argv, shortopts,
longopts, longind,
long_only);
while(i > j) {
tmp=argv[--i];
for(k=i; k+1<my_optind; k++)
argv[k]=argv[k+1];
argv[--my_optind]=tmp;
}
break;
}
} else if((!long_only) && (argv[my_optind][1] != '-'))
opt = my_getopt(argc, argv, shortopts);
else {
int charind, offset;
int found = 0, ind, hits = 0;
if(((my_optopt = argv[my_optind][1]) != '-') && ! argv[my_optind][2]) {
int c;
ind = shortoff;
while((c = shortopts[ind++])) {
if(((shortopts[ind] == ':') ||
((c == 'W') && (shortopts[ind] == ';'))) &&
(shortopts[++ind] == ':'))
ind ++;
if(my_optopt == c) return my_getopt(argc, argv, shortopts);
}
}
offset = 2 - (argv[my_optind][1] != '-');
for(charind = offset;
(argv[my_optind][charind] != '\0') &&
(argv[my_optind][charind] != '=');
charind++);
for(ind = 0; longopts[ind].name && !hits; ind++)
if((strlen(longopts[ind].name) == (size_t) (charind - offset)) &&
(strncmp(longopts[ind].name,
argv[my_optind] + offset, charind - offset) == 0))
found = ind, hits++;
if(!hits) for(ind = 0; longopts[ind].name; ind++)
if(strncmp(longopts[ind].name,
argv[my_optind] + offset, charind - offset) == 0)
found = ind, hits++;
if(hits == 1) {
opt = 0;
if(argv[my_optind][charind] == '=') {
if(longopts[found].has_arg == 0) {
opt = '?';
if(my_opterr) fprintf(stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], longopts[found].name);
} else {
my_optarg = argv[my_optind] + ++charind;
charind = 0;
}
} else if(longopts[found].has_arg == 1) {
if(++my_optind >= argc) {
opt = (colon_mode == ':') ? ':' : '?';
if(my_opterr) fprintf(stderr,
"%s: option `--%s' requires an argument\n",
argv[0], longopts[found].name);
} else my_optarg = argv[my_optind];
}
if(!opt) {
if (longind) *longind = found;
if(!longopts[found].flag) opt = longopts[found].val;
else *(longopts[found].flag) = longopts[found].val;
}
my_optind++;
} else if(!hits) {
if(offset == 1) opt = my_getopt(argc, argv, shortopts);
else {
opt = '?';
if(my_opterr) fprintf(stderr,
"%s: unrecognized option `%s'\n",
argv[0], argv[my_optind++]);
}
} else {
opt = '?';
if(my_opterr) fprintf(stderr,
"%s: option `%s' is ambiguous\n",
argv[0], argv[my_optind++]);
}
}
if (my_optind > argc) my_optind = argc;
return opt;
}
int my_getopt_long(int argc, char * argv[], const char *shortopts,
const struct option *longopts, int *longind)
{
return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0);
}
int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
const struct option *longopts, int *longind)
{
return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1);
}

View File

@ -1,72 +0,0 @@
/*
* my_getopt.h - interface to my re-implementation of getopt.
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef MY_GETOPT_H_INCLUDED
#define MY_GETOPT_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
/* reset argument parser to start-up values */
extern int my_getopt_reset(void);
/* UNIX-style short-argument parser */
extern int my_getopt(int argc, char * argv[], const char *opts);
extern int my_optind, my_opterr, my_optopt;
extern char *my_optarg;
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
/* human-readable values for has_arg */
#undef no_argument
#define no_argument 0
#undef required_argument
#define required_argument 1
#undef optional_argument
#define optional_argument 2
/* GNU-style long-argument parsers */
extern int my_getopt_long(int argc, char * argv[], const char *shortopts,
const struct option *longopts, int *longind);
extern int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
const struct option *longopts, int *longind);
extern int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#ifdef __cplusplus
}
#endif
#endif /* MY_GETOPT_H_INCLUDED */

81
configure.ac Normal file
View File

@ -0,0 +1,81 @@
AC_PREREQ([2.63])
AC_INIT([spice-common],
[noversion],
[spice-devel@lists.freedesktop.org])
AC_CONFIG_SRCDIR([common/log.h])
AC_CONFIG_MACRO_DIR([m4])
AM_CONFIG_HEADER([config.h])
AC_CONFIG_AUX_DIR([build-aux])
# For automake >= 1.12
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
# Checks for programs
AM_INIT_AUTOMAKE([1.11 dist-xz no-dist-gzip tar-ustar foreign subdir-objects -Wall -Werror])
AM_MAINTAINER_MODE
AM_SILENT_RULES([yes])
LT_INIT
SPICE_MANUAL
AC_PROG_CC
AC_PROG_CC_C99
if test "x$ac_cv_prog_cc_c99" = xno; then
AC_MSG_ERROR([C99 compiler is required.])
fi
AM_PROG_CC_C_O
AC_CHECK_HEADERS([sys/mman.h regex.h])
AC_CHECK_FUNCS([sigaction drand48 setlinebuf])
AC_SEARCH_LIBS(regcomp, [regex rx])
SPICE_CHECK_SYSDEPS
SPICE_EXTRA_CHECKS
AC_ARG_ENABLE([tests],
AS_HELP_STRING([--enable-tests],
[Enable tests @<:@default=yes@:>@]),
[],
enable_tests="yes")
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes")
AC_ARG_ENABLE([alignment-checks],
AS_HELP_STRING([--enable-alignment-checks],
[Enable runtime checks for cast alignment @<:@default=no@:>@]),
[],
enable_alignment_checks="no")
AS_IF([test "x$enable_alignment_checks" = "xyes"],
[AC_DEFINE([SPICE_DEBUG_ALIGNMENT], 1, [Enable runtime checks for cast alignment])])
SPICE_CHECK_INSTRUMENTATION
# Checks for libraries
PKG_CHECK_MODULES([PROTOCOL], [spice-protocol >= 0.14.2])
SPICE_CHECK_PYTHON_MODULES()
SPICE_CHECK_PIXMAN
SPICE_CHECK_SMARTCARD
SPICE_CHECK_GLIB2
SPICE_CHECK_OPUS
SPICE_CHECK_OPENSSL
SPICE_CHECK_GDK_PIXBUF
SPICE_CHECK_UDEV
SPICE_COMMON_CFLAGS='$(PIXMAN_CFLAGS) $(SMARTCARD_CFLAGS) $(GLIB2_CFLAGS) $(OPUS_CFLAGS) $(OPENSSL_CFLAGS)'
SPICE_COMMON_CFLAGS="$SPICE_COMMON_CFLAGS -DG_LOG_DOMAIN=\\\"Spice\\\""
SPICE_COMMON_LIBS='$(PIXMAN_LIBS) $(GLIB2_LIBS) $(OPUS_LIBS) $(OPENSSL_LIBS)'
AC_SUBST(SPICE_COMMON_CFLAGS)
AC_SUBST(SPICE_COMMON_LIBS)
# The End!
AC_CONFIG_FILES([
Makefile
common/Makefile
python_modules/Makefile
tests/Makefile
docs/Makefile
])
AC_OUTPUT

27
docs/Makefile.am Normal file
View File

@ -0,0 +1,27 @@
NULL =
CLEANFILES =
ASCIIDOC_FILES = \
spice_protocol.txt \
spice_uri_scheme.txt \
$(NULL)
ASCIIDOC_FLAGS = -n -a icons -a toc
EXTRA_DIST = \
$(ASCIIDOC_FILES) \
meson.build \
$(NULL)
if BUILD_HTML_MANUAL
ASCIIDOC_HTML = $(ASCIIDOC_FILES:.txt=.html)
CLEANFILES += $(ASCIIDOC_HTML)
all-local: $(ASCIIDOC_HTML)
.txt.html:
$(AM_V_GEN)$(ASCIIDOC) $(ASCIIDOC_FLAGS) -o $@ $<
endif
-include $(top_srcdir)/git.mk

12
docs/meson.build Normal file
View File

@ -0,0 +1,12 @@
if get_option('manual')
asciidoc = find_program('asciidoc', required : false)
if asciidoc.found()
foreach f: ['spice_protocol.txt', 'spice_uri_scheme.txt']
custom_target('HTML for @0@'.format(f),
input : f,
output : '@BASENAME@.html',
build_by_default : true,
command : [asciidoc, '-n', '-a', 'icons', '-a', 'toc', '-o', '@OUTPUT@', '@INPUT@'])
endforeach
endif
endif

477
docs/spice_protocol.txt Normal file
View File

@ -0,0 +1,477 @@
Spice protocol format file
==========================
Copyright (C) 2016 Red Hat, Inc.
Licensed under a Creative Commons Attribution-Share Alike 3.0
United States License (see http://creativecommons.org/licenses/by-sa/3.0/us/legalcode).
Basic
-----
The spice protocol format file defines the network protocol used by spice.
It resemble the C format.
file ::= <definitions> <protocol> ;
definitions ::= <definition>|<definitions><definition> ;
definition ::= <typedef>|<structure>|<enum>|<flag>|<message>|<channel> ;
protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;
integer ::= <hex>|<dec> ;
dec ::= [+-][0-9]+ ;
hex ::= "0x" [0-9a-f]+ ;
identifier ::= [a-z][a-z0-9_]* ;
(here BNF with some regular expression is used).
It's used to generate automatically code to marshal/demarshal the network data.
Example:
channel ExampleChannel {
message {
uint32 dummy;
} Dummy;
};
protocol Example {
ExampleChannel first = 1001;
};
As you can see brackets like C are used and structures looks like C but you
can also see that keywords like `channel`, `protocol`, `message` or some
predefined types like `uint32` are proper of the protocol.
Comments
--------
Both C and C++ style comments are supported
// this is a comment
/* this is a comment too
but can be split in multiple lines */
Base types
----------
All int from 8 to 64 bit (8, 16, 32 and 64) are supported either signed or unsigned.
Also you can pass one unix descriptor.
base_type ::= "int8"|"uint8"|"int16"|"uint16"|"int32"|"uint32"|"int64"|"uint64"|"unix_fd" ;
Example:
int16 x;
Enumerations and flags
----------------------
It's possible to specify enumerations and flags. The difference is that flags are defined as 2 power
values and can be combined. Enumerations and flags must have a size (`8`, `16` or `32`) specified.
enum ::= <enum_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
flag ::= <flag_type> "{" [ <enumflag_items> ] "}" <attributes> ";" ;
enum_type ::= "enum8"|"enum16"|"enum32" ;
flag_type ::= "flag8"|"flag16"|"flag32" ;
enumflag_items ::= <enumflag_item>|<enumflag_items><enumflag_item>
enumflag_item ::= <enum_name> [ "=" <integer> ] [ "," ] ;
enum_name ::= [a-z0-9_]* ;
Example:
enum16 Level {
LOW = 0x100,
MEDIUM,
HIGH = 0x1000
};
Variables
---------
As you should already have noted variables are similar to C syntax but there are
some differences.
variable ::= <type> [ "*" ] <identifier> [ "[" <array_size> "]" ] <attributes>;
The `*` specify a pointer. This is quite different from C. For the protocol it
specifies that in the protocol stream a relative offset is put that points to that
variable usually after all defined fields. This happens even on arrays, so for instance
int32 *n;
containing a 0x12345678 `n` value could ended up coded as
04 00 00 00 // 4 as offset
78 56 34 12 // `n`
(little endian). While an array of 2 items defined as
int32 *n[2];
and containing 0x12345678 and 0x9abcdef could end up with
04 00 00 00 // 4 as offset
78 56 34 12 // `n`[0]
ef cd ab 09 // `n`[1]
note that `int32 *n[2]` defined a pointer to an array of 2 items and not
an array of pointers as C.
*WARNING*: You should avoid using pointers on protocol if not necessary as they are complicated
to handle not using autogenerated code and also use more space on the network.
Arrays
------
As seen above the easiest way to define an array size is specifying a constant value.
However there are multiple way to specify the size
array_size ::= <integer>|<identifier>|""|<array_size_image>|<array_size_cstring> ;
array_size_image ::= "image_size" "(" <integer> "," <identifier> ")" ;
array_size_cstring ::= "cstring()" ;
We already seen integer.
Specifying an identifier name instead (should be variable) indicate that the length is specified
in another field, for instance
uint8 name_len;
int8 name[name_len];
allows to put a name of `name_len` len.
The empty value tells that the array will end when the containing message end so if we have
int8 name[];
and the message is
66 6f 6f
possibly the name we want is `foo` (66 6f 6f is the ASCII encoding for `foo`).
TODO: what happen with two [] in the structure ??
TODO: can a [] array not be the last and what happens ??
`image_size` allow to specify an array holding an image, for instance
uint16 width;
uint16 height;
uint8 raw_image[image_size(8, width, height)];
could contain row data in raw_image. The constant `8` is the bit size of the image.
`cstring` allows to specify NUL-terminated sequence so having
int8 name[cstring()];
and the message as
66 6f 6f 00
we'll have the `foo` name. Note that the field does not need to end the message as in `int8 name[]` example.
Structures
----------
The simplest compound type is the structure. As in C is defined as a list of fields (any variable or switch).
But as a protocol definition there are no alignment or padding and every field (beside pointer values) follow each other.
struct ::= "struct" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;
fields ::= <field>|<fields><field> ;
field ::= <variable>|<switch>
Example:
struct Point {
int32 x;
int32 y;
};
Messages
--------
Messages have the same syntax of structure (beside `message`) with the difference that they can
be used directly inside channels.
message ::= "message" <identifier> "{" [ <fields> ] "}" <attributes> ";" ;
Switches
--------
TODO
Type definitions
----------------
Like C type definition allow to short types defining new ones.
typedef ::= "typedef" <identifier> <type> <attributes> ;
note that unlike C name came before the type.
Example:
typedef XCoord int32;
Channels
--------
channel ::= "channel" <identifier> [ ":" <identifier> ] "{" <channel_messages> "}" <attributes> ";" ;
channel_messages ::= <channel_message>|<channel_messages><channel_message> ;
channel_message ::= "server:" | "client:" | "message" <identifier> [ "=" <integer> ] ;
Example:
channel ExampleChannel {
server:
message {
uint32 dummy;
} Dummy;
};
Note that every message is associated with a number which is used in the protocol.
The assignment work in a similar way to enumeration in C beside first message is
assigned 1 value and not 0. So first message (if no integer is specified) is assigned
1, second 2 and so on.
`server:` or `client:` specify the direction of messages following, `server` specify
messages from server while `client` from client. If not specified is assumed from
server.
For each channel you can specify a parent channel. Derived channel inherits all
messages specified in the parent.
Note that messages from parent can be overridden by derived channels.
Protocol
--------
protocol ::= "protocol" <identifier> "{" <protocol_channels> "}" ";" ;
protocol_channels ::= <protocol_channel>|<protocol_channels><protocol_channel> ;
protocol_channel ::= <identifier> <identifier> [ "=" <integer> ] ";" ;
Example:
protocol Example {
ExampleChannel first = 1001;
};
Protocol specify the list of channel supported. Channel have an associated number
assigned in a similar way of channels (incremented from one to the next with
first starting from 0 if not specified).
*NOTE*: Due to the way currently code is generate you should use
small numbers.
Attributes
----------
As you probably noted attributed can be specified for lot of definitions.
They allow to change code generated or specific constraints of the protocol.
attributes ::= ""|<attributes><attribute>|<attribute> ;
attribute ::= <attribute_name> [ "(" <attribute_values> ")" ] ;
attribute_values ::= <attribute_values> "," <attribute_value> | <attribute_value>
attribute_value ::= <integer> | <identifier>
attribute_name ::= @[a-z][a-z0-9_]* ;
Mostly of the attributes have no arguments, other currently have only one
argument.
*NOTE*: Some comments are also written in `spice-common` `python_modules/ptypes.py`
source file.
ctype
~~~~~
Specify the structure type name that the generated marshaller/demarshaller code
will use. By default the name will be converted to CamelCase and prefixed by
`Spice` so for example a structure like
struct Point {
int32 x;
int32 y;
} @ctype(MyPoint);
will be marshalled into a C structure like
struct MyPoint {
int32_t x;
int32_t y;
};
prefix
~~~~~~
This attribute allows to specify the prefix used for generated enumerations (both
protocol enumerations and flags generate C enumerations). By default the enumeration
will use upper case of the enum/flag name prefixed with `SPICE_` and followed by item so
enum32 level {
LOW,
HIGH,
};
will generate
typedef enum SpiceLevel {
SPICE_LEVEL_LOW,
SPICE_LEVEL_HIGH,
SPICE_LEVEL_ENUM_END
} SpiceLevel;
while
enum32 level {
LOW,
HIGH,
} @prefix(LVL_);
will generate
typedef enum SpiceLevel {
LVL_LOW,
LVL_HIGH,
SPICE_LEVEL_ENUM_END
} SpiceLevel;
(note that an automatic `END` enumeration is generated and name is not affected).
end
~~~
This attribute specifies that the data will be appended/embedded in the final C structure.
Example:
struct test {
uint16 len;
uint16 array[len] @end;
};
Output C structure:
struct test {
uint16_t len;
uint16_t array[0];
};
The generated code will allocate the C structure to allow space for extracted array.
*WARNING*: This option is usually confused with with empty size protocol. The
empty protocol array size specify array that extend on the network data while
the `@end` attribute specify to extend the C structure (for instance in the example
the attribute was attached to a `len`-sized array).
to_ptr
~~~~~~
This specifies that the corresponding C structure field contains a pointer to
the data. On marshalling the pointer is used, on demarshalling the data is
allocated in the memory block that holds the returned structure.
The type of this field must be a structure.
Example:
struct test {
uint16 num;
};
struct msg {
test ptr @to_ptr;
};
Output C structure:
struct test {
uint16_t num;
};
struct msg {
struct test *ptr;
};
nocopy
~~~~~~
TODO
as_ptr
~~~~~~
TODO
nomarshal
~~~~~~~~~
Do not generate code for marshalling this variable.
Usually used on last array element to make possible to manually feed data.
Example:
struct Data {
uint32 data_size;
uint8 data[data_size] @nomarshal;
};
zero_terminated
~~~~~~~~~~~~~~~
The field should terminated by zero.
Actually it's not used by python code so it's not enforced and no
code is generated.
marshall
~~~~~~~~
TODO
nonnull
~~~~~~~
This pointer field cannot be NULL. This means that marshaller assume C structure
contain not NULL pointer and demarshaller will fail to demarshall message if offset
is 0.
unique_flag
~~~~~~~~~~~
This flag field should contain just a single flag.
Actually it's not used by python code so it's not enforced and no
code is generated.
deprecated
~~~~~~~~~~
This flag currently apply only to enumerations and flags types and will set
generated C enumeration constant to deprecated
ptr_array
~~~~~~~~~
TODO
outvar
~~~~~~
TODO
anon
~~~~
TODO
chunk
~~~~~
TODO
ifdef
~~~~~
TODO
zero
~~~~
TODO
virtual
~~~~~~~
TODO

131
docs/spice_uri_scheme.txt Normal file
View File

@ -0,0 +1,131 @@
The "spice" URI scheme
======================
This document is inspired by 'The "vnc" URI Scheme' (rfc7869) and
attempts to document a standard Spice URI scheme.
The normative syntax of the Spice URI is defined in the <spice-uri>
rule in the following syntax specification. This specification
uses the Augmented Backus-Naur Form (ABNF) as described in
[RFC5234]. The Spice URI conforms to the generic URI syntax
specified in [RFC3986]. The <userinfo>, <host>, <port>,
<unreserved>, and <pct-encoded> rules are defined in [RFC3986].
spice-uri = spice-scheme "://" [ userinfo "@" ] [ host [ ":" port ] ]
[ "?" [ spice-params ] ]
spice-scheme = "spice" / "spice+unix" / "spice+tls"
spice-params = param "=" value *("&" param "=" value) ["&"]
param = 1*( param-char )
value = *( param-char )
param-char = unreserved / pct-encoded / unreserved-symbols
unreserved-symbols = ":" / "/" / "@" / "!" / "$" / "'"
/ "(" / ")" / "*" / "," / ";"
The "?", "=", and "&" characters are used to delimit Spice parameters
and must be percent-encoded when representing a data octet as
specified in [RFC3986]. Within the <spice-params> portion of a Spice
URI, the <unreserved-symbols> do not have special meaning and need not
be percent-encoded when representing a data octet.
A Spice URI has the general form:
spice-scheme://host:port?param1=value1&param2=value2...
The host information and each parameter value specify information
used in establishing or operating the remote desktop session as
specified in Section "URI Parameters".
URI Parameters
--------------
A description of host information and URI parameters is provided in
this section. Information on the constraints of various data types is
provided in Section "Data Types". All parameters are considered optional;
however, a client will not be able to connect without sufficient
information.
A parameter without a specified default value indicates that no
default value is implied by this URI scheme; however, Spice clients
can apply implementation-dependent default behaviors otherwise
consistent with this document.
The <host> and <port> values in the "spice://" and "spice+tls://" URIs
specify the address of the Spice server on the remote host:
[options="header"]
|=======================================================================
| Name | Type | Description | Default
| host | string | Spice server hostname or IP | none
| port | ushort | Spice server port | none
|=======================================================================
The <host> value in the "spice+unix://" URI specify the UNIX domain
socket path of the Spice server on the local host:
[options="header"]
|=======================================================================
| Name | Type | Description | Default
| host | string | UNIX domain socket path | none
|=======================================================================
The Spice URI parameter values specify remote desktop connection or
session properties, including aspects of client operation, usability,
and security as specified in the table below:
[options="header"]
|=======================================================================
| Name | Type | Description | Default
| port | ushort | Spice server port (legacy) | none
| tls-port | ushort | Spice server TLS port (legacy) | none
| password | string | Spice server password (legacy) | none
| ... | | |
|=======================================================================
Parameter names SHOULD be provided in the case specified in this
document; however, for compatibility, clients SHOULD accept
parameters in a case-insensitive manner. Values SHALL be interpreted
in a case-sensitive manner, unless otherwise noted.
Additional parameters likely to be useful with multiple Spice clients
can be added to the "URI Parameters" registry (at the moment,
discussed and approved on the Spice mailing list). Individual clients
MAY support parameters specific to that client. Spice clients
supporting application-specific parameters SHOULD include a
distinguishing prefix within the parameter name, such as the name of
the application package specified in source code except when precluded
by compatibility constraints. For example:
spice://?com.redhat.spiceclient.MonitorMapping=2&
It can also be expected that clients will maintain backward
compatibility with legacy URI formats and parameters.
Legacy software applications respond to "spice" URIs in different ways
and may fail to behave as expected. It is advisable to test "spice"
URIs with specific applications or consult application-specific
documentation.
Data Types
----------
Spice URIs can be percent-encoded as specified in [RFC3986] and MUST
be decoded. After decoding, the following type constraints and
semantics apply:
string
~~~~~~
Values of "string" type are UTF8-encoded strings as specified in
[RFC3629].
ushort
~~~~~~
The "ushort" values represent unsigned 16-bit integers expressed
in decimal digits with value between 0-65535 inclusive.

400
git.mk Normal file
View File

@ -0,0 +1,400 @@
# git.mk, a small Makefile to autogenerate .gitignore files
# for autotools-based projects.
#
# Copyright 2009, Red Hat, Inc.
# Copyright 2010,2011,2012,2013 Behdad Esfahbod
# Written by Behdad Esfahbod
#
# Copying and distribution of this file, with or without modification,
# is permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
#
# The latest version of this file can be downloaded from:
GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk
#
# Bugs, etc, should be reported upstream at:
# https://github.com/behdad/git.mk
#
# To use in your project, import this file in your git repo's toplevel,
# then do "make -f git.mk". This modifies all Makefile.am files in
# your project to -include git.mk. Remember to add that line to new
# Makefile.am files you create in your project, or just rerun the
# "make -f git.mk".
#
# This enables automatic .gitignore generation. If you need to ignore
# more files, add them to the GITIGNOREFILES variable in your Makefile.am.
# But think twice before doing that. If a file has to be in .gitignore,
# chances are very high that it's a generated file and should be in one
# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES.
#
# The only case that you need to manually add a file to GITIGNOREFILES is
# when remove files in one of mostlyclean-local, clean-local, distclean-local,
# or maintainer-clean-local make targets.
#
# Note that for files like editor backup, etc, there are better places to
# ignore them. See "man gitignore".
#
# If "make maintainer-clean" removes the files but they are not recognized
# by this script (that is, if "git status" shows untracked files still), send
# me the output of "git status" as well as your Makefile.am and Makefile for
# the directories involved and I'll diagnose.
#
# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
# Makefile.am.sample in the git.mk git repo.
#
# Don't EXTRA_DIST this file. It is supposed to only live in git clones,
# not tarballs. It serves no useful purpose in tarballs and clutters the
# build dir.
#
# This file knows how to handle autoconf, automake, libtool, gtk-doc,
# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
# appstream, hotdoc.
#
# This makefile provides the following targets:
#
# - all: "make all" will build all gitignore files.
# - gitignore: makes all gitignore files in the current dir and subdirs.
# - .gitignore: make gitignore file for the current dir.
# - gitignore-recurse: makes all gitignore files in the subdirs.
#
# KNOWN ISSUES:
#
# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the
# submodule doesn't find us. If you have configure.{in,ac} files in
# subdirs, add a proxy git.mk file in those dirs that simply does:
# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste.
# And add those files to git. See vte/gnome-pty-helper/git.mk for
# example.
#
###############################################################################
# Variables user modules may want to add to toplevel MAINTAINERCLEANFILES:
###############################################################################
#
# Most autotools-using modules should be fine including this variable in their
# toplevel MAINTAINERCLEANFILES:
GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL = \
$(srcdir)/aclocal.m4 \
$(srcdir)/autoscan.log \
$(srcdir)/configure.scan \
`AUX_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_AUX_DIR:$$1' ./configure.ac); \
test "x$$AUX_DIR" = "x$(srcdir)/" && AUX_DIR=$(srcdir); \
for x in \
ar-lib \
compile \
config.guess \
config.rpath \
config.sub \
depcomp \
install-sh \
ltmain.sh \
missing \
mkinstalldirs \
test-driver \
ylwrap \
; do echo "$$AUX_DIR/$$x"; done` \
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_HEADERS:$$1' ./configure.ac | \
head -n 1 | while read f; do echo "$(srcdir)/$$f.in"; done`
#
# All modules should also be fine including the following variable, which
# removes automake-generated Makefile.in files:
GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN = \
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_FILES:$$1' ./configure.ac | \
while read f; do \
case $$f in Makefile|*/Makefile) \
test -f "$(srcdir)/$$f.am" && echo "$(srcdir)/$$f.in";; esac; \
done`
#
# Modules that use libtool and use AC_CONFIG_MACRO_DIR() may also include this,
# though it's harmless to include regardless.
GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL = \
`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
for x in \
libtool.m4 \
ltoptions.m4 \
ltsugar.m4 \
ltversion.m4 \
lt~obsolete.m4 \
; do echo "$$MACRO_DIR/$$x"; done; \
fi`
#
# Modules that use gettext and use AC_CONFIG_MACRO_DIR() may also include this,
# though it's harmless to include regardless.
GITIGNORE_MAINTAINERCLEANFILES_M4_GETTEXT = \
`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
for x in \
codeset.m4 \
extern-inline.m4 \
fcntl-o.m4 \
gettext.m4 \
glibc2.m4 \
glibc21.m4 \
iconv.m4 \
intdiv0.m4 \
intl.m4 \
intldir.m4 \
intlmacosx.m4 \
intmax.m4 \
inttypes-pri.m4 \
inttypes_h.m4 \
lcmessage.m4 \
lib-ld.m4 \
lib-link.m4 \
lib-prefix.m4 \
lock.m4 \
longlong.m4 \
nls.m4 \
po.m4 \
printf-posix.m4 \
progtest.m4 \
size_max.m4 \
stdint_h.m4 \
threadlib.m4 \
uintmax_t.m4 \
visibility.m4 \
wchar_t.m4 \
wint_t.m4 \
xsize.m4 \
; do echo "$$MACRO_DIR/$$x"; done; \
fi`
###############################################################################
# Default rule is to install ourselves in all Makefile.am files:
###############################################################################
git-all: git-mk-install
git-mk-install:
@echo "Installing git makefile"
@any_failed=; \
find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \
if grep 'include .*/git.mk' $$x >/dev/null; then \
echo "$$x already includes git.mk"; \
else \
failed=; \
echo "Updating $$x"; \
{ cat $$x; \
echo ''; \
echo '-include $$(top_srcdir)/git.mk'; \
} > $$x.tmp || failed=1; \
if test x$$failed = x; then \
mv $$x.tmp $$x || failed=1; \
fi; \
if test x$$failed = x; then : else \
echo "Failed updating $$x"; >&2 \
any_failed=1; \
fi; \
fi; done; test -z "$$any_failed"
git-mk-update:
wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk
.PHONY: git-all git-mk-install git-mk-update
###############################################################################
# Actual .gitignore generation:
###############################################################################
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.ac
@echo "git.mk: Generating $@"
@{ \
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
for x in \
$(DOC_MODULE)-decl-list.txt \
$(DOC_MODULE)-decl.txt \
tmpl/$(DOC_MODULE)-unused.sgml \
"tmpl/*.bak" \
$(REPORT_FILES) \
$(DOC_MODULE).pdf \
xml html \
; do echo "/$$x"; done; \
FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \
case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-types"; then \
echo "/$(DOC_MODULE).types"; \
fi; \
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-sections"; then \
echo "/$(DOC_MODULE)-sections.txt"; \
fi; \
if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
for x in \
$(SETUP_FILES) \
$(DOC_MODULE).types \
; do echo "/$$x"; done; \
fi; \
fi; \
if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
for lc in $(DOC_LINGUAS); do \
for x in \
$(if $(DOC_MODULE),$(DOC_MODULE).xml) \
$(DOC_PAGES) \
$(DOC_INCLUDES) \
; do echo "/$$lc/$$x"; done; \
done; \
for x in \
$(_DOC_OMF_ALL) \
$(_DOC_DSK_ALL) \
$(_DOC_HTML_ALL) \
$(_DOC_MOFILES) \
$(DOC_H_FILE) \
"*/.xml2po.mo" \
"*/*.omf.out" \
; do echo /$$x; done; \
fi; \
if test "x$(HOTDOC)" = x; then :; else \
$(foreach project, $(HOTDOC_PROJECTS),echo "/$(call HOTDOC_TARGET,$(project))"; \
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-conf-path output)" ; \
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-private-folder)" ; \
) \
for x in \
.hotdoc.d \
; do echo "/$$x"; done; \
fi; \
if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
for lc in $(HELP_LINGUAS); do \
for x in \
$(HELP_FILES) \
"$$lc.stamp" \
"$$lc.mo" \
; do echo "/$$lc/$$x"; done; \
done; \
fi; \
if test "x$(gsettings_SCHEMAS)" = x; then :; else \
for x in \
$(gsettings_SCHEMAS:.xml=.valid) \
$(gsettings__enum_file) \
; do echo "/$$x"; done; \
fi; \
if test "x$(appdata_XML)" = x; then :; else \
for x in \
$(appdata_XML:.xml=.valid) \
; do echo "/$$x"; done; \
fi; \
if test "x$(appstream_XML)" = x; then :; else \
for x in \
$(appstream_XML:.xml=.valid) \
; do echo "/$$x"; done; \
fi; \
if test -f $(srcdir)/po/Makefile.in.in; then \
for x in \
ABOUT-NLS \
po/Makefile.in.in \
po/Makefile.in.in~ \
po/Makefile.in \
po/Makefile \
po/Makevars.template \
po/POTFILES \
po/Rules-quot \
po/stamp-it \
po/stamp-po \
po/.intltool-merge-cache \
"po/*.gmo" \
"po/*.header" \
"po/*.mo" \
"po/*.sed" \
"po/*.sin" \
po/$(GETTEXT_PACKAGE).pot \
intltool-extract.in \
intltool-merge.in \
intltool-update.in \
; do echo "/$$x"; done; \
fi; \
if test -f $(srcdir)/configure; then \
for x in \
autom4te.cache \
configure \
config.h \
stamp-h1 \
libtool \
config.lt \
; do echo "/$$x"; done; \
fi; \
if test "x$(DEJATOOL)" = x; then :; else \
for x in \
$(DEJATOOL) \
; do echo "/$$x.sum"; echo "/$$x.log"; done; \
echo /site.exp; \
fi; \
if test "x$(am__dirstamp)" = x; then :; else \
echo "$(am__dirstamp)"; \
fi; \
if test "x$(findstring libtool,$(LTCOMPILE))" = x -a "x$(findstring libtool,$(LTCXXCOMPILE))" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
for x in \
"*.lo" \
".libs" "_libs" \
; do echo "$$x"; done; \
fi; \
for x in \
.gitignore \
$(GITIGNOREFILES) \
$(CLEANFILES) \
$(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \
$(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \
$(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \
so_locations \
$(MOSTLYCLEANFILES) \
$(TEST_LOGS) \
$(TEST_LOGS:.log=.trs) \
$(TEST_SUITE_LOG) \
$(TESTS:=.test) \
"*.gcda" \
"*.gcno" \
$(DISTCLEANFILES) \
$(am__CONFIG_DISTCLEAN_FILES) \
$(CONFIG_CLEAN_FILES) \
TAGS ID GTAGS GRTAGS GSYMS GPATH tags \
"*.tab.c" \
$(MAINTAINERCLEANFILES) \
$(BUILT_SOURCES) \
$(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \
$(filter %_vala.stamp,$(DIST_COMMON)) \
$(filter %.vapi,$(DIST_COMMON)) \
$(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \
Makefile \
Makefile.in \
"*.orig" \
"*.rej" \
"*.bak" \
"*~" \
".*.sw[nop]" \
".dirstamp" \
; do echo "/$$x"; done; \
for x in \
"*.$(OBJEXT)" \
$(DEPDIR) \
; do echo "$$x"; done; \
} | \
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
sed 's@/[.]/@/@g' | \
LC_ALL=C sort | uniq > $@.tmp && \
mv $@.tmp $@;
all: $(srcdir)/.gitignore gitignore-recurse-maybe
gitignore: $(srcdir)/.gitignore gitignore-recurse
gitignore-recurse-maybe:
@for subdir in $(DIST_SUBDIRS); do \
case " $(SUBDIRS) " in \
*" $$subdir "*) :;; \
*) test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir");; \
esac; \
done
gitignore-recurse:
@for subdir in $(DIST_SUBDIRS); do \
test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir"); \
done
maintainer-clean: gitignore-clean
gitignore-clean:
-rm -f $(srcdir)/.gitignore
.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe

0
m4/.gitignore vendored Normal file
View File

49
m4/ax_python_module.m4 Normal file
View File

@ -0,0 +1,49 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PYTHON_MODULE(modname[, fatal])
#
# DESCRIPTION
#
# Checks for Python module.
#
# If fatal is non-empty then absence of a module will trigger an error.
#
# LICENSE
#
# Copyright (c) 2008 Andrew Collier
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 6
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
AC_DEFUN([AX_PYTHON_MODULE],[
if test -z $PYTHON;
then
PYTHON="python"
fi
PYTHON_NAME=`basename $PYTHON`
AC_MSG_CHECKING($PYTHON_NAME module: $1)
$PYTHON -c "import $1" 2>/dev/null
if test $? -eq 0;
then
AC_MSG_RESULT(yes)
eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
else
AC_MSG_RESULT(no)
eval AS_TR_CPP(HAVE_PYMOD_$1)=no
#
if test -n "$2"
then
AC_MSG_ERROR(failed to find required module $1)
exit 1
fi
fi
])

6
m4/common.m4 Normal file
View File

@ -0,0 +1,6 @@
dnl This file should be included by spice-common user from
dnl configure.ac to have all required checks in order to use spice-common
m4_define(spice_common_dir,m4_bpatsubst(__file__,[/m4/common\.m4],[]))dnl
dnl Automatically include m4 files in m4 directory
AC_CONFIG_MACRO_DIRS(spice_common_dir[/m4])dnl
SPICE_COMMON(spice_common_dir)

368
m4/spice-deps.m4 Normal file
View File

@ -0,0 +1,368 @@
# SPICE_WARNING(warning)
# SPICE_PRINT_MESSAGES
# ----------------------
# Collect warnings and print them at the end so they are clearly visible.
# ---------------------
AC_DEFUN([SPICE_WARNING],[AS_VAR_APPEND([spice_warnings],["|$1"])])
AC_DEFUN([SPICE_PRINT_MESSAGES],[
ac_save_IFS="$IFS"
IFS="|"
for msg in $spice_warnings; do
IFS="$ac_save_IFS"
AS_VAR_IF([msg],[],,[AC_MSG_WARN([$msg]); echo >&2])
done
IFS="$ac_save_IFS"
])
# SPICE_EXTRA_CHECKS()
# --------------------
# Check for --enable-extra-checks option
# --------------------
AC_DEFUN([SPICE_EXTRA_CHECKS],[
AC_ARG_ENABLE([extra-checks],
AS_HELP_STRING([--enable-extra-checks=@<:@yes/no@:>@],
[Enable expensive checks @<:@default=no@:>@]))
AM_CONDITIONAL(ENABLE_EXTRA_CHECKS, test "x$enable_extra_checks" = "xyes")
AM_COND_IF([ENABLE_EXTRA_CHECKS], AC_DEFINE([ENABLE_EXTRA_CHECKS], 1, [Enable extra checks on code]))
])
# SPICE_CHECK_SYSDEPS()
# ---------------------
# Checks for header files and library functions needed by spice-common.
# ---------------------
AC_DEFUN([SPICE_CHECK_SYSDEPS], [
AC_C_BIGENDIAN
AC_FUNC_ALLOCA
AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdlib.h sys/socket.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics
AC_C_INLINE
# Checks for library functions
# do not check malloc or realloc, since that cannot be cross-compiled checked
AC_CHECK_FUNCS([floor])
AC_SEARCH_LIBS([hypot], [m], [], [
AC_MSG_ERROR([unable to find the hypot() function])
])
])
# SPICE_CHECK_SMARTCARD
# ---------------------
# Adds a --enable-smartcard switch in order to enable/disable smartcard
# support, and checks if the needed libraries are available. If found, it will
# return the flags to use in the SMARTCARD_CFLAGS and SMARTCARD_LIBS variables, and
# it will define a USE_SMARTCARD preprocessor symbol as well as a HAVE_SMARTCARD
# Makefile conditional.
#----------------------
AC_DEFUN([SPICE_CHECK_SMARTCARD], [
AC_ARG_ENABLE([smartcard],
AS_HELP_STRING([--enable-smartcard=@<:@yes/no/auto@:>@],
[Enable smartcard support @<:@default=auto@:>@]),
[],
[enable_smartcard="auto"])
have_smartcard=no
if test "x$enable_smartcard" != "xno"; then
PKG_CHECK_MODULES([SMARTCARD], [libcacard >= 2.5.1], [have_smartcard=yes], [have_smartcard=no])
if test "x$enable_smartcard" = "xyes" && test "x$have_smartcard" = "xno"; then
AC_MSG_ERROR([smarcard support explicitly requested, but some required packages are not available])
fi
if test "x$have_smartcard" = "xyes"; then
AC_DEFINE(USE_SMARTCARD, [1], [Define if supporting smartcard proxying])
fi
fi
AM_CONDITIONAL(HAVE_SMARTCARD, test "x$have_smartcard" = "xyes")
])
# SPICE_CHECK_OPUS
# ----------------
# Check for the availability of Opus. If found, it will return the flags to use
# in the OPUS_CFLAGS and OPUS_LIBS variables, and it will define a
# HAVE_OPUS preprocessor symbol as well as a HAVE_OPUS Makefile conditional.
# ----------------
AC_DEFUN([SPICE_CHECK_OPUS], [
AC_ARG_ENABLE([opus],
[ --disable-opus Disable Opus audio codec (enabled by default)],,
[enable_opus="auto"])
if test "x$enable_opus" != "xno"; then
PKG_CHECK_MODULES([OPUS], [opus >= 0.9.14], [have_opus=yes], [have_opus=no])
if test "x$enable_opus" = "xauto" && test "x$have_opus" = "xno"; then
AC_MSG_ERROR([Opus could not be detected, explicitly use --disable-opus if that's intentional])
fi
if test "x$enable_opus" = "xyes" && test "x$have_opus" != "xyes"; then
AC_MSG_ERROR([--enable-opus has been specified, but Opus is missing])
fi
fi
AM_CONDITIONAL([HAVE_OPUS], [test "x$have_opus" = "xyes"])
AM_COND_IF([HAVE_OPUS], AC_DEFINE([HAVE_OPUS], [1], [Define if we have OPUS]))
])
# SPICE_CHECK_PIXMAN
# ------------------
# Check for the availability of pixman. If found, it will return the flags to
# use in the PIXMAN_CFLAGS and PIXMAN_LIBS variables.
#-------------------
AC_DEFUN([SPICE_CHECK_PIXMAN], [
PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.17.7)
])
# SPICE_CHECK_GLIB2
# -----------------
# Check for the availability of glib2. If found, it will return the flags to
# use in the GLIB2_CFLAGS and GLIB2_LIBS variables.
#------------------
AC_DEFUN([SPICE_CHECK_GLIB2], [
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.38)
PKG_CHECK_MODULES(GIO2, gio-2.0 >= 2.38)
GLIB2_CFLAGS="$GLIB2_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_38 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_38"
])
# SPICE_CHECK_GDK_PIXBUF
# ----------------------
# Check for the availability of gdk-pixbuf. If found, it will return the flags to use
# in the GDK_PIXBUF_CFLAGS and GDK_PIXBUF_LIBS variables, and it will define a
# HAVE_GDK_PIXBUF preprocessor symbol as well as a HAVE_GDK_PIXBUF Makefile conditional.
# ----------------
AC_DEFUN([SPICE_CHECK_GDK_PIXBUF], [
PKG_CHECK_MODULES([GDK_PIXBUF], [gdk-pixbuf-2.0 >= 2.26], [have_gdk_pixbuf=yes], [have_gdk_pixbuf=no])
AM_CONDITIONAL([HAVE_GDK_PIXBUF], [test "x$have_gdk_pixbuf" = "xyes"])
AM_COND_IF([HAVE_GDK_PIXBUF], AC_DEFINE([HAVE_GDK_PIXBUF], [1], [Define if gdk-pixbuf was found]))
])
# SPICE_CHECK_PYTHON_MODULES()
# --------------------------
# Adds a --enable-python-checks configure flags as well as checks for the
# availability of the python modules needed by the python scripts generating
# C code from spice.proto. These checks are not needed when building from
# tarballs so they are disabled by default.
#---------------------------
AC_DEFUN([SPICE_CHECK_PYTHON_MODULES], [
AC_ARG_ENABLE([python-checks],
AS_HELP_STRING([--enable-python-checks=@<:@yes/no@:>@],
[Enable checks for Python modules needed to build from git @<:@default=no@:>@]),
[],
[enable_python_checks="no"])
if test "x$enable_python_checks" != "xno"; then
AS_IF([test -n "$PYTHON"], # already set required PYTHON version
[AM_PATH_PYTHON
AX_PYTHON_MODULE([pyparsing], [1])],
[PYTHON=python3
AX_PYTHON_MODULE([pyparsing])
test "$HAVE_PYMOD_PYPARSING" = "yes"],
[AM_PATH_PYTHON([3])],
[AC_MSG_ERROR([Python module pyparsing is required])])
else
AM_PATH_PYTHON
fi
])
# SPICE_CHECK_LZ4
# ---------------
# Adds a --enable-lz4 switch in order to enable/disable LZ4 compression
# support, and checks if the needed libraries are available. If found, it will
# return the flags to use in the LZ4_CFLAGS and LZ4_LIBS variables, and
# it will define a USE_LZ4 preprocessor symbol and a HAVE_LZ4 conditional.
# ---------------
AC_DEFUN([SPICE_CHECK_LZ4], [
AC_ARG_ENABLE([lz4],
AS_HELP_STRING([--enable-lz4=@<:@yes/no/auto@:>@],
[Enable LZ4 compression support @<:@default=auto@:>@]),
[],
[enable_lz4="auto"])
have_lz4="no"
if test "x$enable_lz4" != "xno"; then
# LZ4_compress_default is available in liblz4 >= 129, however liblz has changed
# versioning scheme making the check failing. Rather check for function definition
PKG_CHECK_MODULES([LZ4], [liblz4], [have_lz4="yes"], [have_lz4="no"])
if test "x$have_lz4" = "xyes"; then
# It is necessary to set LIBS and CFLAGS before AC_CHECK_FUNC
old_LIBS="$LIBS"
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $LZ4_CFLAGS"
LIBS="$LIBS $LZ4_LIBS"
AC_CHECK_FUNC([LZ4_compress_default], [
AC_DEFINE(USE_LZ4, [1], [Define to build with lz4 support])],
[have_lz4="no"])
AC_CHECK_FUNCS([LZ4_compress_fast_continue])
LIBS="$old_LIBS"
CFLAGS="$old_CFLAGS"
fi
if test "x$enable_lz4" = "xyes" && test "x$have_lz4" = "xno"; then
AC_MSG_ERROR([lz4 support requested but liblz4 >= 129 could not be found])
fi
fi
AM_CONDITIONAL(HAVE_LZ4, test "x$have_lz4" = "xyes")
])
# SPICE_CHECK_GSTREAMER(VAR, version, packages-to-check-for, [action-if-found, [action-if-not-found]])
# ---------------------
# Checks whether the specified GStreamer modules are present and sets the
# corresponding autoconf variables and preprocessor definitions.
# ---------------------
AC_DEFUN([SPICE_CHECK_GSTREAMER], [
AS_VAR_PUSHDEF([have_gst],[have_]m4_tolower([$1]))dnl
AS_VAR_PUSHDEF([gst_inspect],[GST_INSPECT_$2])dnl
PKG_CHECK_MODULES([$1], [$3],
[have_gst="yes"
AC_SUBST(AS_TR_SH([[$1]_CFLAGS]))
AC_SUBST(AS_TR_SH([[$1]_LIBS]))
AS_VAR_APPEND([SPICE_REQUIRES], [" $3"])
AC_DEFINE(AS_TR_SH([HAVE_$1]), [1], [Define if supporting GStreamer $2])
AC_PATH_PROG(gst_inspect, gst-inspect-$2)
AS_IF([test "x$gst_inspect" = x],
SPICE_WARNING([Cannot verify that the required runtime GStreamer $2 elements are present because gst-inspect-$2 is missing]))
$4],
[have_gst="no"
$5])
AS_VAR_POPDEF([gst_inspect])dnl
AS_VAR_POPDEF([have_gst])dnl
])
# SPICE_CHECK_GSTREAMER_ELEMENTS(gst-inspect, package, elements-to-check-for)
# ---------------------
# Checks that the specified GStreamer elements are installed. If not it
# issues a warning and sets missing_gstreamer_elements.
# ---------------------
AC_DEFUN([SPICE_CHECK_GSTREAMER_ELEMENTS], [
AS_IF([test "x$1" != x],
[missing=""
for element in $3
do
AS_VAR_PUSHDEF([cache_var],[spice_cv_prog_${1}_${element}])dnl
AC_CACHE_CHECK([for the $element GStreamer element], cache_var,
[found=no
"$1" $element >/dev/null 2>/dev/null && found=yes
eval "cache_var=$found"])
AS_VAR_COPY(res, cache_var)
AS_IF([test "x$res" = "xno"], [missing="$missing $element"])
AS_VAR_POPDEF([cache_var])dnl
done
AS_IF([test "x$missing" != x],
[SPICE_WARNING([The$missing GStreamer element(s) are missing. You should be able to find them in the $2 package.])
missing_gstreamer_elements="yes"],
[test "x$missing_gstreamer_elements" = x],
[missing_gstreamer_elements="no"])
])
])
# SPICE_CHECK_SASL
# ----------------
# Adds a --with-sasl switch to allow using SASL for authentication.
# Checks whether the required library is available. If it is present,
# it will return the flags to use in SASL_CFLAGS and SASL_LIBS variables,
# and it will define a have_sasl configure variable and a HAVE_SASL preprocessor
# symbol.
# ----------------
AC_DEFUN([SPICE_CHECK_SASL], [
AC_ARG_WITH([sasl],
[AS_HELP_STRING([--with-sasl=@<:@yes/no/auto@:>@],
[use cyrus SASL for authentication @<:@default=auto@:>@])],
[],
[with_sasl="auto"])
have_sasl=no
if test "x$with_sasl" != "xno"; then
PKG_CHECK_MODULES([SASL], [libsasl2], [have_sasl=yes],[have_sasl=no])
if test "x$have_sasl" = "xno" && test "x$with_sasl" = "xyes"; then
AC_MSG_ERROR([Cyrus SASL support requested but libsasl2 could not be found])
fi
if test "x$have_sasl" = "xyes"; then
AC_DEFINE([HAVE_SASL], 1, [whether Cyrus SASL is available for authentication])
fi
fi
])
# SPICE_CHECK_OPENSSL
# -----------------
# Check for the availability of openssl. If found, it will return the flags to
# use in the OPENSSL_CFLAGS and OPENSSL_LIBS variables.
#------------------
AC_DEFUN([SPICE_CHECK_OPENSSL], [
PKG_CHECK_MODULES(OPENSSL, openssl)
])
# SPICE_CHECK_UDEV
# -----------------
# Check for the availability of libudev. If found, it will help to determine
# if a given vendor GPU is available or not.
#------------------
AC_DEFUN([SPICE_CHECK_UDEV], [
PKG_CHECK_MODULES([UDEV], [libudev], [have_udev=yes],[have_udev=no])
if test "x$have_udev" = "xyes"; then
AC_DEFINE([HAVE_UDEV], 1, [whether libudev is available to identify GPU])
fi
])
# SPICE_CHECK_INSTRUMENTATION
# -----------------
# Check for the availability of an instrumentation library.
#------------------
AC_DEFUN([SPICE_CHECK_INSTRUMENTATION], [
AC_ARG_ENABLE([instrumentation],
AS_HELP_STRING([--enable-instrumentation=@<:@recorder/agent/no@:>@],
[Enable instrumentation @<:@default=no@:>@]),
[],
enable_instrumentation="no")
AS_IF([test "$enable_instrumentation" = "recorder"],
AC_DEFINE([ENABLE_RECORDER], [1], [Define if the recorder instrumentation is enabled]))
AS_IF([test "$enable_instrumentation" = "agent"],
AC_DEFINE([ENABLE_AGENT_INTERFACE], [1], [Define if the agent-interface instrumentation is enabled]))
AM_CONDITIONAL([ENABLE_RECORDER],[test "$enable_instrumentation" = "recorder"])
AM_CONDITIONAL([ENABLE_AGENT_INTERFACE],[test "$enable_instrumentation" = "agent"])
])
# SPICE_COMMON
# -----------------
# Define variables in order to use spice-common
# SPICE_COMMON_DIR directory for output libraries
# SPICE_COMMON_CFLAGS CFLAGS to add to use the library
#
# SPICE_PROTOCOL_MIN_VER input (m4) and output (autoconf) SPICE protocol version
# SPICE_PROTOCOL_CFLAGS CFLAGS for SPICE protocol, already automatically included
#
# GLIB2_MIN_VER input (m4) and output (shell) GLib2 minimum version
# GLIB2_MIN_VERSION output (shell) variable like "GLIB_VERSION_1_2" from GLIB2_MIN_VER
#------------------
AC_DEFUN([SPICE_COMMON], [dnl
dnl These add some flags and checks to component using spice-common
dnl The flags are necessary in order to make included header working
AC_REQUIRE([SPICE_EXTRA_CHECKS])dnl
AC_REQUIRE([SPICE_CHECK_INSTRUMENTATION])dnl
dnl Get the required spice protocol version
m4_define([SPICE_PROTOCOL_MIN_VER],m4_ifdef([SPICE_PROTOCOL_MIN_VER],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
m4_define([SPICE_PROTOCOL_MIN_VER],m4_if(m4_version_compare(SPICE_PROTOCOL_MIN_VER,[0.14.2]),[1],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
[SPICE_PROTOCOL_MIN_VER]=SPICE_PROTOCOL_MIN_VER
m4_undefine([SPICE_PROTOCOL_MIN_VER])dnl
PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER])
AC_SUBST([SPICE_PROTOCOL_MIN_VER])dnl
dnl Get the required GLib2 version
m4_define([GLIB2_MIN_VER],m4_ifdef([GLIB2_MIN_VER],GLIB2_MIN_VER,[2.38]))dnl
m4_define([GLIB2_MIN_VER],m4_if(m4_version_compare(GLIB2_MIN_VER,[2.38]),[1],GLIB2_MIN_VER,[2.38]))dnl
m4_define([GLIB2_MIN_VERSION],[GLIB_VERSION_]m4_translit(GLIB2_MIN_VER,[.],[_]))dnl
[GLIB2_MIN_VER]=GLIB2_MIN_VER
[GLIB2_MIN_VERSION]=GLIB2_MIN_VERSION
m4_undefine([GLIB2_MIN_VER])dnl
m4_undefine([GLIB2_MIN_VERSION])dnl
PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= $GLIB2_MIN_VER gio-2.0 >= $GLIB2_MIN_VER])
dnl Configuration variables
AC_CONFIG_SUBDIRS([$1])dnl
SPICE_COMMON_CFLAGS='-I${top_srcdir}/$1 -I${top_builddir}/$1 -DG_LOG_DOMAIN=\"Spice\" $(SPICE_PROTOCOL_CFLAGS) $(GLIB2_CFLAGS)'
AC_SUBST([SPICE_COMMON_CFLAGS])dnl
SPICE_COMMON_DIR='${top_builddir}/$1'
AC_SUBST([SPICE_COMMON_DIR])dnl
])

32
m4/spice_manual.m4 Normal file
View File

@ -0,0 +1,32 @@
dnl SPICE_MANUAL
dnl ------------
dnl Check if user wants manuals to be compiled and
dnl if all programs (asciidoc and a2x) are available
dnl ------------
dnl Shell defines:
dnl - have_asciidoc yes or not is asciidoc program is available
dnl Automake macros:
dnl - A2X a2x program or empty
dnl - ASCIIDOC asciidoc program or emtpy
dnl - BUILD_MANUAL if asciidoc and a2x are available
dnl - BUILD_HTML_MANUAL if asciidoc is available (html can be produced)
dnl - BUILD_CHUNKED_MANUAL if a2x is available
AC_DEFUN([SPICE_MANUAL],[
AC_ARG_ENABLE([manual],
AS_HELP_STRING([--enable-manual=@<:@auto/yes/no@:>@],
[Build SPICE manual]),
[],
[enable_manual="auto"])
if test "x$enable_manual" != "xno"; then
AC_PATH_PROG([ASCIIDOC], [asciidoc])
AS_IF([test -z "$ASCIIDOC" && test "x$enable_manual" = "xyes"],
[AC_MSG_ERROR([asciidoc is missing and build of manual was requested])])
AC_PATH_PROG([A2X], [a2x])
AS_IF([test -z "$A2X" && test "x$enable_manual" = "xyes"],
[AC_MSG_ERROR([a2x is missing and build of manual was requested])])
fi
AS_IF([test -n "$ASCIIDOC"], [have_asciidoc=yes], [have_asciidoc=no])
AM_CONDITIONAL([BUILD_MANUAL], [test -n "$ASCIIDOC" || test -n "$A2X"])
AM_CONDITIONAL([BUILD_HTML_MANUAL], [test -n "$ASCIIDOC"])
AM_CONDITIONAL([BUILD_CHUNKED_MANUAL], [test -n "$A2X"])
])

181
meson.build Normal file
View File

@ -0,0 +1,181 @@
#
# project definition
#
project('spice-common', 'c',
meson_version : '>= 0.49.0',
license : 'LGPLv2.1',
default_options : ['warning_level=2'])
if not meson.is_subproject()
warning('This project is only intended to be used as a subproject!')
endif
# some global vars
spice_common_global_cflags = ['-DG_LOG_DOMAIN="Spice"',
'-Wno-unused-parameter']
if get_option('alignment-checks')
spice_common_global_cflags += ['-DSPICE_DEBUG_ALIGNMENT']
endif
spice_common_deps = []
spice_common_include = include_directories('.')
spice_proto = files('spice.proto')
spice_codegen = files('spice_codegen.py')
spice_codegen_files = [spice_codegen]
compiler = meson.get_compiler('c')
spice_common_config_data = configuration_data()
if get_option('extra-checks')
spice_common_config_data.set('ENABLE_EXTRA_CHECKS', '1')
endif
if host_machine.endian() == 'big'
spice_common_config_data.set('WORDS_BIGENDIAN', '1')
endif
if get_option('instrumentation') == 'recorder'
spice_common_config_data.set('ENABLE_RECORDER', '1')
endif
if get_option('instrumentation') == 'agent'
spice_common_config_data.set('ENABLE_AGENT_INTERFACE', '1')
endif
spice_common_generate_code = get_option('generate-code')
spice_common_generate_client_code = spice_common_generate_code == 'all' or spice_common_generate_code == 'client'
spice_common_generate_server_code = spice_common_generate_code == 'all' or spice_common_generate_code == 'server'
#
# check for system headers
#
headers = ['alloca.h',
'arpa/inet.h',
'dlfcn.h',
'inttypes.h',
'netinet/in.h',
'stdlib.h',
'sys/socket.h',
'sys/stat.h',
'sys/types.h',
'unistd.h',
'regex.h',
'sys/mman.h']
foreach header : headers
if compiler.has_header(header)
spice_common_config_data.set('HAVE_@0@'.format(header.underscorify().to_upper()), '1')
endif
endforeach
#
# check for system functions
#
functions = ['alloca',
'sigaction',
'drand48',
'setlinebuf']
foreach func : functions
if compiler.has_function(func)
spice_common_config_data.set('HAVE_@0@'.format(func.underscorify().to_upper()), '1')
endif
endforeach
# FIXME
# check for libm, as workaround for https://github.com/mesonbuild/meson/issues/3740
libm = compiler.find_library('m', required : false)
if libm.found()
spice_common_deps += libm
endif
#
# check for mandatory dependencies
#
glib_version = '2.38'
glib_version_info = '>= @0@'.format(glib_version)
spice_protocol_version = '0.14.2'
spice_protocol_version_req = get_option('spice-protocol-version')
if spice_protocol_version_req.version_compare('> @0@'.format(spice_protocol_version))
spice_protocol_version = spice_protocol_version_req
endif
deps = {'spice-protocol' : '>= @0@'.format(spice_protocol_version),
'glib-2.0' : glib_version_info,
'pixman-1' : '>= 0.17.7',
'openssl' : '>= 1.0.0'}
foreach dep, version : deps
spice_common_deps += dependency(dep, version : version)
endforeach
gio2_deps = dependency('gio-2.0', version : glib_version_info)
#
# Non-mandatory/optional dependencies
#
optional_deps = {'opus' : '>= 0.9.14'}
foreach dep, version : optional_deps
d = dependency(dep, required : get_option(dep), version : version)
if d.found()
spice_common_deps += d
spice_common_config_data.set('HAVE_@0@'.format(dep.underscorify().to_upper()), '1')
endif
endforeach
# Python
if spice_common_generate_client_code or spice_common_generate_server_code
py_module = import('python')
python = py_module.find_installation('python3')
if get_option('python-checks')
foreach module : ['pyparsing']
message('Checking for python module @0@'.format(module))
cmd = run_command(python, '-c', 'import @0@'.format(module), check : false)
if cmd.returncode() != 0
error('Python module @0@ not found'.format(module))
endif
endforeach
endif
endif
# smartcard check
smartcard_dep = dependency('libcacard', required : get_option('smartcard'), version : '>= 2.5.1')
if smartcard_dep.found()
spice_common_deps += smartcard_dep
spice_common_config_data.set('USE_SMARTCARD', '1')
endif
# udev check
udev_dep = dependency('libudev', required : false)
if udev_dep.found()
spice_common_deps += udev_dep
spice_common_config_data.set('HAVE_UDEV', '1')
endif
#
# global C defines
#
glib_encoded_version = 'GLIB_VERSION_@0@'.format(glib_version.underscorify())
spice_common_global_cflags += ['-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_encoded_version),
'-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_encoded_version)]
add_project_arguments(compiler.get_supported_arguments(spice_common_global_cflags),
language : 'c')
#
# Subdirectories
#
subdir('python_modules')
subdir('common')
if get_option('tests')
subdir('tests')
endif
subdir('docs')
#
# write config.h
#
configure_file(output : 'config.h',
configuration : spice_common_config_data)

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