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
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
struct wl_buffer {
|
|
|
|
|
char data[4096];
|
2012-10-15 17:16:30 -04:00
|
|
|
uint32_t head, tail;
|
2008-10-08 12:48:46 -04:00
|
|
|
};
|
|
|
|
|
|
2010-08-26 17:44:31 -04:00
|
|
|
#define MASK(i) ((i) & 4095)
|
|
|
|
|
|
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 {
|
|
|
|
|
struct wl_buffer in, out;
|
2010-08-26 21:49:44 -04:00
|
|
|
struct wl_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
|
|
|
};
|
|
|
|
|
|
2014-04-17 18:20:37 +03:00
|
|
|
static int
|
2010-08-26 17:44:31 -04:00
|
|
|
wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
|
|
|
|
|
{
|
2012-10-15 17:16:30 -04:00
|
|
|
uint32_t head, size;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
2014-04-17 18:20:37 +03:00
|
|
|
if (count > sizeof(b->data)) {
|
|
|
|
|
wl_log("Data too big for buffer (%d > %d).\n",
|
|
|
|
|
count, sizeof(b->data));
|
|
|
|
|
errno = E2BIG;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-26 17:44:31 -04:00
|
|
|
head = MASK(b->head);
|
|
|
|
|
if (head + count <= sizeof b->data) {
|
|
|
|
|
memcpy(b->data + head, data, count);
|
|
|
|
|
} else {
|
|
|
|
|
size = sizeof b->data - head;
|
|
|
|
|
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
|
|
|
|
|
wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count)
|
|
|
|
|
{
|
2012-10-15 17:16:30 -04:00
|
|
|
uint32_t head, tail;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
|
|
|
|
head = MASK(b->head);
|
|
|
|
|
tail = MASK(b->tail);
|
|
|
|
|
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;
|
|
|
|
|
iov[0].iov_len = sizeof b->data - head;
|
|
|
|
|
*count = 1;
|
|
|
|
|
} else {
|
|
|
|
|
iov[0].iov_base = b->data + head;
|
|
|
|
|
iov[0].iov_len = sizeof b->data - head;
|
|
|
|
|
iov[1].iov_base = b->data;
|
|
|
|
|
iov[1].iov_len = tail;
|
|
|
|
|
*count = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count)
|
|
|
|
|
{
|
2012-10-15 17:16:30 -04:00
|
|
|
uint32_t head, tail;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
|
|
|
|
head = MASK(b->head);
|
|
|
|
|
tail = MASK(b->tail);
|
|
|
|
|
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;
|
|
|
|
|
iov[0].iov_len = sizeof b->data - tail;
|
|
|
|
|
*count = 1;
|
|
|
|
|
} else {
|
|
|
|
|
iov[0].iov_base = b->data + tail;
|
|
|
|
|
iov[0].iov_len = sizeof b->data - tail;
|
|
|
|
|
iov[1].iov_base = b->data;
|
|
|
|
|
iov[1].iov_len = head;
|
|
|
|
|
*count = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_buffer_copy(struct wl_buffer *b, void *data, size_t count)
|
|
|
|
|
{
|
2012-10-15 17:16:30 -04:00
|
|
|
uint32_t tail, size;
|
2010-08-26 17:44:31 -04:00
|
|
|
|
|
|
|
|
tail = MASK(b->tail);
|
|
|
|
|
if (tail + count <= sizeof b->data) {
|
|
|
|
|
memcpy(data, b->data + tail, count);
|
|
|
|
|
} else {
|
|
|
|
|
size = sizeof b->data - tail;
|
|
|
|
|
memcpy(data, b->data + tail, size);
|
|
|
|
|
memcpy((char *) data + size, b->data, count - size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-15 17:16:30 -04:00
|
|
|
static uint32_t
|
2012-03-23 00:48:19 -04:00
|
|
|
wl_buffer_size(struct wl_buffer *b)
|
|
|
|
|
{
|
|
|
|
|
return b->head - b->tail;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
struct wl_connection *
|
2012-10-04 16:54:22 -04:00
|
|
|
wl_connection_create(int fd)
|
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
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
connection->fd = fd;
|
|
|
|
|
|
|
|
|
|
return connection;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-11 23:37:45 +02:00
|
|
|
static void
|
2012-10-11 23:37:46 +02:00
|
|
|
close_fds(struct wl_buffer *buffer, int max)
|
2012-10-11 23:37:45 +02:00
|
|
|
{
|
2012-10-11 23:37:46 +02:00
|
|
|
int32_t fds[sizeof(buffer->data) / sizeof(int32_t)], i, count;
|
2012-10-11 23:37:45 +02:00
|
|
|
size_t size;
|
|
|
|
|
|
2017-04-13 11:51:51 -05:00
|
|
|
size = wl_buffer_size(buffer);
|
2012-10-11 23:37:45 +02:00
|
|
|
if (size == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
wl_buffer_copy(buffer, fds, size);
|
|
|
|
|
count = size / sizeof fds[0];
|
2012-10-11 23:37:46 +02:00
|
|
|
if (max > 0 && max < count)
|
|
|
|
|
count = max;
|
2017-04-13 11:51:43 -05:00
|
|
|
size = count * sizeof fds[0];
|
2012-10-11 23:37:45 +02:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
close(fds[i]);
|
|
|
|
|
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);
|
2012-10-11 23:37:47 +02:00
|
|
|
close_fds(&connection->fds_in, -1);
|
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)
|
|
|
|
|
{
|
2010-08-26 17:44:31 -04:00
|
|
|
wl_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
|
|
|
|
|
build_cmsg(struct wl_buffer *buffer, char *data, int *clen)
|
|
|
|
|
{
|
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
|
size_t size;
|
|
|
|
|
|
2017-04-13 11:51:51 -05:00
|
|
|
size = wl_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);
|
|
|
|
|
wl_buffer_copy(buffer, CMSG_DATA(cmsg), size);
|
|
|
|
|
*clen = cmsg->cmsg_len;
|
|
|
|
|
} else {
|
|
|
|
|
*clen = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-11 23:37:49 +02:00
|
|
|
static int
|
2010-08-26 21:49:44 -04:00
|
|
|
decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg)
|
|
|
|
|
{
|
|
|
|
|
struct cmsghdr *cmsg;
|
2012-10-11 23:37:49 +02:00
|
|
|
size_t size, max, i;
|
|
|
|
|
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);
|
|
|
|
|
max = sizeof(buffer->data) - wl_buffer_size(buffer);
|
|
|
|
|
if (size > max || overflow) {
|
|
|
|
|
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]);
|
2014-04-17 18:20:37 +03:00
|
|
|
} else if (wl_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
|
|
|
|
|
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];
|
2010-08-25 17:11:29 -04:00
|
|
|
struct msghdr msg;
|
2012-03-09 12:51:42 +02:00
|
|
|
char cmsg[CLEN];
|
2012-10-04 16:54:22 -04:00
|
|
|
int len = 0, count, clen;
|
|
|
|
|
uint32_t tail;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
while (connection->out.head - connection->out.tail > 0) {
|
2011-01-15 00:40:00 +01:00
|
|
|
wl_buffer_get_iov(&connection->out, iov, &count);
|
|
|
|
|
|
|
|
|
|
build_cmsg(&connection->fds_out, cmsg, &clen);
|
2010-08-26 17:44:31 -04:00
|
|
|
|
|
|
|
|
msg.msg_name = NULL;
|
|
|
|
|
msg.msg_namelen = 0;
|
|
|
|
|
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 21:49:44 -04:00
|
|
|
msg.msg_flags = 0;
|
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)
|
|
|
|
|
{
|
|
|
|
|
return wl_buffer_size(&connection->in);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2012-10-15 17:19:38 -04:00
|
|
|
if (wl_buffer_size(&connection->in) >= sizeof(connection->in.data)) {
|
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
wl_buffer_put_iov(&connection->in, iov, &count);
|
|
|
|
|
|
|
|
|
|
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;
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
do {
|
client: Add wl_display_prepare_read() API to relax thread model assumptions
The current thread model assumes that the application or toolkit will have
one thread that either polls the display fd and dispatches events or just
dispatches in a loop. Only this main thread will read from the fd while
all other threads will block on a pthread condition and expect the main
thread to deliver events to them.
This turns out to be too restrictive. We can't assume that there
always will be a thread like that. Qt QML threaded rendering will
block the main thread on a condition that's signaled by a rendering
thread after it finishes rendering. This leads to a deadlock when the
rendering threads blocks in eglSwapBuffers(), and the main thread is
waiting on the condition. Another problematic use case is with games
that has a rendering thread for a splash screen while the main thread
is busy loading game data or compiling shaders. The main thread isn't
responsive and ends up blocking eglSwapBuffers() in the rendering thread.
We also can't assume that there will be only one thread polling on the
file descriptor. A valid use case is a thread receiving data from a
custom wayland interface as well as a device fd or network socket.
The thread may want to wait on either events from the wayland
interface or data from the fd, in which case it needs to poll on both
the wayland display fd and the device/network fd.
The solution seems pretty straightforward: just let all threads read
from the fd. However, the main-thread restriction was introduced to
avoid a race. Simplified, main loops will do something like this:
wl_display_dispatch_pending(display);
/* Race here if other thread reads from fd and places events
* in main eent queue. We go to sleep in poll while sitting on
* events that may stall the application if not dispatched. */
poll(fds, nfds, -1);
/* Race here if other thread reads and doesn't queue any
* events for main queue. wl_display_dispatch() below will block
* trying to read from the fd, while other fds in the mainloop
* are ignored. */
wl_display_dispatch(display);
The restriction that only the main thread can read from the fd avoids
these races, but has the problems described above.
This patch introduces new API to solve both problems. We add
int wl_display_prepare_read(struct wl_display *display);
and
int wl_display_read_events(struct wl_display *display);
wl_display_prepare_read() registers the calling thread as a potential
reader of events. Once data is available on the fd, all reader
threads must call wl_display_read_events(), at which point one of the
threads will read from the fd and distribute the events to event
queues. When that is done, all threads return from
wl_display_read_events().
From the point of view of a single thread, this ensures that between
calling wl_display_prepare_read() and wl_display_read_events(), no
other thread will read from the fd and queue events in its event
queue. This avoids the race conditions described above, and we avoid
relying on any one thread to be available to read events.
2013-03-17 14:21:48 -04:00
|
|
|
len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT);
|
2012-10-04 16:54:22 -04:00
|
|
|
} while (len < 0 && errno == EINTR);
|
2010-08-26 21:49:44 -04:00
|
|
|
|
2012-10-04 16:54:22 -04:00
|
|
|
if (len <= 0)
|
|
|
|
|
return len;
|
|
|
|
|
|
2012-10-11 23:37:49 +02:00
|
|
|
ret = decode_cmsg(&connection->fds_in, &msg);
|
|
|
|
|
if (ret)
|
|
|
|
|
return -1;
|
2012-10-04 16:54:22 -04:00
|
|
|
|
|
|
|
|
connection->in.head += len;
|
2008-10-08 12:48:46 -04:00
|
|
|
|
2016-01-12 13:12:34 +09:00
|
|
|
return wl_connection_pending_input(connection);
|
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
|
|
|
{
|
2011-06-10 10:24:23 +02:00
|
|
|
if (connection->out.head - connection->out.tail +
|
2012-10-04 16:54:22 -04:00
|
|
|
count > ARRAY_LENGTH(connection->out.data)) {
|
|
|
|
|
connection->want_flush = 1;
|
|
|
|
|
if (wl_connection_flush(connection) < 0)
|
2012-02-29 11:07:48 -05:00
|
|
|
return -1;
|
2012-10-04 16:54:22 -04:00
|
|
|
}
|
2011-06-10 10:24:23 +02:00
|
|
|
|
2014-04-17 18:20:37 +03:00
|
|
|
if (wl_buffer_put(&connection->out, data, count) < 0)
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (connection->out.head - connection->out.tail +
|
2012-10-04 16:54:22 -04:00
|
|
|
count > ARRAY_LENGTH(connection->out.data)) {
|
|
|
|
|
connection->want_flush = 1;
|
|
|
|
|
if (wl_connection_flush(connection) < 0)
|
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
|
|
|
|
2014-04-17 18:20:37 +03:00
|
|
|
return wl_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++) {
|
|
|
|
|
if (message->signature[i] == 'a')
|
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)
|
|
|
|
|
{
|
2012-10-04 16:54:22 -04:00
|
|
|
if (wl_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd) {
|
|
|
|
|
connection->want_flush = 1;
|
|
|
|
|
if (wl_connection_flush(connection) < 0)
|
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
|
|
|
|
2014-04-17 18:20:37 +03:00
|
|
|
return wl_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) {
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 's':
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'n':
|
|
|
|
|
case 'a':
|
|
|
|
|
case 'h':
|
|
|
|
|
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) {
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 's':
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'n':
|
|
|
|
|
case 'a':
|
|
|
|
|
case 'h':
|
|
|
|
|
++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) {
|
|
|
|
|
case 'i':
|
|
|
|
|
args[i].i = va_arg(ap, int32_t);
|
|
|
|
|
break;
|
|
|
|
|
case 'u':
|
|
|
|
|
args[i].u = va_arg(ap, uint32_t);
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
args[i].f = va_arg(ap, wl_fixed_t);
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
args[i].s = va_arg(ap, const char *);
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
args[i].o = va_arg(ap, struct wl_object *);
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
args[i].o = va_arg(ap, struct wl_object *);
|
|
|
|
|
break;
|
|
|
|
|
case 'a':
|
|
|
|
|
args[i].a = va_arg(ap, struct wl_array *);
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
args[i].h = va_arg(ap, int32_t);
|
|
|
|
|
break;
|
|
|
|
|
case '\0':
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
if (arg.type == 'h')
|
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) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("too many args (%d)\n", count);
|
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
|
|
|
|
2017-12-06 11:22:18 -06:00
|
|
|
if (size) {
|
|
|
|
|
*num_arrays = wl_message_count_arrays(message);
|
|
|
|
|
closure = malloc(sizeof *closure + size +
|
|
|
|
|
*num_arrays * sizeof(struct wl_array));
|
|
|
|
|
} else {
|
|
|
|
|
closure = malloc(sizeof *closure);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!closure) {
|
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) {
|
2012-05-08 17:17:25 +01:00
|
|
|
case 'f':
|
2008-12-24 19:30:25 -05:00
|
|
|
case 'u':
|
2010-09-07 17:03:17 -04:00
|
|
|
case 'i':
|
|
|
|
|
break;
|
2008-12-24 19:30:25 -05:00
|
|
|
case 's':
|
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;
|
|
|
|
|
case 'o':
|
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;
|
2010-09-07 20:57:40 -04:00
|
|
|
case 'n':
|
2013-02-26 11:30:51 -05:00
|
|
|
object = args[i].o;
|
2012-07-23 19:54:41 +01:00
|
|
|
if (!arg.nullable && object == NULL)
|
|
|
|
|
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;
|
2009-02-23 22:30:29 -05:00
|
|
|
case 'a':
|
2013-02-26 13:40:34 -05:00
|
|
|
if (!arg.nullable && args[i].a == NULL)
|
2012-07-02 20:03:30 +10:00
|
|
|
goto err_null;
|
2009-02-23 22:30:29 -05:00
|
|
|
break;
|
2010-08-26 21:49:44 -04:00
|
|
|
case 'h':
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
char *s;
|
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);
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
if (arg.type != 'h' && p + 1 > 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) {
|
2008-12-24 19:30:25 -05:00
|
|
|
case 'u':
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].u = *p++;
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2010-09-07 17:03:17 -04:00
|
|
|
case 'i':
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].i = *p++;
|
2010-09-07 17:03:17 -04:00
|
|
|
break;
|
2012-05-08 17:17:25 +01:00
|
|
|
case 'f':
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->args[i].f = *p++;
|
2012-05-08 17:17:25 +01:00
|
|
|
break;
|
2008-12-24 19:30:25 -05:00
|
|
|
case 's':
|
|
|
|
|
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
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
s = (char *) p;
|
2010-09-07 17:00:34 -04:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
if (length > 0 && 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
|
|
|
|
|
|
|
|
closure->args[i].s = s;
|
2010-08-09 14:34:11 -04:00
|
|
|
p = next;
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
|
|
|
|
case 'o':
|
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;
|
|
|
|
|
case 'n':
|
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 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) {
|
2014-04-22 16:03:12 +03:00
|
|
|
wl_log("not a valid new object id (%u), "
|
2010-08-09 14:34:11 -04:00
|
|
|
"message %s(%s)\n",
|
2013-02-26 11:30:51 -05:00
|
|
|
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-18 15:53:23 +02:00
|
|
|
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
2009-02-23 22:30:29 -05:00
|
|
|
case 'a':
|
|
|
|
|
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;
|
2010-08-26 21:49:44 -04:00
|
|
|
case 'h':
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
wl_buffer_copy(&connection->fds_in, &fd, sizeof fd);
|
|
|
|
|
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);
|
|
|
|
|
switch (arg.type) {
|
|
|
|
|
case 'o':
|
2013-02-26 11:30:51 -05:00
|
|
|
id = closure->args[i].n;
|
|
|
|
|
closure->args[i].o = NULL;
|
|
|
|
|
|
|
|
|
|
object = wl_map_lookup(objects, id);
|
2017-12-28 15:15:46 +00:00
|
|
|
if (wl_object_is_zombie(objects, id)) {
|
2012-10-09 12:14:34 -04:00
|
|
|
/* references object we've already
|
|
|
|
|
* destroyed client side */
|
2013-02-26 11:30:51 -05:00
|
|
|
object = NULL;
|
|
|
|
|
} else if (object == NULL && id != 0) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("unknown object (%u), message %s(%s)\n",
|
2012-10-09 12:14:34 -04:00
|
|
|
id, message->name, message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
if (object != NULL && message->types[i] != NULL &&
|
2013-06-20 20:36:47 -05:00
|
|
|
!wl_interface_equal((object)->interface,
|
|
|
|
|
message->types[i])) {
|
2014-02-17 19:04:28 -05:00
|
|
|
wl_log("invalid object (%u), type (%s), "
|
2012-10-09 12:14:34 -04:00
|
|
|
"message %s(%s)\n",
|
2013-02-26 11:30:51 -05:00
|
|
|
id, (object)->interface->name,
|
2012-10-09 12:14:34 -04:00
|
|
|
message->name, message->signature);
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2013-02-26 11:30:51 -05: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) {
|
|
|
|
|
case 'i':
|
|
|
|
|
ffi_types[i] = &ffi_type_sint32;
|
|
|
|
|
ffi_args[i] = &args[i].i;
|
|
|
|
|
break;
|
|
|
|
|
case 'u':
|
|
|
|
|
ffi_types[i] = &ffi_type_uint32;
|
|
|
|
|
ffi_args[i] = &args[i].u;
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
ffi_types[i] = &ffi_type_sint32;
|
|
|
|
|
ffi_args[i] = &args[i].f;
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
ffi_types[i] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[i] = &args[i].s;
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
ffi_types[i] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[i] = &args[i].o;
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
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;
|
|
|
|
|
case 'a':
|
|
|
|
|
ffi_types[i] = &ffi_type_pointer;
|
|
|
|
|
ffi_args[i] = &args[i].a;
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
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);
|
|
|
|
|
if (arg.type != 'h')
|
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) {
|
|
|
|
|
case 'h':
|
|
|
|
|
break;
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'n':
|
|
|
|
|
buffer_size++;
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
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;
|
|
|
|
|
case 'a':
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (arg.type == 'h')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (p + 1 > end)
|
|
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
|
|
switch (arg.type) {
|
|
|
|
|
case 'u':
|
|
|
|
|
*p++ = closure->args[i].u;
|
|
|
|
|
break;
|
|
|
|
|
case 'i':
|
|
|
|
|
*p++ = closure->args[i].i;
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
*p++ = closure->args[i].f;
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
*p++ = closure->args[i].o ? closure->args[i].o->id : 0;
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
*p++ = closure->args[i].n;
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
if (closure->args[i].s == NULL) {
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = strlen(closure->args[i].s) + 1;
|
|
|
|
|
*p++ = size;
|
|
|
|
|
|
2018-08-14 13:07:52 +02:00
|
|
|
if (p + div_roundup(size, sizeof *p) > end)
|
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;
|
|
|
|
|
case 'a':
|
|
|
|
|
if (closure->args[i].a == NULL) {
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = closure->args[i].a->size;
|
|
|
|
|
*p++ = size;
|
|
|
|
|
|
2018-08-14 13:07:52 +02:00
|
|
|
if (p + div_roundup(size, sizeof *p) > end)
|
2013-02-26 11:30:51 -05:00
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = (p - buffer) * sizeof *p;
|
|
|
|
|
|
|
|
|
|
buffer[0] = closure->sender_id;
|
|
|
|
|
buffer[1] = size << 16 | (closure->opcode & 0x0000ffff);
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
|
|
|
|
|
overflow:
|
|
|
|
|
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]);
|
2013-12-05 14:28:53 +01:00
|
|
|
if (buffer == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
if (buffer == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
int send, int discarded)
|
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;
|
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);
|
|
|
|
|
|
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
|
|
|
fprintf(stderr, "[%10.3f] %s%s%s@%u.%s(",
|
2011-07-14 18:56:40 +03:00
|
|
|
time / 1000.0,
|
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)
|
2010-09-07 10:58:19 -04:00
|
|
|
fprintf(stderr, ", ");
|
2010-09-07 17:00:34 -04:00
|
|
|
|
2012-07-02 20:03:30 +10:00
|
|
|
switch (arg.type) {
|
2010-09-07 10:58:19 -04:00
|
|
|
case 'u':
|
2013-02-26 11:30:51 -05:00
|
|
|
fprintf(stderr, "%u", closure->args[i].u);
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
|
|
|
|
case 'i':
|
2013-02-26 11:30:51 -05:00
|
|
|
fprintf(stderr, "%d", closure->args[i].i);
|
2012-05-08 17:17:25 +01:00
|
|
|
break;
|
|
|
|
|
case 'f':
|
2013-02-26 11:30:51 -05:00
|
|
|
fprintf(stderr, "%f",
|
|
|
|
|
wl_fixed_to_double(closure->args[i].f));
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
|
|
|
|
case 's':
|
2019-01-29 22:00:40 +00:00
|
|
|
if (closure->args[i].s)
|
|
|
|
|
fprintf(stderr, "\"%s\"", closure->args[i].s);
|
|
|
|
|
else
|
|
|
|
|
fprintf(stderr, "nil");
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
|
|
|
|
case 'o':
|
2013-02-26 11:30:51 -05:00
|
|
|
if (closure->args[i].o)
|
2011-02-07 16:05:36 -05:00
|
|
|
fprintf(stderr, "%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
|
|
|
|
|
fprintf(stderr, "nil");
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
|
|
|
|
case 'n':
|
2012-07-23 19:54:41 +01:00
|
|
|
fprintf(stderr, "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]");
|
2013-02-26 11:30:51 -05:00
|
|
|
if (closure->args[i].n != 0)
|
|
|
|
|
fprintf(stderr, "%u", closure->args[i].n);
|
2012-07-23 19:54:41 +01:00
|
|
|
else
|
|
|
|
|
fprintf(stderr, "nil");
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
|
|
|
|
case 'a':
|
|
|
|
|
fprintf(stderr, "array");
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
2013-02-26 11:30:51 -05:00
|
|
|
fprintf(stderr, "fd %d", closure->args[i].h);
|
2010-09-07 10:58:19 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, ")\n");
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
if (arg.type == 'h' && closure->args[i].h != -1)
|
|
|
|
|
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
|
|
|
}
|