2008-12-02 15:15:01 -05:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2008 Kristian Høgsberg
|
2013-02-26 11:30:51 -05:00
|
|
|
* Copyright © 2013 Jason Ekstrand
|
2008-12-02 15:15:01 -05:00
|
|
|
*
|
2015-06-10 10:54:15 -07:00
|
|
|
* 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:
|
2008-12-02 15:15:01 -05:00
|
|
|
*
|
2015-06-10 10:54:15 -07:00
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
|
* next paragraph) 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.
|
2008-12-02 15:15:01 -05:00
|
|
|
*/
|
|
|
|
|
|
2011-05-04 21:21:52 +02:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
|
2012-05-08 17:17:25 +01:00
|
|
|
#include <math.h>
|
2008-10-08 12:48:46 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/uio.h>
|
2010-08-05 17:44:31 -04:00
|
|
|
#include <fcntl.h>
|
2010-08-09 14:34:11 -04:00
|
|
|
#include <unistd.h>
|
2010-08-25 17:11:29 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/socket.h>
|
2011-07-14 18:56:40 +03:00
|
|
|
#include <time.h>
|
2013-02-26 11:30:51 -05:00
|
|
|
#include <ffi.h>
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2008-12-21 21:50:23 -05:00
|
|
|
#include "wayland-util.h"
|
2011-11-18 13:46:56 -05:00
|
|
|
#include "wayland-private.h"
|
2012-04-23 13:55:55 +03:00
|
|
|
#include "wayland-os.h"
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2018-08-14 13:07:52 +02:00
|
|
|
static inline uint32_t
|
|
|
|
|
div_roundup(uint32_t n, size_t a)
|
|
|
|
|
{
|
|
|
|
|
/* The cast to uint64_t is necessary to prevent overflow when rounding
|
|
|
|
|
* values close to UINT32_MAX. After the division it is again safe to
|
|
|
|
|
* cast back to uint32_t.
|
|
|
|
|
*/
|
|
|
|
|
return (uint32_t) (((uint64_t) n + (a - 1)) / a);
|
|
|
|
|
}
|
2012-03-30 10:28:39 -04:00
|
|
|
|
2021-08-06 13:16:55 -05:00
|
|
|
struct wl_ring_buffer {
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
char *data;
|
|
|
|
|
size_t head, tail;
|
|
|
|
|
uint32_t size_bits;
|
|
|
|
|
uint32_t max_size_bits; /* 0 for unlimited */
|
2008-10-08 12:48:46 -04:00
|
|
|
};
|
|
|
|
|
|
2012-03-09 12:51:42 +02:00
|
|
|
#define MAX_FDS_OUT 28
|
|
|
|
|
#define CLEN (CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t)))
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
struct wl_connection {
|
2021-08-06 13:16:55 -05:00
|
|
|
struct wl_ring_buffer in, out;
|
|
|
|
|
struct wl_ring_buffer fds_in, fds_out;
|
2008-10-08 12:48:46 -04:00
|
|
|
int fd;
|
2012-10-04 16:54:22 -04:00
|
|
|
int want_flush;
|
2008-10-08 12:48:46 -04:00
|
|
|
};
|
|
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
static inline size_t
|
|
|
|
|
size_pot(uint32_t size_bits)
|
|
|
|
|
{
|
2024-06-30 22:36:11 +05:30
|
|
|
if (!(size_bits < 8 * sizeof(size_t)))
|
|
|
|
|
wl_abort("Too many bits for size_t\n");
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
|
|
|
|
|
return ((size_t)1) << size_bits;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
|
ring_buffer_capacity(const struct wl_ring_buffer *b) {
|
|
|
|
|
return size_pot(b->size_bits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
|
ring_buffer_mask(const struct wl_ring_buffer *b, size_t i) {
|
|
|
|
|
size_t m = ring_buffer_capacity(b) - 1;
|
|
|
|
|
return i & m;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-17 18:20:37 +03:00
|
|
|
static int
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count)
|
2010-08-26 17:44:31 -04:00
|
|
|
{
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size_t head, size;
|
2014-04-17 18:20:37 +03:00
|
|
|
|
2023-11-07 22:38:52 -05:00
|
|
|
if (count == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
head = ring_buffer_mask(b, b->head);
|
|
|
|
|
if (head + count <= ring_buffer_capacity(b)) {
|
2010-08-26 17:44:31 -04:00
|
|
|
memcpy(b->data + head, data, count);
|
|
|
|
|
} else {
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size = ring_buffer_capacity(b) - head;
|
2010-08-26 17:44:31 -04:00
|
|
|
memcpy(b->data + head, data, size);
|
|
|
|
|
memcpy(b->data, (const char *) data + size, count - size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b->head += count;
|
2014-04-17 18:20:37 +03:00
|
|
|
|
|
|
|
|
return 0;
|
2010-08-26 17:44:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
|
2010-08-26 17:44:31 -04:00
|
|
|
{
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size_t head, tail;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
head = ring_buffer_mask(b, b->head);
|
|
|
|
|
tail = ring_buffer_mask(b, b->tail);
|
2010-08-26 17:44:31 -04:00
|
|
|
if (head < tail) {
|
|
|
|
|
iov[0].iov_base = b->data + head;
|
|
|
|
|
iov[0].iov_len = tail - head;
|
|
|
|
|
*count = 1;
|
|
|
|
|
} else if (tail == 0) {
|
|
|
|
|
iov[0].iov_base = b->data + head;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
iov[0].iov_len = ring_buffer_capacity(b) - head;
|
2010-08-26 17:44:31 -04:00
|
|
|
*count = 1;
|
|
|
|
|
} else {
|
|
|
|
|
iov[0].iov_base = b->data + head;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
iov[0].iov_len = ring_buffer_capacity(b) - head;
|
2010-08-26 17:44:31 -04:00
|
|
|
iov[1].iov_base = b->data;
|
|
|
|
|
iov[1].iov_len = tail;
|
|
|
|
|
*count = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
|
2010-08-26 17:44:31 -04:00
|
|
|
{
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size_t head, tail;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
head = ring_buffer_mask(b, b->head);
|
|
|
|
|
tail = ring_buffer_mask(b, b->tail);
|
2010-08-26 17:44:31 -04:00
|
|
|
if (tail < head) {
|
|
|
|
|
iov[0].iov_base = b->data + tail;
|
|
|
|
|
iov[0].iov_len = head - tail;
|
|
|
|
|
*count = 1;
|
|
|
|
|
} else if (head == 0) {
|
|
|
|
|
iov[0].iov_base = b->data + tail;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
iov[0].iov_len = ring_buffer_capacity(b) - tail;
|
2010-08-26 17:44:31 -04:00
|
|
|
*count = 1;
|
|
|
|
|
} else {
|
|
|
|
|
iov[0].iov_base = b->data + tail;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
iov[0].iov_len = ring_buffer_capacity(b) - tail;
|
2010-08-26 17:44:31 -04:00
|
|
|
iov[1].iov_base = b->data;
|
|
|
|
|
iov[1].iov_len = head;
|
|
|
|
|
*count = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count)
|
2010-08-26 17:44:31 -04:00
|
|
|
{
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size_t tail, size;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
2023-11-07 22:38:52 -05:00
|
|
|
if (count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
tail = ring_buffer_mask(b, b->tail);
|
|
|
|
|
if (tail + count <= ring_buffer_capacity(b)) {
|
2010-08-26 17:44:31 -04:00
|
|
|
memcpy(data, b->data + tail, count);
|
|
|
|
|
} else {
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size = ring_buffer_capacity(b) - tail;
|
2010-08-26 17:44:31 -04:00
|
|
|
memcpy(data, b->data + tail, size);
|
|
|
|
|
memcpy((char *) data + size, b->data, count - size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
static size_t
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_size(struct wl_ring_buffer *b)
|
2012-03-23 00:48:19 -04:00
|
|
|
{
|
|
|
|
|
return b->head - b->tail;
|
|
|
|
|
}
|
|
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
static char *
|
|
|
|
|
ring_buffer_tail(const struct wl_ring_buffer *b)
|
|
|
|
|
{
|
|
|
|
|
return b->data + ring_buffer_mask(b, b->tail);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
|
get_max_size_bits_for_size(size_t buffer_size)
|
|
|
|
|
{
|
|
|
|
|
uint32_t max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
|
|
|
|
|
|
|
|
|
|
/* buffer_size == 0 means unbound buffer size */
|
|
|
|
|
if (buffer_size == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
while (max_size_bits < 8 * sizeof(size_t) && size_pot(max_size_bits) < buffer_size)
|
|
|
|
|
max_size_bits++;
|
|
|
|
|
|
|
|
|
|
return max_size_bits;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ring_buffer_allocate(struct wl_ring_buffer *b, size_t size_bits)
|
|
|
|
|
{
|
|
|
|
|
char *new_data;
|
|
|
|
|
|
|
|
|
|
new_data = calloc(size_pot(size_bits), 1);
|
|
|
|
|
if (!new_data)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
ring_buffer_copy(b, new_data, ring_buffer_size(b));
|
|
|
|
|
free(b->data);
|
|
|
|
|
b->data = new_data;
|
|
|
|
|
b->size_bits = size_bits;
|
|
|
|
|
b->head = ring_buffer_size(b);
|
|
|
|
|
b->tail = 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
|
ring_buffer_get_bits_for_size(struct wl_ring_buffer *b, size_t net_size)
|
|
|
|
|
{
|
|
|
|
|
size_t max_size_bits = get_max_size_bits_for_size(net_size);
|
|
|
|
|
|
|
|
|
|
if (max_size_bits < WL_BUFFER_DEFAULT_SIZE_POT)
|
|
|
|
|
max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
|
|
|
|
|
|
|
|
|
|
if (b->max_size_bits > 0 && max_size_bits > b->max_size_bits)
|
|
|
|
|
max_size_bits = b->max_size_bits;
|
|
|
|
|
|
|
|
|
|
return max_size_bits;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
ring_buffer_is_max_size_reached(struct wl_ring_buffer *b)
|
|
|
|
|
{
|
|
|
|
|
size_t net_size = ring_buffer_size(b) + 1;
|
|
|
|
|
size_t size_bits = ring_buffer_get_bits_for_size(b, net_size);
|
|
|
|
|
|
|
|
|
|
return net_size >= size_pot(size_bits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ring_buffer_ensure_space(struct wl_ring_buffer *b, size_t count)
|
|
|
|
|
{
|
|
|
|
|
size_t net_size = ring_buffer_size(b) + count;
|
|
|
|
|
size_t size_bits = ring_buffer_get_bits_for_size(b, net_size);
|
|
|
|
|
|
|
|
|
|
/* The 'size_bits' value represents the required size (in POT) to store
|
|
|
|
|
* 'net_size', which depending whether the buffers are bounded or not
|
|
|
|
|
* might not be sufficient (i.e. we might have reached the maximum size
|
|
|
|
|
* allowed).
|
|
|
|
|
*/
|
|
|
|
|
if (net_size > size_pot(size_bits)) {
|
|
|
|
|
wl_log("Data too big for buffer (%d + %zd > %zd).\n",
|
|
|
|
|
ring_buffer_size(b), count, size_pot(size_bits));
|
|
|
|
|
errno = E2BIG;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The following test here is a short-cut to avoid reallocating a buffer
|
|
|
|
|
* of the same size.
|
|
|
|
|
*/
|
|
|
|
|
if (size_bits == b->size_bits)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Otherwise, we (re)allocate the buffer to match the required size */
|
|
|
|
|
return ring_buffer_allocate(b, size_bits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ring_buffer_close_fds(struct wl_ring_buffer *buffer, int32_t count)
|
|
|
|
|
{
|
|
|
|
|
int32_t i, *p;
|
|
|
|
|
size_t size, tail;
|
|
|
|
|
|
|
|
|
|
size = ring_buffer_capacity(buffer);
|
|
|
|
|
tail = ring_buffer_mask(buffer, buffer->tail);
|
|
|
|
|
p = (int32_t *) (buffer->data + tail);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
if (p >= (int32_t *) (buffer->data + size))
|
|
|
|
|
p = (int32_t *) buffer->data;
|
|
|
|
|
close(*p++);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
wl_connection_set_max_buffer_size(struct wl_connection *connection,
|
|
|
|
|
size_t max_buffer_size)
|
|
|
|
|
{
|
|
|
|
|
uint32_t max_size_bits;
|
|
|
|
|
|
|
|
|
|
max_size_bits = get_max_size_bits_for_size(max_buffer_size);
|
|
|
|
|
|
|
|
|
|
connection->fds_in.max_size_bits = max_size_bits;
|
|
|
|
|
ring_buffer_ensure_space(&connection->fds_in, 0);
|
|
|
|
|
|
|
|
|
|
connection->fds_out.max_size_bits = max_size_bits;
|
|
|
|
|
ring_buffer_ensure_space(&connection->fds_out, 0);
|
|
|
|
|
|
|
|
|
|
connection->in.max_size_bits = max_size_bits;
|
|
|
|
|
ring_buffer_ensure_space(&connection->in, 0);
|
|
|
|
|
|
|
|
|
|
connection->out.max_size_bits = max_size_bits;
|
|
|
|
|
ring_buffer_ensure_space(&connection->out, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
struct wl_connection *
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
wl_connection_create(int fd, size_t max_buffer_size)
|
2008-10-08 12:48:46 -04:00
|
|
|
{
|
|
|
|
|
struct wl_connection *connection;
|
|
|
|
|
|
2015-08-26 12:00:06 +08:00
|
|
|
connection = zalloc(sizeof *connection);
|
2011-03-11 14:43:10 +02:00
|
|
|
if (connection == NULL)
|
|
|
|
|
return NULL;
|
2015-08-26 12:00:06 +08:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
wl_connection_set_max_buffer_size(connection, max_buffer_size);
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
connection->fd = fd;
|
|
|
|
|
|
|
|
|
|
return connection;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-11 23:37:45 +02:00
|
|
|
static void
|
2021-08-06 13:16:55 -05:00
|
|
|
close_fds(struct wl_ring_buffer *buffer, int max)
|
2012-10-11 23:37:45 +02:00
|
|
|
{
|
|
|
|
|
size_t size;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
int32_t count;
|
2012-10-11 23:37:45 +02:00
|
|
|
|
2021-08-06 13:16:55 -05:00
|
|
|
size = ring_buffer_size(buffer);
|
2012-10-11 23:37:45 +02:00
|
|
|
if (size == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
count = size / sizeof(int32_t);
|
2012-10-11 23:37:46 +02:00
|
|
|
if (max > 0 && max < count)
|
|
|
|
|
count = max;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
|
|
|
|
|
ring_buffer_close_fds(buffer, count);
|
|
|
|
|
|
|
|
|
|
size = count * sizeof(int32_t);
|
2012-10-11 23:37:45 +02:00
|
|
|
buffer->tail += size;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-06 11:22:23 -06:00
|
|
|
void
|
|
|
|
|
wl_connection_close_fds_in(struct wl_connection *connection, int max)
|
|
|
|
|
{
|
|
|
|
|
close_fds(&connection->fds_in, max);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-30 14:43:03 +02:00
|
|
|
int
|
2008-10-08 12:48:46 -04:00
|
|
|
wl_connection_destroy(struct wl_connection *connection)
|
|
|
|
|
{
|
2014-09-30 14:43:03 +02:00
|
|
|
int fd = connection->fd;
|
|
|
|
|
|
2012-10-11 23:37:46 +02:00
|
|
|
close_fds(&connection->fds_out, -1);
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
free(connection->fds_out.data);
|
|
|
|
|
free(connection->out.data);
|
|
|
|
|
|
2012-10-11 23:37:47 +02:00
|
|
|
close_fds(&connection->fds_in, -1);
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
free(connection->fds_in.data);
|
|
|
|
|
free(connection->in.data);
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
free(connection);
|
2014-09-30 14:43:03 +02:00
|
|
|
|
|
|
|
|
return fd;
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
|
|
|
|
|
{
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_copy(&connection->in, data, size);
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
wl_connection_consume(struct wl_connection *connection, size_t size)
|
|
|
|
|
{
|
2010-08-26 17:44:31 -04:00
|
|
|
connection->in.tail += size;
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
|
|
|
|
|
2010-08-26 21:49:44 -04:00
|
|
|
static void
|
2022-03-29 18:51:15 +02:00
|
|
|
build_cmsg(struct wl_ring_buffer *buffer, char *data, size_t *clen)
|
2010-08-26 21:49:44 -04:00
|
|
|
{
|
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
|
size_t size;
|
|
|
|
|
|
2021-08-06 13:16:55 -05:00
|
|
|
size = ring_buffer_size(buffer);
|
2012-10-11 23:37:48 +02:00
|
|
|
if (size > MAX_FDS_OUT * sizeof(int32_t))
|
|
|
|
|
size = MAX_FDS_OUT * sizeof(int32_t);
|
|
|
|
|
|
2010-08-26 21:49:44 -04:00
|
|
|
if (size > 0) {
|
|
|
|
|
cmsg = (struct cmsghdr *) data;
|
|
|
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
|
|
|
cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
|
|
cmsg->cmsg_len = CMSG_LEN(size);
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_copy(buffer, CMSG_DATA(cmsg), size);
|
2010-08-26 21:49:44 -04:00
|
|
|
*clen = cmsg->cmsg_len;
|
|
|
|
|
} else {
|
|
|
|
|
*clen = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-11 23:37:49 +02:00
|
|
|
static int
|
2021-08-06 13:16:55 -05:00
|
|
|
decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
|
2010-08-26 21:49:44 -04:00
|
|
|
{
|
|
|
|
|
struct cmsghdr *cmsg;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size_t size, i;
|
2012-10-11 23:37:49 +02:00
|
|
|
int overflow = 0;
|
2010-08-26 21:49:44 -04:00
|
|
|
|
|
|
|
|
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
|
|
|
|
|
cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
2012-10-11 23:37:49 +02:00
|
|
|
if (cmsg->cmsg_level != SOL_SOCKET ||
|
|
|
|
|
cmsg->cmsg_type != SCM_RIGHTS)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
size = cmsg->cmsg_len - CMSG_LEN(0);
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
|
|
|
|
|
if (ring_buffer_ensure_space(buffer, size) < 0 || overflow) {
|
2012-10-11 23:37:49 +02:00
|
|
|
overflow = 1;
|
|
|
|
|
size /= sizeof(int32_t);
|
2013-02-26 13:40:34 -05:00
|
|
|
for (i = 0; i < size; i++)
|
2012-10-11 23:37:49 +02:00
|
|
|
close(((int*)CMSG_DATA(cmsg))[i]);
|
2021-08-06 13:16:55 -05:00
|
|
|
} else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
|
2014-04-17 18:20:37 +03:00
|
|
|
return -1;
|
2010-08-26 21:49:44 -04:00
|
|
|
}
|
|
|
|
|
}
|
2012-10-11 23:37:49 +02:00
|
|
|
|
|
|
|
|
if (overflow) {
|
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2010-08-26 21:49:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2012-10-04 16:54:22 -04:00
|
|
|
wl_connection_flush(struct wl_connection *connection)
|
2008-10-08 12:48:46 -04:00
|
|
|
{
|
|
|
|
|
struct iovec iov[2];
|
2022-03-29 17:59:15 +02:00
|
|
|
struct msghdr msg = {0};
|
2012-03-09 12:51:42 +02:00
|
|
|
char cmsg[CLEN];
|
2022-03-29 18:51:15 +02:00
|
|
|
int len = 0, count;
|
|
|
|
|
size_t clen;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
size_t tail;
|
2012-10-04 16:54:22 -04:00
|
|
|
|
|
|
|
|
if (!connection->want_flush)
|
|
|
|
|
return 0;
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
tail = connection->out.tail;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
while (ring_buffer_size(&connection->out) > 0) {
|
2011-01-15 00:40:00 +01:00
|
|
|
build_cmsg(&connection->fds_out, cmsg, &clen);
|
2010-08-26 17:44:31 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
if (clen >= CLEN) {
|
|
|
|
|
/* UNIX domain sockets allows to send file descriptors
|
|
|
|
|
* using ancillary data.
|
|
|
|
|
*
|
|
|
|
|
* As per the UNIX domain sockets man page (man 7 unix),
|
|
|
|
|
* "at least one byte of real data should be sent when
|
|
|
|
|
* sending ancillary data".
|
|
|
|
|
*
|
|
|
|
|
* This is why we send only a single byte here, to ensure
|
|
|
|
|
* all file descriptors are sent before the bytes are
|
|
|
|
|
* cleared out.
|
|
|
|
|
*
|
|
|
|
|
* Otherwise This can fail to clear the file descriptors
|
|
|
|
|
* first if individual messages are allowed to have 224
|
|
|
|
|
* (8 bytes * MAX_FDS_OUT = 224) file descriptors .
|
|
|
|
|
*/
|
|
|
|
|
iov[0].iov_base = ring_buffer_tail(&connection->out);
|
|
|
|
|
iov[0].iov_len = 1;
|
|
|
|
|
count = 1;
|
|
|
|
|
} else {
|
|
|
|
|
ring_buffer_get_iov(&connection->out, iov, &count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg.msg_name = NULL;
|
|
|
|
|
msg.msg_namelen = 0;
|
2010-08-26 17:44:31 -04:00
|
|
|
msg.msg_iov = iov;
|
|
|
|
|
msg.msg_iovlen = count;
|
2014-11-03 09:49:03 +00:00
|
|
|
msg.msg_control = (clen > 0) ? cmsg : NULL;
|
2011-01-15 00:40:00 +01:00
|
|
|
msg.msg_controllen = clen;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
2008-12-09 10:47:36 -05:00
|
|
|
do {
|
2012-02-29 11:07:48 -05:00
|
|
|
len = sendmsg(connection->fd, &msg,
|
|
|
|
|
MSG_NOSIGNAL | MSG_DONTWAIT);
|
2012-10-04 16:54:22 -04:00
|
|
|
} while (len == -1 && errno == EINTR);
|
2010-08-26 17:44:31 -04:00
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
if (len == -1)
|
2011-01-29 13:12:39 +01:00
|
|
|
return -1;
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2012-10-11 23:37:46 +02:00
|
|
|
close_fds(&connection->fds_out, MAX_FDS_OUT);
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2011-01-15 00:40:00 +01:00
|
|
|
connection->out.tail += len;
|
|
|
|
|
}
|
2010-08-26 17:44:31 -04:00
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
connection->want_flush = 0;
|
2010-08-26 21:49:44 -04:00
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
return connection->out.head - tail;
|
|
|
|
|
}
|
2010-08-26 17:44:31 -04:00
|
|
|
|
2016-01-12 13:12:34 +09:00
|
|
|
uint32_t
|
|
|
|
|
wl_connection_pending_input(struct wl_connection *connection)
|
|
|
|
|
{
|
2021-08-06 13:16:55 -05:00
|
|
|
return ring_buffer_size(&connection->in);
|
2016-01-12 13:12:34 +09:00
|
|
|
}
|
|
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
int
|
|
|
|
|
wl_connection_read(struct wl_connection *connection)
|
|
|
|
|
{
|
|
|
|
|
struct iovec iov[2];
|
|
|
|
|
struct msghdr msg;
|
|
|
|
|
char cmsg[CLEN];
|
2012-10-11 23:37:49 +02:00
|
|
|
int len, count, ret;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
while (1) {
|
|
|
|
|
int data_size = ring_buffer_size(&connection->in);
|
2012-10-15 17:19:38 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
/* Stop once we've read the max buffer size. */
|
|
|
|
|
if (ring_buffer_is_max_size_reached(&connection->in))
|
|
|
|
|
return data_size;
|
2012-10-04 16:54:22 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
if (ring_buffer_ensure_space(&connection->in, 1) < 0)
|
|
|
|
|
return -1;
|
2008-10-08 12:48:46 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
ring_buffer_put_iov(&connection->in, iov, &count);
|
2010-08-26 21:49:44 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
msg.msg_name = NULL;
|
|
|
|
|
msg.msg_namelen = 0;
|
|
|
|
|
msg.msg_iov = iov;
|
|
|
|
|
msg.msg_iovlen = count;
|
|
|
|
|
msg.msg_control = cmsg;
|
|
|
|
|
msg.msg_controllen = sizeof cmsg;
|
|
|
|
|
msg.msg_flags = 0;
|
2012-10-04 16:54:22 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
do {
|
|
|
|
|
len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT);
|
|
|
|
|
} while (len < 0 && errno == EINTR);
|
|
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
/* EOF, return previously read data first */
|
|
|
|
|
return data_size;
|
|
|
|
|
}
|
|
|
|
|
if (len < 0) {
|
|
|
|
|
if (errno == EAGAIN && data_size > 0) {
|
|
|
|
|
/* nothing new read, return previously read data */
|
|
|
|
|
return data_size;
|
|
|
|
|
}
|
|
|
|
|
return len;
|
|
|
|
|
}
|
2012-10-04 16:54:22 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
ret = decode_cmsg(&connection->fds_in, &msg);
|
|
|
|
|
if (ret)
|
|
|
|
|
return -1;
|
2008-10-08 12:48:46 -04:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
connection->in.head += len;
|
|
|
|
|
}
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
|
|
|
|
|
2012-02-29 11:07:48 -05:00
|
|
|
int
|
2010-08-26 17:44:31 -04:00
|
|
|
wl_connection_write(struct wl_connection *connection,
|
|
|
|
|
const void *data, size_t count)
|
2008-10-08 12:48:46 -04:00
|
|
|
{
|
2022-02-28 08:54:47 -05:00
|
|
|
if (wl_connection_queue(connection, data, count) < 0)
|
2014-04-17 18:20:37 +03:00
|
|
|
return -1;
|
|
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
connection->want_flush = 1;
|
2012-02-29 11:07:48 -05:00
|
|
|
|
|
|
|
|
return 0;
|
2011-11-17 16:46:36 -05:00
|
|
|
}
|
|
|
|
|
|
2012-03-02 23:38:31 -05:00
|
|
|
int
|
2011-11-17 16:46:36 -05:00
|
|
|
wl_connection_queue(struct wl_connection *connection,
|
|
|
|
|
const void *data, size_t count)
|
|
|
|
|
{
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
/* We want to try to flush when the buffer reaches the default maximum
|
|
|
|
|
* size even if the buffer has been previously expanded.
|
|
|
|
|
*
|
|
|
|
|
* Otherwise the larger buffer will cause us to flush less frequently,
|
|
|
|
|
* which could increase lag.
|
|
|
|
|
*
|
|
|
|
|
* We'd like to flush often and get the buffer size back down if possible.
|
|
|
|
|
*/
|
|
|
|
|
if (ring_buffer_size(&connection->out) + count > WL_BUFFER_DEFAULT_MAX_SIZE) {
|
2012-10-04 16:54:22 -04:00
|
|
|
connection->want_flush = 1;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
if (wl_connection_flush(connection) < 0 && errno != EAGAIN)
|
2012-02-29 11:07:48 -05:00
|
|
|
return -1;
|
2012-10-04 16:54:22 -04:00
|
|
|
}
|
2011-11-17 16:46:36 -05:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
if (ring_buffer_ensure_space(&connection->out, count) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2021-08-06 13:16:55 -05:00
|
|
|
return ring_buffer_put(&connection->out, data, count);
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
2008-12-24 19:30:25 -05:00
|
|
|
|
2016-11-03 13:42:54 -07:00
|
|
|
int
|
2013-02-26 11:30:51 -05:00
|
|
|
wl_message_count_arrays(const struct wl_message *message)
|
2010-09-07 20:57:40 -04:00
|
|
|
{
|
2013-02-26 11:30:51 -05:00
|
|
|
int i, arrays;
|
2010-09-07 20:57:40 -04:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
for (i = 0, arrays = 0; message->signature[i]; i++) {
|
2024-03-06 19:08:53 +01:00
|
|
|
if (message->signature[i] == WL_ARG_ARRAY)
|
2013-02-26 13:40:34 -05:00
|
|
|
arrays++;
|
2010-09-07 20:57:40 -04:00
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
return arrays;
|
2010-09-07 20:57:40 -04:00
|
|
|
}
|
|
|
|
|
|
2016-01-14 16:03:43 +09:00
|
|
|
int
|
|
|
|
|
wl_connection_get_fd(struct wl_connection *connection)
|
|
|
|
|
{
|
|
|
|
|
return connection->fd;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-09 12:51:42 +02:00
|
|
|
static int
|
|
|
|
|
wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
|
|
|
|
|
{
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
if (ring_buffer_size(&connection->fds_out) >= MAX_FDS_OUT * sizeof fd) {
|
2012-10-04 16:54:22 -04:00
|
|
|
connection->want_flush = 1;
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
if (wl_connection_flush(connection) < 0 && errno != EAGAIN)
|
2012-03-09 12:51:42 +02:00
|
|
|
return -1;
|
2012-10-04 16:54:22 -04:00
|
|
|
}
|
2012-03-09 12:51:42 +02:00
|
|
|
|
connection: Dynamically resize connection buffers
When using fixed size connection buffers, if either the client or the
server is sending requests faster than the other end can cope with, the
connection buffers will fill up, eventually killing the connection.
This can be a problem for example with Xwayland mapping a lot of
windows, faster than the Wayland compositor can cope with, or a
high-rate mouse flooding the Wayland client with pointer events.
To avoid the issue, resize the connection buffers dynamically when they
get full.
Both data and fd buffers are resized on demand.
The default max buffer size is controlled via the wl_display interface
while each client's connection buffer size is adjustable for finer
control.
The purpose is to explicitly have larger connection buffers for specific
clients such as Xwayland, or set a larger buffer size for the client
with pointer focus to deal with a higher input events rate.
v0: Manuel:
Dynamically resize connection buffers - Both data and fd buffers are
resized on demand.
v1: Olivier
1. Add support for unbounded buffers on the client side and growable
(yet limited) connection buffers on the server side.
2. Add the API to set the default maximum size and a limit for a given
client.
3. Add tests for growable connection buffers and adjustable limits.
v2: Additional fixes by John:
1. Fix the size calculation in ring_buffer_check_space()
2. Fix wl_connection_read() to return gracefully once it has read up to
the max buffer size, rather than returning an error.
3. If wl_connection_flush() fails with EAGAIN but the transmit
ring-buffer has space remaining (or can be expanded),
wl_connection_queue() should store the message rather than
returning an error.
4. When the receive ring-buffer is at capacity but more data is
available to be read, wl_connection_read() should attempt to
expand the ring-buffer in order to read the remaining data.
v3: Thomas Lukaszewicz <tluk@chromium.org>
Add a test for unbounded buffers
v4: Add a client API as well to force bounded buffers (unbounded
by default (Olivier)
v5: Simplify ring_buffer_ensure_space() (Sebastian)
Co-authored-by: Olivier Fourdan <ofourdan@redhat.com>
Co-authored-by: John Lindgren <john@jlindgren.net>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: John Lindgren <john@jlindgren.net>
Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
Closes: https://gitlab.freedesktop.org/wayland/wayland/-/issues/237
2021-09-25 22:34:44 -04:00
|
|
|
if (ring_buffer_ensure_space(&connection->fds_out, sizeof fd) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2021-08-06 13:16:55 -05:00
|
|
|
return ring_buffer_put(&connection->fds_out, &fd, sizeof fd);
|
2012-03-09 12:51:42 +02:00
|
|
|
}
|
|
|
|
|
|
2012-07-23 19:54:40 +01:00
|
|
|
const char *
|
2012-07-02 20:03:30 +10:00
|
|
|
get_next_argument(const char *signature, struct argument_details *details)
|
|
|
|
|
{
|
2013-06-27 20:09:19 -05:00
|
|
|
details->nullable = 0;
|
|
|
|
|
for(; *signature; ++signature) {
|
|
|
|
|
switch(*signature) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_INT:
|
|
|
|
|
case WL_ARG_UINT:
|
|
|
|
|
case WL_ARG_FIXED:
|
|
|
|
|
case WL_ARG_STRING:
|
|
|
|
|
case WL_ARG_OBJECT:
|
|
|
|
|
case WL_ARG_NEW_ID:
|
|
|
|
|
case WL_ARG_ARRAY:
|
|
|
|
|
case WL_ARG_FD:
|
2013-06-27 20:09:19 -05:00
|
|
|
details->type = *signature;
|
|
|
|
|
return signature + 1;
|
|
|
|
|
case '?':
|
|
|
|
|
details->nullable = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-07-10 23:40:56 +02:00
|
|
|
details->type = '\0';
|
2013-06-27 20:09:19 -05:00
|
|
|
return signature;
|
2012-07-02 20:03:30 +10:00
|
|
|
}
|
|
|
|
|
|
2012-07-23 19:54:40 +01:00
|
|
|
int
|
2012-07-02 20:03:30 +10:00
|
|
|
arg_count_for_signature(const char *signature)
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
2013-06-27 20:09:19 -05:00
|
|
|
for(; *signature; ++signature) {
|
|
|
|
|
switch(*signature) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_INT:
|
|
|
|
|
case WL_ARG_UINT:
|
|
|
|
|
case WL_ARG_FIXED:
|
|
|
|
|
case WL_ARG_STRING:
|
|
|
|
|
case WL_ARG_OBJECT:
|
|
|
|
|
case WL_ARG_NEW_ID:
|
|
|
|
|
case WL_ARG_ARRAY:
|
|
|
|
|
case WL_ARG_FD:
|
2013-06-27 20:09:19 -05:00
|
|
|
++count;
|
|
|
|
|
}
|
2012-07-02 20:03:30 +10:00
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 20:09:19 -05:00
|
|
|
int
|
|
|
|
|
wl_message_get_since(const struct wl_message *message)
|
|
|
|
|
{
|
|
|
|
|
int since;
|
|
|
|
|
|
|
|
|
|
since = atoi(message->signature);
|
|
|
|
|
|
|
|
|
|
if (since == 0)
|
|
|
|
|
since = 1;
|
|
|
|
|
|
|
|
|
|
return since;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
void
|
|
|
|
|
wl_argument_from_va_list(const char *signature, union wl_argument *args,
|
|
|
|
|
int count, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
const char *sig_iter;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
|
|
|
|
|
sig_iter = signature;
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
sig_iter = get_next_argument(sig_iter, &arg);
|
|
|
|
|
|
|
|
|
|
switch(arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_INT:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].i = va_arg(ap, int32_t);
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_UINT:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].u = va_arg(ap, uint32_t);
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FIXED:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].f = va_arg(ap, wl_fixed_t);
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_STRING:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].s = va_arg(ap, const char *);
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_OBJECT:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].o = va_arg(ap, struct wl_object *);
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_NEW_ID:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].o = va_arg(ap, struct wl_object *);
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_ARRAY:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].a = va_arg(ap, struct wl_array *);
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FD:
|
2013-02-26 11:30:51 -05:00
|
|
|
args[i].h = va_arg(ap, int32_t);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-06 11:22:19 -06:00
|
|
|
static void
|
|
|
|
|
wl_closure_clear_fds(struct wl_closure *closure)
|
|
|
|
|
{
|
2018-01-19 15:20:31 -06:00
|
|
|
const char *signature = closure->message->signature;
|
|
|
|
|
struct argument_details arg;
|
2017-12-06 11:22:19 -06:00
|
|
|
int i;
|
|
|
|
|
|
2018-01-19 15:20:31 -06:00
|
|
|
for (i = 0; i < closure->count; i++) {
|
|
|
|
|
signature = get_next_argument(signature, &arg);
|
2024-02-15 10:37:34 +01:00
|
|
|
if (arg.type == WL_ARG_FD)
|
2017-12-06 11:22:19 -06:00
|
|
|
closure->args[i].h = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-06 11:22:18 -06:00
|
|
|
static struct wl_closure *
|
|
|
|
|
wl_closure_init(const struct wl_message *message, uint32_t size,
|
|
|
|
|
int *num_arrays, union wl_argument *args)
|
2008-12-24 19:30:25 -05:00
|
|
|
{
|
2012-06-12 17:45:25 -04:00
|
|
|
struct wl_closure *closure;
|
2017-12-06 11:22:18 -06:00
|
|
|
int count;
|
2008-12-24 19:30:25 -05:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
count = arg_count_for_signature(message->signature);
|
|
|
|
|
if (count > WL_CLOSURE_MAX_ARGS) {
|
2022-09-29 23:39:40 +00:00
|
|
|
wl_log("too many args (%d) for %s (signature %s)\n", count,
|
|
|
|
|
message->name, message->signature);
|
2013-02-26 11:30:51 -05:00
|
|
|
errno = EINVAL;
|
2012-06-12 17:45:25 -04:00
|
|
|
return NULL;
|
2013-02-26 11:30:51 -05:00
|
|
|
}
|
2012-06-12 17:45:25 -04:00
|
|
|
|
2022-09-29 23:39:40 +00:00
|
|
|
int size_to_allocate;
|
|
|
|
|
|
2017-12-06 11:22:18 -06:00
|
|
|
if (size) {
|
|
|
|
|
*num_arrays = wl_message_count_arrays(message);
|
2022-09-29 23:39:40 +00:00
|
|
|
size_to_allocate = sizeof *closure + size +
|
|
|
|
|
*num_arrays * sizeof(struct wl_array);
|
2017-12-06 11:22:18 -06:00
|
|
|
} else {
|
2022-09-29 23:39:40 +00:00
|
|
|
size_to_allocate = sizeof *closure;
|
2017-12-06 11:22:18 -06:00
|
|
|
}
|
2022-09-29 23:39:40 +00:00
|
|
|
closure = zalloc(size_to_allocate);
|
2017-12-06 11:22:18 -06:00
|
|
|
|
|
|
|
|
if (!closure) {
|
2022-09-29 23:39:40 +00:00
|
|
|
wl_log("could not allocate closure of size (%d) for "
|
|
|
|
|
"%s (signature %s)\n", size_to_allocate, message->name,
|
|
|
|
|
message->signature);
|
2013-02-26 11:30:51 -05:00
|
|
|
errno = ENOMEM;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-12-16 10:29:36 +02:00
|
|
|
|
2017-12-06 11:22:18 -06:00
|
|
|
if (args)
|
|
|
|
|
memcpy(closure->args, args, count * sizeof *args);
|
|
|
|
|
|
|
|
|
|
closure->message = message;
|
|
|
|
|
closure->count = count;
|
|
|
|
|
|
2017-12-06 11:22:19 -06:00
|
|
|
/* Set these all to -1 so we can close any that have been
|
|
|
|
|
* set to a real value during wl_closure_destroy().
|
|
|
|
|
* We may have copied a bunch of fds into the closure with
|
|
|
|
|
* memcpy previously, but those are undup()d client fds
|
|
|
|
|
* that we would have replaced anyway.
|
|
|
|
|
*/
|
|
|
|
|
wl_closure_clear_fds(closure);
|
|
|
|
|
|
2017-12-06 11:22:18 -06:00
|
|
|
return closure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct wl_closure *
|
|
|
|
|
wl_closure_marshal(struct wl_object *sender, uint32_t opcode,
|
|
|
|
|
union wl_argument *args,
|
|
|
|
|
const struct wl_message *message)
|
|
|
|
|
{
|
|
|
|
|
struct wl_closure *closure;
|
|
|
|
|
struct wl_object *object;
|
|
|
|
|
int i, count, fd, dup_fd;
|
|
|
|
|
const char *signature;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
|
|
|
|
|
closure = wl_closure_init(message, 0, NULL, args);
|
|
|
|
|
if (closure == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
count = closure->count;
|
2012-04-22 14:16:08 -04:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
signature = message->signature;
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2012-07-02 20:03:30 +10:00
|
|
|
signature = get_next_argument(signature, &arg);
|
|
|
|
|
|
|
|
|
|
switch (arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FIXED:
|
|
|
|
|
case WL_ARG_UINT:
|
|
|
|
|
case WL_ARG_INT:
|
2010-09-07 17:03:17 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_STRING:
|
2013-02-26 13:40:34 -05:00
|
|
|
if (!arg.nullable && args[i].s == NULL)
|
2012-07-02 20:03:30 +10:00
|
|
|
goto err_null;
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_OBJECT:
|
2013-02-26 13:40:34 -05:00
|
|
|
if (!arg.nullable && args[i].o == NULL)
|
2012-07-02 20:03:30 +10:00
|
|
|
goto err_null;
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_NEW_ID:
|
2013-02-26 11:30:51 -05:00
|
|
|
object = args[i].o;
|
2022-07-14 08:36:21 -07:00
|
|
|
if (object == NULL)
|
2012-07-23 19:54:41 +01:00
|
|
|
goto err_null;
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].n = object ? object->id : 0;
|
2010-09-07 20:57:40 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_ARRAY:
|
2022-07-12 09:12:33 -07:00
|
|
|
if (args[i].a == NULL)
|
2012-07-02 20:03:30 +10:00
|
|
|
goto err_null;
|
2009-02-23 22:30:29 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FD:
|
2013-02-26 11:30:51 -05:00
|
|
|
fd = args[i].h;
|
2012-04-23 13:55:55 +03:00
|
|
|
dup_fd = wl_os_dupfd_cloexec(fd, 0);
|
2019-07-05 19:48:18 -04:00
|
|
|
if (dup_fd < 0) {
|
|
|
|
|
wl_closure_destroy(closure);
|
|
|
|
|
wl_log("error marshalling arguments for %s: dup failed: %s\n",
|
|
|
|
|
message->name, strerror(errno));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].h = dup_fd;
|
2010-08-26 21:49:44 -04:00
|
|
|
break;
|
2008-12-24 19:30:25 -05:00
|
|
|
default:
|
2015-11-16 11:49:02 +01:00
|
|
|
wl_abort("unhandled format code: '%c'\n", arg.type);
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->sender_id = sender->id;
|
|
|
|
|
closure->opcode = opcode;
|
2010-09-07 21:34:45 -04:00
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
return closure;
|
2011-12-16 10:29:36 +02:00
|
|
|
|
2012-07-02 20:03:30 +10:00
|
|
|
err_null:
|
2013-02-26 11:30:51 -05:00
|
|
|
wl_closure_destroy(closure);
|
|
|
|
|
wl_log("error marshalling arguments for %s (signature %s): "
|
|
|
|
|
"null value passed for arg %i\n", message->name,
|
2012-07-02 20:03:30 +10:00
|
|
|
message->signature, i);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return NULL;
|
2010-09-07 17:00:34 -04:00
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
struct wl_closure *
|
|
|
|
|
wl_closure_vmarshal(struct wl_object *sender, uint32_t opcode, va_list ap,
|
|
|
|
|
const struct wl_message *message)
|
|
|
|
|
{
|
|
|
|
|
union wl_argument args[WL_CLOSURE_MAX_ARGS];
|
|
|
|
|
|
|
|
|
|
wl_argument_from_va_list(message->signature, args,
|
|
|
|
|
WL_CLOSURE_MAX_ARGS, ap);
|
|
|
|
|
|
|
|
|
|
return wl_closure_marshal(sender, opcode, args, message);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-26 20:19:30 -04:00
|
|
|
/*
|
|
|
|
|
* Check that the provided NUL-terminated string is valid UTF-8. Returns a
|
|
|
|
|
* pointer to the byte _after_ the terminating NUL, or NULL if invalid UTF-8
|
|
|
|
|
* is found first.
|
|
|
|
|
*/
|
|
|
|
|
static const unsigned char *
|
|
|
|
|
wayland_string_validate(const unsigned char *const s,
|
|
|
|
|
const struct wl_message *const message)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *p = s;
|
|
|
|
|
unsigned char first, b;
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
bool okay;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Many strings are ASCII, so handle them in a fast path.
|
|
|
|
|
* This loop skips all non-NUL ASCII characters.
|
|
|
|
|
*/
|
|
|
|
|
do {
|
|
|
|
|
first = *p++;
|
|
|
|
|
} while (first > 0 && first < 0x80);
|
|
|
|
|
|
|
|
|
|
if (first == 0x0)
|
|
|
|
|
return p;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Validate that the string is well-formed UTF-8.
|
|
|
|
|
* ASCII bytes have already been checked for. Start by rejecting the
|
|
|
|
|
* following values, which are not valid as the start of a multibyte UTF-8
|
|
|
|
|
* sequence.
|
|
|
|
|
*
|
|
|
|
|
* 0x80 ... 0xBF: 0b10xxxxxx, continuation bytes.
|
|
|
|
|
* 0xC0 ... 0xC1: 0b1100000x 0b10xxxxxx, overlong encoding of 0x0 ... 0x7F.
|
|
|
|
|
* 0xF5 ... 0xF7: 0b111101xx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx where at least
|
|
|
|
|
* one of the first two "x" bits is set. This corresponds
|
|
|
|
|
* to 0b1 xxxx xxxx xxxx xxxx xxxx with at least one of the
|
|
|
|
|
* first two "x" bits set, or 0x140000 ... 0x1FFFFF. These
|
|
|
|
|
* all exceed 0x10FFFF, the largest Unicode code point.
|
|
|
|
|
* 0xF8 ... 0xFF: These are of the form 0b11111xxx. They
|
|
|
|
|
* correspond to 5-, 6-, 7-, or 8-byte encodings,
|
|
|
|
|
* which are all invalid: every code point can be expressed
|
|
|
|
|
* in at most 4 bytes, so longer encodings are either
|
|
|
|
|
* overlong or exceed the 0x10FFFF limit.
|
|
|
|
|
*/
|
|
|
|
|
if (first < 0xC2 || first > 0xF4) {
|
|
|
|
|
wl_log("string has invalid UTF-8 start byte 0x%hhx "
|
|
|
|
|
"at offset %td, message %s(%s)\n", first, p - s,
|
|
|
|
|
message->name, message->signature);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
b = *p++;
|
|
|
|
|
switch (first) {
|
|
|
|
|
case 0xe0:
|
|
|
|
|
/*
|
|
|
|
|
* 3-byte encoding of form 0b11100000 0b10xxxxxx 0b10xxxxxx.
|
|
|
|
|
* The greatest 2-byte encoding is 0b11011111 0b10111111 or
|
|
|
|
|
* 0b011111111111, which is 0x7FF. Therefore, for the encoding
|
|
|
|
|
* to not be overlong, the first "x" bit must be set.
|
|
|
|
|
*/
|
|
|
|
|
okay = (b >= 0xa0 && b <= 0xbf);
|
|
|
|
|
break;
|
|
|
|
|
case 0xed:
|
|
|
|
|
/*
|
|
|
|
|
* 3-byte encoding of form 0b11101101 0b10xxxxxx 0b10xxxxxx,
|
|
|
|
|
* or 0xDxxx. Values in the range 0xD800 ... 0xDFFF are surrogates,
|
|
|
|
|
* which are not valid Unicode code points. Therefore, only values
|
|
|
|
|
* in the range 0xD000 ... 0xD7FF are permitted, meaning that the
|
|
|
|
|
* first "x" bit must be clear.
|
|
|
|
|
*/
|
|
|
|
|
okay = (b >= 0x80 && b <= 0x9f);
|
|
|
|
|
break;
|
|
|
|
|
case 0xf0:
|
|
|
|
|
/*
|
|
|
|
|
* 4-byte encoding of form 0b11110000 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx.
|
|
|
|
|
* The greatest 3-byte encoding is 0b11101111 0b10111111 0b10111111 or
|
|
|
|
|
* 0b001111 111111 111111, which is 0xFFFF. Therefore, for the encoding
|
|
|
|
|
* to not be overlong, the first continuation byte must be at least
|
|
|
|
|
* 0b10010000, or 0x90.
|
|
|
|
|
*/
|
|
|
|
|
okay = (b >= 0x90 && b <= 0xbf);
|
|
|
|
|
break;
|
|
|
|
|
case 0xf4:
|
|
|
|
|
/*
|
|
|
|
|
* 4-byte encoding of form 0b11110100 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx.
|
|
|
|
|
* The largest Unicode code point is 0x10FFFF, encoded as
|
|
|
|
|
* 0b11110100 0b10001111 0b10111111 0b10111111. Therefore,
|
|
|
|
|
* the first continuation byte must not exceed 0b10001111,
|
|
|
|
|
* or 0x8F.
|
|
|
|
|
*/
|
|
|
|
|
okay = (b >= 0x80 && b <= 0x8F);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Default range is 0x80 to 0xBF */
|
|
|
|
|
okay = (b >= 0x80 && b <= 0xBF);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!okay)
|
|
|
|
|
break; /* invalid */
|
|
|
|
|
if (first < 0xE0)
|
|
|
|
|
continue; /* 2 byte */
|
|
|
|
|
b = *p++;
|
|
|
|
|
if (b < 0x80 || b > 0xBF)
|
|
|
|
|
break; /* invalid */
|
|
|
|
|
if (first < 0xF0)
|
|
|
|
|
continue; /* 3 bytes */
|
|
|
|
|
b = *p++;
|
|
|
|
|
if (b < 0x80 || b > 0xBF)
|
|
|
|
|
break; /* invalid */
|
|
|
|
|
/* valid 4 byte */
|
|
|
|
|
}
|
|
|
|
|
wl_log("string has invalid UTF-8 continuation byte 0x%hhx "
|
|
|
|
|
"at offset %td, message %s(%s)\n", b, p - s,
|
|
|
|
|
message->name, message->signature);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
struct wl_closure *
|
2008-12-24 19:30:25 -05:00
|
|
|
wl_connection_demarshal(struct wl_connection *connection,
|
|
|
|
|
uint32_t size,
|
2011-08-19 22:50:53 -04:00
|
|
|
struct wl_map *objects,
|
2008-12-24 19:30:25 -05:00
|
|
|
const struct wl_message *message)
|
|
|
|
|
{
|
2018-08-14 13:07:53 +02:00
|
|
|
uint32_t *p, *next, *end, length, length_in_u32, id;
|
2013-02-26 11:30:51 -05:00
|
|
|
int fd;
|
2024-08-26 20:19:30 -04:00
|
|
|
const unsigned char *s, *str_end;
|
2017-12-06 11:22:18 -06:00
|
|
|
int i, count, num_arrays;
|
2013-02-26 11:30:51 -05:00
|
|
|
const char *signature;
|
2012-07-02 20:03:30 +10:00
|
|
|
struct argument_details arg;
|
2012-06-12 17:45:25 -04:00
|
|
|
struct wl_closure *closure;
|
2017-12-06 11:22:16 -06:00
|
|
|
struct wl_array *array_extra;
|
2008-12-24 19:30:25 -05:00
|
|
|
|
2019-03-06 13:42:23 +02:00
|
|
|
/* Space for sender_id and opcode */
|
|
|
|
|
if (size < 2 * sizeof *p) {
|
|
|
|
|
wl_log("message too short, invalid header\n");
|
|
|
|
|
wl_connection_consume(connection, size);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-06 11:22:18 -06:00
|
|
|
closure = wl_closure_init(message, size, &num_arrays, NULL);
|
2013-02-26 11:30:51 -05:00
|
|
|
if (closure == NULL) {
|
|
|
|
|
wl_connection_consume(connection, size);
|
2012-06-12 17:45:25 -04:00
|
|
|
return NULL;
|
2013-02-26 11:30:51 -05:00
|
|
|
}
|
2008-12-24 19:30:25 -05:00
|
|
|
|
2017-12-06 11:22:18 -06:00
|
|
|
count = closure->count;
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
array_extra = closure->extra;
|
|
|
|
|
p = (uint32_t *)(closure->extra + num_arrays);
|
|
|
|
|
end = p + size / sizeof *p;
|
|
|
|
|
|
|
|
|
|
wl_connection_copy(connection, p, size);
|
|
|
|
|
closure->sender_id = *p++;
|
|
|
|
|
closure->opcode = *p++ & 0x0000ffff;
|
|
|
|
|
|
|
|
|
|
signature = message->signature;
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2012-07-02 20:03:30 +10:00
|
|
|
signature = get_next_argument(signature, &arg);
|
|
|
|
|
|
2024-07-24 21:18:40 -04:00
|
|
|
if (arg.type != WL_ARG_FD && p >= end) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("message too short, "
|
2010-08-09 14:34:11 -04:00
|
|
|
"object (%d), message %s(%s)\n",
|
2018-02-14 12:15:11 -06:00
|
|
|
closure->sender_id, message->name,
|
|
|
|
|
message->signature);
|
2010-08-09 14:34:11 -04:00
|
|
|
errno = EINVAL;
|
2010-08-30 09:47:36 -04:00
|
|
|
goto err;
|
2010-08-09 14:34:11 -04:00
|
|
|
}
|
|
|
|
|
|
2012-07-02 20:03:30 +10:00
|
|
|
switch (arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_UINT:
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].u = *p++;
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_INT:
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].i = *p++;
|
2010-09-07 17:03:17 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FIXED:
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].f = *p++;
|
2012-05-08 17:17:25 +01:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_STRING:
|
2008-12-24 19:30:25 -05:00
|
|
|
length = *p++;
|
2010-08-09 14:34:11 -04:00
|
|
|
|
2021-06-22 19:31:26 +10:00
|
|
|
if (length == 0 && !arg.nullable) {
|
|
|
|
|
wl_log("NULL string received on non-nullable "
|
|
|
|
|
"type, message %s(%s)\n", message->name,
|
|
|
|
|
message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
2013-02-26 11:30:51 -05:00
|
|
|
if (length == 0) {
|
|
|
|
|
closure->args[i].s = NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-14 13:07:53 +02:00
|
|
|
length_in_u32 = div_roundup(length, sizeof *p);
|
|
|
|
|
if ((uint32_t) (end - p) < length_in_u32) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("message too short, "
|
2010-08-09 14:34:11 -04:00
|
|
|
"object (%d), message %s(%s)\n",
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->sender_id, message->name,
|
|
|
|
|
message->signature);
|
2010-08-09 14:34:11 -04:00
|
|
|
errno = EINVAL;
|
2010-08-30 09:47:36 -04:00
|
|
|
goto err;
|
2010-08-09 14:34:11 -04:00
|
|
|
}
|
2018-08-14 13:07:53 +02:00
|
|
|
next = p + length_in_u32;
|
2010-08-09 14:34:11 -04:00
|
|
|
|
2024-08-26 20:19:30 -04:00
|
|
|
s = (const unsigned char *)p;
|
2010-09-07 17:00:34 -04:00
|
|
|
|
2024-07-24 21:20:12 -04:00
|
|
|
if (s[length - 1] != '\0') {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("string not nul-terminated, "
|
2010-09-07 17:00:34 -04:00
|
|
|
"message %s(%s)\n",
|
|
|
|
|
message->name, message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
goto err;
|
2008-12-24 19:30:25 -05:00
|
|
|
}
|
2013-02-26 11:30:51 -05:00
|
|
|
|
2024-08-26 20:19:30 -04:00
|
|
|
str_end = wayland_string_validate(s, message);
|
|
|
|
|
if (str_end != (const unsigned char *)p + length) {
|
|
|
|
|
if (str_end != NULL) {
|
|
|
|
|
/* NUL byte before end of string */
|
|
|
|
|
wl_log("string has embedded nul at offset %td, "
|
|
|
|
|
"message %s(%s)\n", str_end - s,
|
|
|
|
|
message->name, message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
} else {
|
|
|
|
|
/* Invalid UTF-8 */
|
|
|
|
|
errno = EILSEQ;
|
|
|
|
|
}
|
2024-07-24 21:20:12 -04:00
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-26 20:19:30 -04:00
|
|
|
closure->args[i].s = (const char *)s;
|
2010-08-09 14:34:11 -04:00
|
|
|
p = next;
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_OBJECT:
|
2013-02-26 11:30:51 -05:00
|
|
|
id = *p++;
|
|
|
|
|
closure->args[i].n = id;
|
|
|
|
|
|
|
|
|
|
if (id == 0 && !arg.nullable) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("NULL object received on non-nullable "
|
2012-07-23 19:54:41 +01:00
|
|
|
"type, message %s(%s)\n", message->name,
|
|
|
|
|
message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_NEW_ID:
|
2013-02-26 11:30:51 -05:00
|
|
|
id = *p++;
|
|
|
|
|
closure->args[i].n = id;
|
|
|
|
|
|
2022-07-14 08:36:21 -07:00
|
|
|
if (id == 0) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("NULL new ID received on non-nullable "
|
2012-07-23 19:54:41 +01:00
|
|
|
"type, message %s(%s)\n", message->name,
|
|
|
|
|
message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
if (wl_map_reserve_new(objects, id) < 0) {
|
2022-02-09 04:10:42 +06:00
|
|
|
if (errno == EINVAL) {
|
|
|
|
|
wl_log("not a valid new object id (%u), "
|
|
|
|
|
"message %s(%s)\n", id,
|
|
|
|
|
message->name,
|
|
|
|
|
message->signature);
|
|
|
|
|
}
|
2010-08-30 09:47:36 -04:00
|
|
|
goto err;
|
2010-08-09 14:34:11 -04:00
|
|
|
}
|
2012-07-18 15:53:23 +02:00
|
|
|
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_ARRAY:
|
2009-02-23 22:30:29 -05:00
|
|
|
length = *p++;
|
2010-08-09 14:34:11 -04:00
|
|
|
|
2018-08-14 13:07:53 +02:00
|
|
|
length_in_u32 = div_roundup(length, sizeof *p);
|
|
|
|
|
if ((uint32_t) (end - p) < length_in_u32) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("message too short, "
|
2010-08-09 14:34:11 -04:00
|
|
|
"object (%d), message %s(%s)\n",
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->sender_id, message->name,
|
|
|
|
|
message->signature);
|
2010-08-09 14:34:11 -04:00
|
|
|
errno = EINVAL;
|
2010-08-30 09:47:36 -04:00
|
|
|
goto err;
|
2010-08-09 14:34:11 -04:00
|
|
|
}
|
2018-08-14 13:07:53 +02:00
|
|
|
next = p + length_in_u32;
|
2010-08-09 14:34:11 -04:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
array_extra->size = length;
|
|
|
|
|
array_extra->alloc = 0;
|
|
|
|
|
array_extra->data = p;
|
2010-09-07 17:00:34 -04:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].a = array_extra++;
|
2010-08-09 14:34:11 -04:00
|
|
|
p = next;
|
2009-02-23 22:30:29 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FD:
|
2013-11-16 14:31:03 +01:00
|
|
|
if (connection->fds_in.tail == connection->fds_in.head) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("file descriptor expected, "
|
2013-11-16 14:31:03 +01:00
|
|
|
"object (%d), message %s(%s)\n",
|
|
|
|
|
closure->sender_id, message->name,
|
|
|
|
|
message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-06 13:16:55 -05:00
|
|
|
ring_buffer_copy(&connection->fds_in, &fd, sizeof fd);
|
2013-02-26 11:30:51 -05:00
|
|
|
connection->fds_in.tail += sizeof fd;
|
|
|
|
|
closure->args[i].h = fd;
|
2010-08-26 21:49:44 -04:00
|
|
|
break;
|
2008-12-24 19:30:25 -05:00
|
|
|
default:
|
2015-11-16 11:49:02 +01:00
|
|
|
wl_abort("unknown type\n");
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-30 09:47:36 -04:00
|
|
|
wl_connection_consume(connection, size);
|
2010-08-26 21:49:44 -04:00
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
return closure;
|
2010-08-30 09:47:36 -04:00
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
wl_closure_destroy(closure);
|
2011-01-26 11:46:35 -05:00
|
|
|
wl_connection_consume(connection, size);
|
2010-08-30 09:47:36 -04:00
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
return NULL;
|
2010-08-30 09:47:36 -04:00
|
|
|
}
|
|
|
|
|
|
2017-12-28 15:15:46 +00:00
|
|
|
bool
|
|
|
|
|
wl_object_is_zombie(struct wl_map *map, uint32_t id)
|
|
|
|
|
{
|
2017-12-28 15:22:25 +00:00
|
|
|
uint32_t flags;
|
2017-12-28 15:15:46 +00:00
|
|
|
|
2017-12-28 15:22:25 +00:00
|
|
|
/* Zombie objects only exist on the client side. */
|
|
|
|
|
if (map->side == WL_MAP_SERVER_SIDE)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* Zombie objects can only have been created by the client. */
|
|
|
|
|
if (id >= WL_SERVER_ID_START)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
flags = wl_map_lookup_flags(map, id);
|
|
|
|
|
return !!(flags & WL_MAP_ENTRY_ZOMBIE);
|
2017-12-28 15:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
2012-10-09 12:14:34 -04:00
|
|
|
int
|
|
|
|
|
wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
|
|
|
|
|
{
|
2013-02-26 11:30:51 -05:00
|
|
|
struct wl_object *object;
|
2012-10-09 12:14:34 -04:00
|
|
|
const struct wl_message *message;
|
|
|
|
|
const char *signature;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
int i, count;
|
|
|
|
|
uint32_t id;
|
|
|
|
|
|
|
|
|
|
message = closure->message;
|
|
|
|
|
signature = message->signature;
|
2013-02-26 11:30:51 -05:00
|
|
|
count = arg_count_for_signature(signature);
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2012-10-09 12:14:34 -04:00
|
|
|
signature = get_next_argument(signature, &arg);
|
2024-02-27 12:23:34 +01:00
|
|
|
if (arg.type != WL_ARG_OBJECT)
|
|
|
|
|
continue;
|
2012-10-09 12:14:34 -04:00
|
|
|
|
2024-02-27 12:23:34 +01:00
|
|
|
id = closure->args[i].n;
|
|
|
|
|
closure->args[i].o = NULL;
|
|
|
|
|
|
|
|
|
|
object = wl_map_lookup(objects, id);
|
|
|
|
|
if (wl_object_is_zombie(objects, id)) {
|
|
|
|
|
/* references object we've already
|
|
|
|
|
* destroyed client side */
|
|
|
|
|
object = NULL;
|
|
|
|
|
} else if (object == NULL && id != 0) {
|
|
|
|
|
wl_log("unknown object (%u), message %s(%s)\n",
|
|
|
|
|
id, message->name, message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (object != NULL && message->types[i] != NULL &&
|
|
|
|
|
!wl_interface_equal((object)->interface,
|
|
|
|
|
message->types[i])) {
|
|
|
|
|
wl_log("invalid object (%u), type (%s), "
|
|
|
|
|
"message %s(%s)\n",
|
|
|
|
|
id, (object)->interface->name,
|
|
|
|
|
message->name, message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
2012-10-09 12:14:34 -04:00
|
|
|
}
|
2024-02-27 12:23:34 +01:00
|
|
|
closure->args[i].o = object;
|
2012-10-09 12:14:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
static void
|
2013-03-08 18:44:16 +01:00
|
|
|
convert_arguments_to_ffi(const char *signature, uint32_t flags,
|
|
|
|
|
union wl_argument *args,
|
2013-02-26 11:30:51 -05:00
|
|
|
int count, ffi_type **ffi_types, void** ffi_args)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
const char *sig_iter;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
|
|
|
|
|
sig_iter = signature;
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
sig_iter = get_next_argument(sig_iter, &arg);
|
|
|
|
|
|
|
|
|
|
switch(arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_INT:
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_types[i] = &ffi_type_sint32;
|
|
|
|
|
ffi_args[i] = &args[i].i;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_UINT:
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_types[i] = &ffi_type_uint32;
|
|
|
|
|
ffi_args[i] = &args[i].u;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FIXED:
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_types[i] = &ffi_type_sint32;
|
|
|
|
|
ffi_args[i] = &args[i].f;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_STRING:
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_types[i] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[i] = &args[i].s;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_OBJECT:
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_types[i] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[i] = &args[i].o;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_NEW_ID:
|
2013-03-08 18:44:16 +01:00
|
|
|
if (flags & WL_CLOSURE_INVOKE_CLIENT) {
|
|
|
|
|
ffi_types[i] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[i] = &args[i].o;
|
|
|
|
|
} else {
|
|
|
|
|
ffi_types[i] = &ffi_type_uint32;
|
|
|
|
|
ffi_args[i] = &args[i].n;
|
|
|
|
|
}
|
2013-02-26 11:30:51 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_ARRAY:
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_types[i] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[i] = &args[i].a;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FD:
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_types[i] = &ffi_type_sint32;
|
|
|
|
|
ffi_args[i] = &args[i].h;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2015-11-16 11:49:02 +01:00
|
|
|
wl_abort("unknown type\n");
|
2013-02-26 11:30:51 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-30 09:47:36 -04:00
|
|
|
void
|
2013-03-08 18:44:16 +01:00
|
|
|
wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
|
2013-03-08 22:26:12 -06:00
|
|
|
struct wl_object *target, uint32_t opcode, void *data)
|
2010-08-30 09:47:36 -04:00
|
|
|
{
|
2013-02-26 11:30:51 -05:00
|
|
|
int count;
|
|
|
|
|
ffi_cif cif;
|
|
|
|
|
ffi_type *ffi_types[WL_CLOSURE_MAX_ARGS + 2];
|
|
|
|
|
void * ffi_args[WL_CLOSURE_MAX_ARGS + 2];
|
2013-03-08 22:26:12 -06:00
|
|
|
void (* const *implementation)(void);
|
2013-02-26 11:30:51 -05:00
|
|
|
|
|
|
|
|
count = arg_count_for_signature(closure->message->signature);
|
|
|
|
|
|
|
|
|
|
ffi_types[0] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[0] = &data;
|
|
|
|
|
ffi_types[1] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[1] = ⌖
|
|
|
|
|
|
2013-03-08 18:44:16 +01:00
|
|
|
convert_arguments_to_ffi(closure->message->signature, flags, closure->args,
|
2013-02-26 11:30:51 -05:00
|
|
|
count, ffi_types + 2, ffi_args + 2);
|
2010-08-30 09:47:36 -04:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
|
|
|
|
|
count + 2, &ffi_type_void, ffi_types);
|
2010-08-30 09:47:36 -04:00
|
|
|
|
2013-03-08 22:26:12 -06:00
|
|
|
implementation = target->implementation;
|
2014-10-01 21:17:18 +09:00
|
|
|
if (!implementation[opcode]) {
|
2015-11-16 11:49:02 +01:00
|
|
|
wl_abort("listener function for opcode %u of %s is NULL\n",
|
|
|
|
|
opcode, target->interface->name);
|
2014-10-01 21:17:18 +09:00
|
|
|
}
|
2013-03-08 22:26:12 -06:00
|
|
|
ffi_call(&cif, implementation[opcode], NULL, ffi_args);
|
2017-12-06 11:22:19 -06:00
|
|
|
|
|
|
|
|
wl_closure_clear_fds(closure);
|
2010-08-30 09:47:36 -04:00
|
|
|
}
|
|
|
|
|
|
2013-07-17 21:58:46 -05:00
|
|
|
void
|
|
|
|
|
wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher,
|
|
|
|
|
struct wl_object *target, uint32_t opcode)
|
|
|
|
|
{
|
|
|
|
|
dispatcher(target->implementation, target, opcode, closure->message,
|
|
|
|
|
closure->args);
|
2017-12-06 11:22:19 -06:00
|
|
|
|
|
|
|
|
wl_closure_clear_fds(closure);
|
2013-07-17 21:58:46 -05:00
|
|
|
}
|
|
|
|
|
|
2012-04-21 23:50:09 -04:00
|
|
|
static int
|
|
|
|
|
copy_fds_to_connection(struct wl_closure *closure,
|
|
|
|
|
struct wl_connection *connection)
|
|
|
|
|
{
|
|
|
|
|
const struct wl_message *message = closure->message;
|
|
|
|
|
uint32_t i, count;
|
2012-07-02 20:03:30 +10:00
|
|
|
struct argument_details arg;
|
|
|
|
|
const char *signature = message->signature;
|
2013-02-26 11:30:51 -05:00
|
|
|
int fd;
|
2012-04-21 23:50:09 -04:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
count = arg_count_for_signature(signature);
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2012-07-02 20:03:30 +10:00
|
|
|
signature = get_next_argument(signature, &arg);
|
2024-02-15 10:37:34 +01:00
|
|
|
if (arg.type != WL_ARG_FD)
|
2012-04-21 23:50:09 -04:00
|
|
|
continue;
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
fd = closure->args[i].h;
|
|
|
|
|
if (wl_connection_put_fd(connection, fd)) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("request could not be marshaled: "
|
2021-05-07 11:00:43 +03:00
|
|
|
"can't send file descriptor\n");
|
2012-04-21 23:50:09 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
2017-12-06 11:22:19 -06:00
|
|
|
closure->args[i].h = -1;
|
2012-04-21 23:50:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 14:28:53 +01:00
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
|
buffer_size_for_closure(struct wl_closure *closure)
|
|
|
|
|
{
|
|
|
|
|
const struct wl_message *message = closure->message;
|
|
|
|
|
int i, count;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
const char *signature;
|
|
|
|
|
uint32_t size, buffer_size = 0;
|
|
|
|
|
|
|
|
|
|
signature = message->signature;
|
|
|
|
|
count = arg_count_for_signature(signature);
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
signature = get_next_argument(signature, &arg);
|
|
|
|
|
|
|
|
|
|
switch (arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FD:
|
2013-12-05 14:28:53 +01:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_UINT:
|
|
|
|
|
case WL_ARG_INT:
|
|
|
|
|
case WL_ARG_FIXED:
|
|
|
|
|
case WL_ARG_OBJECT:
|
|
|
|
|
case WL_ARG_NEW_ID:
|
2013-12-05 14:28:53 +01:00
|
|
|
buffer_size++;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_STRING:
|
2013-12-05 14:28:53 +01:00
|
|
|
if (closure->args[i].s == NULL) {
|
|
|
|
|
buffer_size++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = strlen(closure->args[i].s) + 1;
|
2018-08-14 13:07:52 +02:00
|
|
|
buffer_size += 1 + div_roundup(size, sizeof(uint32_t));
|
2013-12-05 14:28:53 +01:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_ARRAY:
|
2013-12-05 14:28:53 +01:00
|
|
|
if (closure->args[i].a == NULL) {
|
|
|
|
|
buffer_size++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = closure->args[i].a->size;
|
2018-08-14 13:07:52 +02:00
|
|
|
buffer_size += (1 + div_roundup(size, sizeof(uint32_t)));
|
2013-12-05 14:28:53 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buffer_size + 2;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
static int
|
|
|
|
|
serialize_closure(struct wl_closure *closure, uint32_t *buffer,
|
|
|
|
|
size_t buffer_count)
|
|
|
|
|
{
|
|
|
|
|
const struct wl_message *message = closure->message;
|
|
|
|
|
unsigned int i, count, size;
|
|
|
|
|
uint32_t *p, *end;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
const char *signature;
|
|
|
|
|
|
|
|
|
|
if (buffer_count < 2)
|
|
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
|
|
p = buffer + 2;
|
|
|
|
|
end = buffer + buffer_count;
|
|
|
|
|
|
|
|
|
|
signature = message->signature;
|
|
|
|
|
count = arg_count_for_signature(signature);
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
|
signature = get_next_argument(signature, &arg);
|
|
|
|
|
|
2024-02-15 10:37:34 +01:00
|
|
|
if (arg.type == WL_ARG_FD)
|
2013-02-26 11:30:51 -05:00
|
|
|
continue;
|
|
|
|
|
|
2024-07-24 21:18:40 -04:00
|
|
|
if (p >= end)
|
2013-02-26 11:30:51 -05:00
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
|
|
switch (arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_UINT:
|
2013-02-26 11:30:51 -05:00
|
|
|
*p++ = closure->args[i].u;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_INT:
|
2013-02-26 11:30:51 -05:00
|
|
|
*p++ = closure->args[i].i;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FIXED:
|
2013-02-26 11:30:51 -05:00
|
|
|
*p++ = closure->args[i].f;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_OBJECT:
|
2013-02-26 11:30:51 -05:00
|
|
|
*p++ = closure->args[i].o ? closure->args[i].o->id : 0;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_NEW_ID:
|
2013-02-26 11:30:51 -05:00
|
|
|
*p++ = closure->args[i].n;
|
|
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_STRING:
|
2013-02-26 11:30:51 -05:00
|
|
|
if (closure->args[i].s == NULL) {
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = strlen(closure->args[i].s) + 1;
|
|
|
|
|
*p++ = size;
|
|
|
|
|
|
2024-07-24 21:18:40 -04:00
|
|
|
if (div_roundup(size, sizeof *p) > (uint32_t)(end - p))
|
2013-02-26 11:30:51 -05:00
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
|
|
memcpy(p, closure->args[i].s, size);
|
2018-08-14 13:07:52 +02:00
|
|
|
p += div_roundup(size, sizeof *p);
|
2013-02-26 11:30:51 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_ARRAY:
|
2013-02-26 11:30:51 -05:00
|
|
|
if (closure->args[i].a == NULL) {
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = closure->args[i].a->size;
|
|
|
|
|
*p++ = size;
|
|
|
|
|
|
2024-07-24 21:18:40 -04:00
|
|
|
if (div_roundup(size, sizeof *p) > (uint32_t)(end - p))
|
2013-02-26 11:30:51 -05:00
|
|
|
goto overflow;
|
|
|
|
|
|
2023-11-07 22:38:52 -05:00
|
|
|
if (size != 0)
|
|
|
|
|
memcpy(p, closure->args[i].a->data, size);
|
2018-08-14 13:07:52 +02:00
|
|
|
p += div_roundup(size, sizeof *p);
|
2013-02-26 11:30:51 -05:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FD:
|
2013-02-26 11:30:51 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = (p - buffer) * sizeof *p;
|
|
|
|
|
|
|
|
|
|
buffer[0] = closure->sender_id;
|
|
|
|
|
buffer[1] = size << 16 | (closure->opcode & 0x0000ffff);
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
|
|
|
|
|
overflow:
|
2022-09-29 23:39:40 +00:00
|
|
|
wl_log("serialize_closure overflow for %s (signature %s)\n",
|
|
|
|
|
message->name, message->signature);
|
2013-02-26 11:30:51 -05:00
|
|
|
errno = ERANGE;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-29 11:07:48 -05:00
|
|
|
int
|
2010-09-07 21:34:45 -04:00
|
|
|
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
|
|
|
|
|
{
|
2013-02-26 11:30:51 -05:00
|
|
|
int size;
|
2013-12-05 14:28:53 +01:00
|
|
|
uint32_t buffer_size;
|
|
|
|
|
uint32_t *buffer;
|
|
|
|
|
int result;
|
2010-09-07 21:34:45 -04:00
|
|
|
|
2012-04-21 23:50:09 -04:00
|
|
|
if (copy_fds_to_connection(closure, connection))
|
|
|
|
|
return -1;
|
|
|
|
|
|
2013-12-05 14:28:53 +01:00
|
|
|
buffer_size = buffer_size_for_closure(closure);
|
2016-02-10 23:35:44 +08:00
|
|
|
buffer = zalloc(buffer_size * sizeof buffer[0]);
|
2022-09-29 23:39:40 +00:00
|
|
|
if (buffer == NULL) {
|
|
|
|
|
wl_log("wl_closure_send error: buffer allocation failure of "
|
|
|
|
|
"size %d\n for %s (signature %s)",
|
|
|
|
|
buffer_size * sizeof buffer[0], closure->message->name,
|
|
|
|
|
closure->message->signature);
|
2013-12-05 14:28:53 +01:00
|
|
|
return -1;
|
2022-09-29 23:39:40 +00:00
|
|
|
}
|
2013-12-05 14:28:53 +01:00
|
|
|
|
|
|
|
|
size = serialize_closure(closure, buffer, buffer_size);
|
|
|
|
|
if (size < 0) {
|
|
|
|
|
free(buffer);
|
2013-02-26 11:30:51 -05:00
|
|
|
return -1;
|
2013-12-05 14:28:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = wl_connection_write(connection, buffer, size);
|
|
|
|
|
free(buffer);
|
2012-02-29 11:07:48 -05:00
|
|
|
|
2013-12-05 14:28:53 +01:00
|
|
|
return result;
|
2010-09-07 21:34:45 -04:00
|
|
|
}
|
|
|
|
|
|
2012-02-29 11:07:48 -05:00
|
|
|
int
|
2011-11-17 16:46:36 -05:00
|
|
|
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
|
|
|
|
|
{
|
2013-02-26 11:30:51 -05:00
|
|
|
int size;
|
2013-12-05 14:28:53 +01:00
|
|
|
uint32_t buffer_size;
|
|
|
|
|
uint32_t *buffer;
|
|
|
|
|
int result;
|
2011-11-17 16:46:36 -05:00
|
|
|
|
2012-04-21 23:50:09 -04:00
|
|
|
if (copy_fds_to_connection(closure, connection))
|
|
|
|
|
return -1;
|
|
|
|
|
|
2013-12-05 14:28:53 +01:00
|
|
|
buffer_size = buffer_size_for_closure(closure);
|
|
|
|
|
buffer = malloc(buffer_size * sizeof buffer[0]);
|
2022-09-29 23:39:40 +00:00
|
|
|
if (buffer == NULL) {
|
|
|
|
|
wl_log("wl_closure_queue error: buffer allocation failure of "
|
|
|
|
|
"size %d\n for %s (signature %s)",
|
|
|
|
|
buffer_size * sizeof buffer[0], closure->message->name,
|
|
|
|
|
closure->message->signature);
|
2013-12-05 14:28:53 +01:00
|
|
|
return -1;
|
2022-09-29 23:39:40 +00:00
|
|
|
}
|
2013-12-05 14:28:53 +01:00
|
|
|
|
|
|
|
|
size = serialize_closure(closure, buffer, buffer_size);
|
|
|
|
|
if (size < 0) {
|
|
|
|
|
free(buffer);
|
2013-02-26 11:30:51 -05:00
|
|
|
return -1;
|
2013-12-05 14:28:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = wl_connection_queue(connection, buffer, size);
|
|
|
|
|
free(buffer);
|
2012-02-29 11:07:48 -05:00
|
|
|
|
2013-12-05 14:28:53 +01:00
|
|
|
return result;
|
2011-11-17 16:46:36 -05:00
|
|
|
}
|
|
|
|
|
|
2010-09-07 10:58:19 -04:00
|
|
|
void
|
client: print discarded events in debug log
Before this patch, setting WAYLAND_DEBUG=1 or WAYLAND_DEBUG=client made
a program log all requests sent and events that it processes. However,
some events received are not processed. This can happen when a Wayland
server sends an event to an object that does not exist, or was recently
destroyed by the client program (either before the event was decoded,
or after being decoded but before being dispatched.)
This commit prints all discarded messages in the debug log, producing
lines like:
[1234567.890] discarded [unknown]@42.[event 0](0 fd, 12 byte)
[1234567.890] discarded wl_callback@3.done(34567)
[1234567.890] discarded [zombie]@13.[event 1](3 fd, 8 byte)
The first indicates an event to an object that does not exist; the
second, an event to an object that was deleted after decoding, but
before dispatch; the third, an event to an object that left a
'zombie' marker behind to indicate which events have associated
file descriptors.
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
2020-09-26 21:14:16 -04:00
|
|
|
wl_closure_print(struct wl_closure *closure, struct wl_object *target,
|
2023-11-10 14:21:48 -06:00
|
|
|
int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg),
|
|
|
|
|
const char *queue_name)
|
2010-09-07 10:58:19 -04:00
|
|
|
{
|
|
|
|
|
int i;
|
2012-07-02 20:03:30 +10:00
|
|
|
struct argument_details arg;
|
|
|
|
|
const char *signature = closure->message->signature;
|
2011-07-14 18:56:40 +03:00
|
|
|
struct timespec tp;
|
|
|
|
|
unsigned int time;
|
2021-08-24 17:08:51 -05:00
|
|
|
uint32_t nval;
|
2022-03-07 15:49:49 +01:00
|
|
|
FILE *f;
|
|
|
|
|
char *buffer;
|
|
|
|
|
size_t buffer_length;
|
|
|
|
|
|
|
|
|
|
f = open_memstream(&buffer, &buffer_length);
|
|
|
|
|
if (f == NULL)
|
|
|
|
|
return;
|
2010-09-07 10:58:19 -04:00
|
|
|
|
2011-07-14 18:56:40 +03:00
|
|
|
clock_gettime(CLOCK_REALTIME, &tp);
|
|
|
|
|
time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
|
|
|
|
|
|
2023-11-10 14:21:48 -06:00
|
|
|
fprintf(f, "[%7u.%03u] ", time / 1000, time % 1000);
|
|
|
|
|
|
|
|
|
|
if (queue_name)
|
|
|
|
|
fprintf(f, "{%s} ", queue_name);
|
|
|
|
|
|
|
|
|
|
fprintf(f, "%s%s%s#%u.%s(",
|
client: print discarded events in debug log
Before this patch, setting WAYLAND_DEBUG=1 or WAYLAND_DEBUG=client made
a program log all requests sent and events that it processes. However,
some events received are not processed. This can happen when a Wayland
server sends an event to an object that does not exist, or was recently
destroyed by the client program (either before the event was decoded,
or after being decoded but before being dispatched.)
This commit prints all discarded messages in the debug log, producing
lines like:
[1234567.890] discarded [unknown]@42.[event 0](0 fd, 12 byte)
[1234567.890] discarded wl_callback@3.done(34567)
[1234567.890] discarded [zombie]@13.[event 1](3 fd, 8 byte)
The first indicates an event to an object that does not exist; the
second, an event to an object that was deleted after decoding, but
before dispatch; the third, an event to an object that left a
'zombie' marker behind to indicate which events have associated
file descriptors.
Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
2020-09-26 21:14:16 -04:00
|
|
|
discarded ? "discarded " : "",
|
2011-07-19 10:01:46 -07:00
|
|
|
send ? " -> " : "",
|
2010-09-07 10:58:19 -04:00
|
|
|
target->interface->name, target->id,
|
|
|
|
|
closure->message->name);
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
for (i = 0; i < closure->count; i++) {
|
2012-07-02 20:03:30 +10:00
|
|
|
signature = get_next_argument(signature, &arg);
|
2013-02-26 11:30:51 -05:00
|
|
|
if (i > 0)
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, ", ");
|
2010-09-07 17:00:34 -04:00
|
|
|
|
2012-07-02 20:03:30 +10:00
|
|
|
switch (arg.type) {
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_UINT:
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "%u", closure->args[i].u);
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_INT:
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "%d", closure->args[i].i);
|
2012-05-08 17:17:25 +01:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FIXED:
|
2021-01-17 18:02:50 -05:00
|
|
|
/* The magic number 390625 is 1e8 / 256 */
|
|
|
|
|
if (closure->args[i].f >= 0) {
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "%d.%08d",
|
2021-01-17 18:02:50 -05:00
|
|
|
closure->args[i].f / 256,
|
|
|
|
|
390625 * (closure->args[i].f % 256));
|
|
|
|
|
} else {
|
|
|
|
|
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "-%d.%08d",
|
2021-01-17 18:02:50 -05:00
|
|
|
closure->args[i].f / -256,
|
|
|
|
|
-390625 * (closure->args[i].f % 256));
|
|
|
|
|
}
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_STRING:
|
2019-01-29 22:00:40 +00:00
|
|
|
if (closure->args[i].s)
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "\"%s\"", closure->args[i].s);
|
2019-01-29 22:00:40 +00:00
|
|
|
else
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "nil");
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_OBJECT:
|
2013-02-26 11:30:51 -05:00
|
|
|
if (closure->args[i].o)
|
2023-05-24 11:24:23 -07:00
|
|
|
fprintf(f, "%s#%u",
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].o->interface->name,
|
|
|
|
|
closure->args[i].o->id);
|
2011-02-07 16:05:36 -05:00
|
|
|
else
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "nil");
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_NEW_ID:
|
2021-08-24 17:08:51 -05:00
|
|
|
if (n_parse)
|
|
|
|
|
nval = n_parse(&closure->args[i]);
|
|
|
|
|
else
|
|
|
|
|
nval = closure->args[i].n;
|
|
|
|
|
|
2023-05-24 11:24:23 -07:00
|
|
|
fprintf(f, "new id %s#",
|
2013-02-26 11:30:51 -05:00
|
|
|
(closure->message->types[i]) ?
|
|
|
|
|
closure->message->types[i]->name :
|
2012-07-23 19:54:41 +01:00
|
|
|
"[unknown]");
|
2021-08-24 17:08:51 -05:00
|
|
|
if (nval != 0)
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "%u", nval);
|
2012-07-23 19:54:41 +01:00
|
|
|
else
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "nil");
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_ARRAY:
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "array[%zu]", closure->args[i].a->size);
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
2024-02-15 10:37:34 +01:00
|
|
|
case WL_ARG_FD:
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, "fd %d", closure->args[i].h);
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 15:49:49 +01:00
|
|
|
fprintf(f, ")\n");
|
|
|
|
|
|
|
|
|
|
if (fclose(f) == 0) {
|
|
|
|
|
fprintf(stderr, "%s", buffer);
|
|
|
|
|
free(buffer);
|
|
|
|
|
}
|
2010-09-07 10:58:19 -04:00
|
|
|
}
|
|
|
|
|
|
2017-12-06 11:22:20 -06:00
|
|
|
static int
|
|
|
|
|
wl_closure_close_fds(struct wl_closure *closure)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct argument_details arg;
|
|
|
|
|
const char *signature = closure->message->signature;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < closure->count; i++) {
|
|
|
|
|
signature = get_next_argument(signature, &arg);
|
2024-02-15 10:37:34 +01:00
|
|
|
if (arg.type == WL_ARG_FD && closure->args[i].h != -1)
|
2017-12-06 11:22:20 -06:00
|
|
|
close(closure->args[i].h);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-30 09:47:36 -04:00
|
|
|
void
|
|
|
|
|
wl_closure_destroy(struct wl_closure *closure)
|
|
|
|
|
{
|
2017-12-06 11:22:20 -06:00
|
|
|
/* wl_closure_destroy has free() semantics */
|
|
|
|
|
if (!closure)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
wl_closure_close_fds(closure);
|
2012-06-12 17:45:25 -04:00
|
|
|
free(closure);
|
2008-12-24 19:30:25 -05:00
|
|
|
}
|