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
|
|
|
*
|
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
|
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
|
|
|
* that the name of the copyright holders not be used in advertising or
|
|
|
|
|
* publicity pertaining to distribution of the software without specific,
|
|
|
|
|
* written prior permission. The copyright holders make no representations
|
|
|
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
|
|
|
* is" without express or implied warranty.
|
|
|
|
|
*
|
|
|
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
|
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
|
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
|
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
|
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
|
|
|
* OF THIS SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
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>
|
2008-12-24 19:30:25 -05:00
|
|
|
#include <assert.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
|
|
|
|
2012-03-30 10:28:39 -04:00
|
|
|
#define DIV_ROUNDUP(n, a) ( ((n) + ((a) - 1)) / (a) )
|
|
|
|
|
|
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
|
|
|
};
|
|
|
|
|
|
2010-08-26 17:44:31 -04:00
|
|
|
static void
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
connection = malloc(sizeof *connection);
|
2011-03-11 14:43:10 +02:00
|
|
|
if (connection == NULL)
|
|
|
|
|
return NULL;
|
2008-10-08 12:48:46 -04:00
|
|
|
memset(connection, 0, sizeof *connection);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
size = buffer->head - buffer->tail;
|
|
|
|
|
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;
|
2012-10-11 23:37:45 +02:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
close(fds[i]);
|
|
|
|
|
buffer->tail += size;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-08 12:48:46 -04:00
|
|
|
void
|
|
|
|
|
wl_connection_destroy(struct wl_connection *connection)
|
|
|
|
|
{
|
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);
|
2010-08-05 17:44:31 -04:00
|
|
|
close(connection->fd);
|
2008-10-08 12:48:46 -04:00
|
|
|
free(connection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
size = buffer->head - buffer->tail;
|
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);
|
|
|
|
|
for (i = 0; i < size; ++i)
|
|
|
|
|
close(((int*)CMSG_DATA(cmsg))[i]);
|
|
|
|
|
} else {
|
2010-08-26 21:49:44 -04:00
|
|
|
wl_buffer_put(buffer, CMSG_DATA(cmsg), size);
|
|
|
|
|
}
|
|
|
|
|
}
|
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;
|
2010-08-26 21:49:44 -04:00
|
|
|
msg.msg_control = cmsg;
|
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
|
|
|
|
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 {
|
|
|
|
|
len = wl_os_recvmsg_cloexec(connection->fd, &msg, 0);
|
|
|
|
|
} 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
|
|
|
|
2010-08-26 17:44:31 -04:00
|
|
|
return connection->in.head - connection->in.tail;
|
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
|
|
|
|
2010-08-26 17:44:31 -04:00
|
|
|
wl_buffer_put(&connection->out, data, count);
|
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
|
|
|
|
|
|
|
|
wl_buffer_put(&connection->out, data, count);
|
2012-02-29 11:07:48 -05:00
|
|
|
|
|
|
|
|
return 0;
|
2008-10-08 12:48:46 -04:00
|
|
|
}
|
2008-12-24 19:30:25 -05:00
|
|
|
|
2010-09-07 20:57:40 -04:00
|
|
|
static 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')
|
|
|
|
|
++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
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
wl_buffer_put(&connection->fds_out, &fd, sizeof fd);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (*signature == '?') {
|
|
|
|
|
details->nullable = 1;
|
|
|
|
|
signature++;
|
|
|
|
|
} else
|
|
|
|
|
details->nullable = 0;
|
|
|
|
|
|
|
|
|
|
details->type = *signature;
|
|
|
|
|
return signature + 1;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
while (*signature) {
|
|
|
|
|
if (*signature != '?')
|
|
|
|
|
count++;
|
|
|
|
|
signature++;
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-12 17:45:25 -04:00
|
|
|
struct wl_closure *
|
2013-02-26 11:30:51 -05:00
|
|
|
wl_closure_marshal(struct wl_object *sender, uint32_t opcode,
|
|
|
|
|
union wl_argument *args,
|
|
|
|
|
const struct wl_message *message)
|
2008-12-24 19:30:25 -05:00
|
|
|
{
|
2012-06-12 17:45:25 -04:00
|
|
|
struct wl_closure *closure;
|
2013-02-26 11:30:51 -05:00
|
|
|
struct wl_object *object;
|
|
|
|
|
int i, count, fd, dup_fd;
|
|
|
|
|
const char *signature;
|
2012-07-02 20:03:30 +10:00
|
|
|
struct argument_details arg;
|
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) {
|
|
|
|
|
printf("too many args (%d)\n", count);
|
|
|
|
|
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
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
closure = malloc(sizeof *closure);
|
|
|
|
|
if (closure == NULL) {
|
|
|
|
|
errno = ENOMEM;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-12-16 10:29:36 +02:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
memcpy(closure->args, args, count * sizeof *args);
|
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 11:30:51 -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 11:30:51 -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 11:30:51 -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);
|
2010-08-26 21:49:44 -04:00
|
|
|
if (dup_fd < 0) {
|
|
|
|
|
fprintf(stderr, "dup failed: %m");
|
|
|
|
|
abort();
|
|
|
|
|
}
|
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:
|
2011-11-15 08:58:34 -05:00
|
|
|
fprintf(stderr, "unhandled format code: '%c'\n",
|
2012-07-02 20:03:30 +10:00
|
|
|
arg.type);
|
2008-12-24 19:30:25 -05:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->sender_id = sender->id;
|
|
|
|
|
closure->opcode = opcode;
|
2010-09-07 21:40:31 -04:00
|
|
|
closure->message = message;
|
|
|
|
|
closure->count = count;
|
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)
|
|
|
|
|
{
|
2013-02-26 11:30:51 -05:00
|
|
|
uint32_t *p, *next, *end, length, id;
|
|
|
|
|
int fd;
|
|
|
|
|
char *s;
|
|
|
|
|
unsigned int i, count, num_arrays;
|
|
|
|
|
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;
|
2013-02-26 11:30:51 -05:00
|
|
|
struct wl_array *array, *array_extra;
|
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) {
|
2008-12-24 19:30:25 -05:00
|
|
|
printf("too many args (%d)\n", count);
|
2011-07-18 13:10:49 -04:00
|
|
|
errno = EINVAL;
|
|
|
|
|
wl_connection_consume(connection, size);
|
2012-06-12 17:45:25 -04:00
|
|
|
return NULL;
|
2008-12-24 19:30:25 -05:00
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
num_arrays = wl_message_count_arrays(message);
|
|
|
|
|
closure = malloc(sizeof *closure + size + num_arrays * sizeof *array);
|
|
|
|
|
if (closure == NULL) {
|
|
|
|
|
errno = ENOMEM;
|
|
|
|
|
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
|
|
|
|
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) {
|
2010-08-09 14:34:11 -04:00
|
|
|
printf("message too short, "
|
|
|
|
|
"object (%d), message %s(%s)\n",
|
|
|
|
|
*p, message->name, message->signature);
|
|
|
|
|
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
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
if (length == 0) {
|
|
|
|
|
closure->args[i].s = NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-09 14:34:11 -04:00
|
|
|
next = p + DIV_ROUNDUP(length, sizeof *p);
|
|
|
|
|
if (next > end) {
|
|
|
|
|
printf("message too short, "
|
|
|
|
|
"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
|
|
|
}
|
|
|
|
|
|
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') {
|
2010-09-07 17:00:34 -04:00
|
|
|
printf("string not nul-terminated, "
|
|
|
|
|
"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) {
|
2012-10-09 12:14:34 -04:00
|
|
|
printf("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) {
|
2012-07-23 19:54:41 +01:00
|
|
|
printf("NULL new ID 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 (wl_map_reserve_new(objects, id) < 0) {
|
2012-07-18 15:53:23 +02:00
|
|
|
printf("not a valid new object id (%d), "
|
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
|
|
|
|
|
|
|
|
next = p + DIV_ROUNDUP(length, sizeof *p);
|
|
|
|
|
if (next > end) {
|
|
|
|
|
printf("message too short, "
|
|
|
|
|
"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
|
|
|
}
|
|
|
|
|
|
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-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:
|
|
|
|
|
printf("unknown type\n");
|
2010-08-09 14:34:11 -04:00
|
|
|
assert(0);
|
2008-12-24 19:30:25 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
closure->count = count;
|
|
|
|
|
closure->message = message;
|
2008-12-24 19:30:25 -05:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2012-10-10 19:25:48 -04:00
|
|
|
static int
|
|
|
|
|
interface_equal(const struct wl_interface *a, const struct wl_interface *b)
|
|
|
|
|
{
|
|
|
|
|
/* In most cases the pointer equality test is sufficient.
|
|
|
|
|
* However, in some cases, depending on how things are split
|
|
|
|
|
* across shared objects, we can end up with multiple
|
|
|
|
|
* instances of the interface metadata constants. So if the
|
|
|
|
|
* pointers match, the interfaces are equal, if they don't
|
|
|
|
|
* match we have to compare the interface names. */
|
|
|
|
|
|
|
|
|
|
return a == b || strcmp(a->name, b->name) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
if (object == WL_ZOMBIE_OBJECT) {
|
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) {
|
2012-10-09 12:14:34 -04:00
|
|
|
printf("unknown object (%u), message %s(%s)\n",
|
|
|
|
|
id, message->name, message->signature);
|
2013-02-26 11:30:51 -05:00
|
|
|
object = NULL;
|
2012-10-09 12:14:34 -04:00
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
if (object != NULL && message->types[i] != NULL &&
|
|
|
|
|
!interface_equal((object)->interface,
|
|
|
|
|
message->types[i])) {
|
2012-10-09 12:14:34 -04:00
|
|
|
printf("invalid object (%u), type (%s), "
|
|
|
|
|
"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
|
|
|
|
|
convert_arguments_to_ffi(const char *signature, union wl_argument *args,
|
|
|
|
|
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':
|
|
|
|
|
ffi_types[i] = &ffi_type_uint32;
|
|
|
|
|
ffi_args[i] = &args[i].n;
|
|
|
|
|
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:
|
|
|
|
|
printf("unknown type\n");
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-08-30 09:47:36 -04:00
|
|
|
void
|
|
|
|
|
wl_closure_invoke(struct wl_closure *closure,
|
|
|
|
|
struct wl_object *target, void (*func)(void), void *data)
|
|
|
|
|
{
|
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];
|
|
|
|
|
|
|
|
|
|
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] = ⌖
|
|
|
|
|
|
|
|
|
|
convert_arguments_to_ffi(closure->message->signature, closure->args,
|
|
|
|
|
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-02-26 11:30:51 -05:00
|
|
|
ffi_call(&cif, func, NULL, ffi_args);
|
2010-08-30 09:47:36 -04: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)) {
|
2012-04-21 23:50:09 -04:00
|
|
|
fprintf(stderr, "request could not be marshaled: "
|
|
|
|
|
"can't send file descriptor");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (p + DIV_ROUNDUP(size, sizeof *p) > end)
|
|
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
|
|
memcpy(p, closure->args[i].s, size);
|
|
|
|
|
p += DIV_ROUNDUP(size, sizeof *p);
|
|
|
|
|
break;
|
|
|
|
|
case 'a':
|
|
|
|
|
if (closure->args[i].a == NULL) {
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size = closure->args[i].a->size;
|
|
|
|
|
*p++ = size;
|
|
|
|
|
|
|
|
|
|
if (p + DIV_ROUNDUP(size, sizeof *p) > end)
|
|
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
|
|
memcpy(p, closure->args[i].a->data, size);
|
|
|
|
|
p += DIV_ROUNDUP(size, sizeof *p);
|
|
|
|
|
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
|
|
|
uint32_t buffer[256];
|
|
|
|
|
int size;
|
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-02-26 11:30:51 -05:00
|
|
|
size = serialize_closure(closure, buffer, 256);
|
|
|
|
|
if (size < 0)
|
|
|
|
|
return -1;
|
2012-02-29 11:07:48 -05:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
return wl_connection_write(connection, buffer, size);
|
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
|
|
|
uint32_t buffer[256];
|
|
|
|
|
int size;
|
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-02-26 11:30:51 -05:00
|
|
|
size = serialize_closure(closure, buffer, 256);
|
|
|
|
|
if (size < 0)
|
|
|
|
|
return -1;
|
2012-02-29 11:07:48 -05:00
|
|
|
|
2013-02-26 11:30:51 -05:00
|
|
|
return wl_connection_queue(connection, buffer, size);
|
2011-11-17 16:46:36 -05:00
|
|
|
}
|
|
|
|
|
|
2010-09-07 10:58:19 -04:00
|
|
|
void
|
2011-07-14 18:56:40 +03:00
|
|
|
wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
|
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);
|
|
|
|
|
|
2011-11-22 14:03:33 -05:00
|
|
|
fprintf(stderr, "[%10.3f] %s%s@%u.%s(",
|
2011-07-14 18:56:40 +03:00
|
|
|
time / 1000.0,
|
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':
|
2013-02-26 11:30:51 -05:00
|
|
|
fprintf(stderr, "\"%s\"", closure->args[i].s);
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-30 09:47:36 -04:00
|
|
|
void
|
|
|
|
|
wl_closure_destroy(struct wl_closure *closure)
|
|
|
|
|
{
|
2012-06-12 17:45:25 -04:00
|
|
|
free(closure);
|
2008-12-24 19:30:25 -05:00
|
|
|
}
|