wayland/src/connection.c

990 lines
22 KiB
C
Raw Normal View History

2008-12-02 15:15:01 -05:00
/*
* Copyright © 2008 Kristian Høgsberg
*
* 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.
*/
#define _GNU_SOURCE
#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>
#include <assert.h>
#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>
#include <time.h>
2008-10-08 12:48:46 -04:00
#include "wayland-util.h"
#include "wayland-private.h"
#include "wayland-os.h"
2008-10-08 12:48:46 -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];
int head, tail;
};
#define MASK(i) ((i) & 4095)
#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;
struct wl_buffer fds_in, fds_out;
2008-10-08 12:48:46 -04:00
int fd;
void *data;
wl_connection_update_func_t update;
int write_signalled;
2008-10-08 12:48:46 -04:00
};
union wl_value {
uint32_t uint32;
char *string;
struct wl_object *object;
uint32_t new_id;
struct wl_array *array;
};
static void
wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
{
int head, size;
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)
{
int head, tail;
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)
{
int head, tail;
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)
{
int tail, size;
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);
}
}
static int
wl_buffer_size(struct wl_buffer *b)
{
return b->head - b->tail;
}
2008-10-08 12:48:46 -04:00
struct wl_connection *
wl_connection_create(int fd,
wl_connection_update_func_t update,
void *data)
{
struct wl_connection *connection;
connection = malloc(sizeof *connection);
if (connection == NULL)
return NULL;
2008-10-08 12:48:46 -04:00
memset(connection, 0, sizeof *connection);
connection->fd = fd;
connection->update = update;
connection->data = data;
connection->update(connection,
WL_CONNECTION_READABLE,
connection->data);
return connection;
}
void
wl_connection_destroy(struct wl_connection *connection)
{
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)
{
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)
{
connection->in.tail += size;
2008-10-08 12:48:46 -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;
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;
}
}
static void
close_fds(struct wl_buffer *buffer)
{
int fds[MAX_FDS_OUT], i, count;
size_t size;
size = buffer->head - buffer->tail;
if (size == 0)
return;
wl_buffer_copy(buffer, fds, size);
count = size / sizeof fds[0];
for (i = 0; i < count; i++)
close(fds[i]);
buffer->tail += size;
}
static void
decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg)
{
struct cmsghdr *cmsg;
size_t size;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
size = cmsg->cmsg_len - CMSG_LEN(0);
wl_buffer_put(buffer, CMSG_DATA(cmsg), size);
}
}
}
int
wl_connection_data(struct wl_connection *connection, uint32_t mask)
2008-10-08 12:48:46 -04:00
{
struct iovec iov[2];
2010-08-25 17:11:29 -04:00
struct msghdr msg;
char cmsg[CLEN];
int len, count, clen;
2008-10-08 12:48:46 -04:00
if (mask & WL_CONNECTION_WRITABLE) {
wl_buffer_get_iov(&connection->out, iov, &count);
build_cmsg(&connection->fds_out, cmsg, &clen);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = count;
msg.msg_control = cmsg;
msg.msg_controllen = clen;
msg.msg_flags = 0;
do {
len = sendmsg(connection->fd, &msg,
MSG_NOSIGNAL | MSG_DONTWAIT);
} while (len < 0 && errno == EINTR);
if (len == -1 && errno == EPIPE) {
return -1;
} else if (len < 0) {
2008-10-08 12:48:46 -04:00
fprintf(stderr,
"write error for connection %p, fd %d: %m\n",
connection, connection->fd);
2008-10-08 12:48:46 -04:00
return -1;
}
close_fds(&connection->fds_out);
2008-10-08 12:48:46 -04:00
connection->out.tail += len;
if (connection->out.tail == connection->out.head &&
connection->write_signalled) {
connection->update(connection,
WL_CONNECTION_READABLE,
connection->data);
connection->write_signalled = 0;
}
}
if (mask & WL_CONNECTION_READABLE) {
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;
do {
len = wl_os_recvmsg_cloexec(connection->fd, &msg, 0);
} while (len < 0 && errno == EINTR);
2008-10-08 12:48:46 -04:00
if (len < 0) {
fprintf(stderr,
"read error from connection %p: %m (%d)\n",
connection, errno);
return -1;
} else if (len == 0) {
/* FIXME: Handle this better? */
2008-10-08 12:48:46 -04:00
return -1;
}
decode_cmsg(&connection->fds_in, &msg);
connection->in.head += len;
}
2008-10-08 12:48:46 -04:00
return connection->in.head - connection->in.tail;
2008-10-08 12:48:46 -04:00
}
int
wl_connection_write(struct wl_connection *connection,
const void *data, size_t count)
2008-10-08 12:48:46 -04:00
{
if (connection->out.head - connection->out.tail +
count > ARRAY_LENGTH(connection->out.data))
if (wl_connection_data(connection, WL_CONNECTION_WRITABLE))
return -1;
wl_buffer_put(&connection->out, data, count);
2008-10-08 12:48:46 -04:00
if (!connection->write_signalled) {
2008-10-08 12:48:46 -04:00
connection->update(connection,
WL_CONNECTION_READABLE |
WL_CONNECTION_WRITABLE,
connection->data);
connection->write_signalled = 1;
}
return 0;
}
int
wl_connection_queue(struct wl_connection *connection,
const void *data, size_t count)
{
if (connection->out.head - connection->out.tail +
count > ARRAY_LENGTH(connection->out.data))
if (wl_connection_data(connection, WL_CONNECTION_WRITABLE))
return -1;
wl_buffer_put(&connection->out, data, count);
return 0;
2008-10-08 12:48:46 -04:00
}
static int
wl_message_size_extra(const struct wl_message *message)
{
int i, extra;
for (i = 0, extra = 0; message->signature[i]; i++) {
switch (message->signature[i]) {
case 's':
case 'o':
case 'n':
extra += sizeof (void *);
break;
case 'a':
extra += sizeof (void *) + sizeof (struct wl_array);
break;
case 'h':
extra += sizeof (int);
break;
default:
break;
}
}
return extra;
}
static int
wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
{
if (wl_buffer_size(&connection->fds_out) == MAX_FDS_OUT * sizeof fd)
if (wl_connection_data(connection, WL_CONNECTION_WRITABLE))
return -1;
wl_buffer_put(&connection->fds_out, &fd, sizeof fd);
return 0;
}
const char *
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;
}
int
arg_count_for_signature(const char *signature)
{
int count = 0;
while (*signature) {
if (*signature != '?')
count++;
signature++;
}
return count;
}
struct wl_closure *
wl_closure_vmarshal(struct wl_object *sender,
uint32_t opcode, va_list ap,
const struct wl_message *message)
{
struct wl_closure *closure;
struct wl_object **objectp, *object;
uint32_t length, aligned, *p, *start, size, *end;
int dup_fd;
struct wl_array **arrayp, *array;
const char **sp, *s;
const char *signature = message->signature;
struct argument_details arg;
char *extra;
int i, count, fd, extra_size, *fd_ptr;
/* FIXME: Match old fixed allocation for now */
closure = malloc(sizeof *closure + 1024);
if (closure == NULL)
return NULL;
extra_size = wl_message_size_extra(message);
count = arg_count_for_signature(signature) + 2;
extra = (char *) closure->buffer;
start = &closure->buffer[DIV_ROUNDUP(extra_size, sizeof *p)];
end = &closure->buffer[256];
p = &start[2];
closure->types[0] = &ffi_type_pointer;
closure->types[1] = &ffi_type_pointer;
for (i = 2; i < count; i++) {
signature = get_next_argument(signature, &arg);
switch (arg.type) {
case 'f':
closure->types[i] = &ffi_type_sint32;
closure->args[i] = p;
if (end - p < 1)
goto err;
*p++ = va_arg(ap, wl_fixed_t);
break;
case 'u':
closure->types[i] = &ffi_type_uint32;
closure->args[i] = p;
if (end - p < 1)
goto err;
*p++ = va_arg(ap, uint32_t);
break;
case 'i':
closure->types[i] = &ffi_type_sint32;
closure->args[i] = p;
if (end - p < 1)
goto err;
*p++ = va_arg(ap, int32_t);
break;
case 's':
closure->types[i] = &ffi_type_pointer;
closure->args[i] = extra;
sp = (const char **) extra;
extra += sizeof *sp;
s = va_arg(ap, const char *);
if (!arg.nullable && s == NULL)
goto err_null;
length = s ? strlen(s) + 1: 0;
aligned = (length + 3) & ~3;
if (p + aligned / sizeof *p + 1 > end)
goto err;
*p++ = length;
2010-09-07 22:15:22 -04:00
if (length > 0)
*sp = (const char *) p;
else
*sp = NULL;
memcpy(p, s, length);
memset((char *) p + length, 0, aligned - length);
p += aligned / sizeof *p;
break;
case 'o':
closure->types[i] = &ffi_type_pointer;
closure->args[i] = extra;
objectp = (struct wl_object **) extra;
extra += sizeof *objectp;
object = va_arg(ap, struct wl_object *);
if (!arg.nullable && object == NULL)
goto err_null;
*objectp = object;
if (end - p < 1)
goto err;
2009-02-22 20:57:57 -05:00
*p++ = object ? object->id : 0;
break;
case 'n':
closure->types[i] = &ffi_type_uint32;
closure->args[i] = p;
object = va_arg(ap, struct wl_object *);
if (end - p < 1)
goto err;
if (!arg.nullable && object == NULL)
goto err_null;
*p++ = object ? object->id : 0;
break;
case 'a':
closure->types[i] = &ffi_type_pointer;
closure->args[i] = extra;
arrayp = (struct wl_array **) extra;
extra += sizeof *arrayp;
*arrayp = (struct wl_array *) extra;
extra += sizeof **arrayp;
array = va_arg(ap, struct wl_array *);
if (!arg.nullable && array == NULL)
goto err_null;
if (array == NULL || array->size == 0) {
if (end - p < 1)
goto err;
*p++ = 0;
break;
}
2012-03-30 10:36:57 -04:00
if (p + DIV_ROUNDUP(array->size, sizeof *p) + 1 > end)
goto err;
*p++ = array->size;
memcpy(p, array->data, array->size);
(*arrayp)->size = array->size;
(*arrayp)->alloc = array->alloc;
(*arrayp)->data = p;
p += DIV_ROUNDUP(array->size, sizeof *p);
break;
case 'h':
closure->types[i] = &ffi_type_sint;
closure->args[i] = extra;
fd_ptr = (int *) extra;
extra += sizeof *fd_ptr;
fd = va_arg(ap, int);
dup_fd = wl_os_dupfd_cloexec(fd, 0);
if (dup_fd < 0) {
fprintf(stderr, "dup failed: %m");
abort();
}
*fd_ptr = dup_fd;
break;
default:
fprintf(stderr, "unhandled format code: '%c'\n",
arg.type);
assert(0);
break;
}
}
size = (p - start) * sizeof *p;
start[0] = sender->id;
start[1] = opcode | (size << 16);
closure->start = start;
closure->message = message;
closure->count = count;
ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI,
closure->count, &ffi_type_void, closure->types);
return closure;
err:
printf("request too big to marshal, maximum size is %zu\n",
sizeof closure->buffer);
errno = ENOMEM;
free(closure);
return NULL;
err_null:
free(closure);
wl_log("error marshalling arguments for %s:%i.%s (signature %s): "
"null value passed for arg %i\n",
sender->interface->name, sender->id, message->name,
message->signature, i);
errno = EINVAL;
return NULL;
}
struct wl_closure *
wl_connection_demarshal(struct wl_connection *connection,
uint32_t size,
struct wl_map *objects,
const struct wl_message *message)
{
uint32_t *p, *next, *end, length, **id;
int *fd;
char *extra, **s;
2012-03-30 10:36:57 -04:00
unsigned int i, count, extra_space;
const char *signature = message->signature;
struct argument_details arg;
struct wl_object **object;
struct wl_array **array;
struct wl_closure *closure;
count = arg_count_for_signature(signature) + 2;
if (count > ARRAY_LENGTH(closure->types)) {
printf("too many args (%d)\n", count);
errno = EINVAL;
wl_connection_consume(connection, size);
return NULL;
}
extra_space = wl_message_size_extra(message);
closure = malloc(sizeof *closure + 8 + size + extra_space);
if (closure == NULL)
return NULL;
closure->message = message;
closure->types[0] = &ffi_type_pointer;
closure->types[1] = &ffi_type_pointer;
closure->start = closure->buffer;
wl_connection_copy(connection, closure->buffer, size);
p = &closure->buffer[2];
end = (uint32_t *) ((char *) p + size);
extra = (char *) end;
for (i = 2; i < count; i++) {
signature = get_next_argument(signature, &arg);
2010-08-09 14:34:11 -04:00
if (p + 1 > end) {
printf("message too short, "
"object (%d), message %s(%s)\n",
*p, message->name, message->signature);
errno = EINVAL;
goto err;
2010-08-09 14:34:11 -04:00
}
switch (arg.type) {
case 'u':
closure->types[i] = &ffi_type_uint32;
closure->args[i] = p++;
break;
case 'i':
closure->types[i] = &ffi_type_sint32;
closure->args[i] = p++;
break;
case 'f':
closure->types[i] = &ffi_type_sint32;
closure->args[i] = p++;
break;
case 's':
closure->types[i] = &ffi_type_pointer;
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",
*p, message->name, message->signature);
errno = EINVAL;
goto err;
2010-08-09 14:34:11 -04:00
}
s = (char **) extra;
extra += sizeof *s;
closure->args[i] = s;
2010-08-27 22:16:50 -04:00
if (length == 0) {
*s = NULL;
2010-08-27 22:16:50 -04:00
} else {
*s = (char *) p;
}
if (length > 0 && (*s)[length - 1] != '\0') {
printf("string not nul-terminated, "
"message %s(%s)\n",
message->name, message->signature);
errno = EINVAL;
goto err;
}
2010-08-09 14:34:11 -04:00
p = next;
break;
case 'o':
closure->types[i] = &ffi_type_pointer;
object = (struct wl_object **) extra;
extra += sizeof *object;
closure->args[i] = object;
if (*p == 0 && !arg.nullable) {
printf("NULL new ID received on non-nullable "
"type, message %s(%s)\n", message->name,
message->signature);
*object = NULL;
errno = EINVAL;
goto err;
}
*object = wl_map_lookup(objects, *p);
if (*object == WL_ZOMBIE_OBJECT) {
/* references object we've already
* destroyed client side */
*object = NULL;
} else if (*object == NULL && *p != 0) {
printf("unknown object (%u), message %s(%s)\n",
2010-07-28 23:47:16 -04:00
*p, message->name, message->signature);
*object = NULL;
2010-08-09 14:34:11 -04:00
errno = EINVAL;
goto err;
2010-08-09 14:34:11 -04:00
}
if (*object != NULL && message->types[i-2] != NULL &&
(*object)->interface != message->types[i-2]) {
printf("invalid object (%u), type (%s), "
"message %s(%s)\n",
*p, (*object)->interface->name,
message->name, message->signature);
errno = EINVAL;
goto err;
}
p++;
break;
case 'n':
closure->types[i] = &ffi_type_pointer;
id = (uint32_t **) extra;
extra += sizeof *id;
closure->args[i] = id;
*id = p;
if (*id == 0 && !arg.nullable) {
printf("NULL new ID received on non-nullable "
"type, message %s(%s)\n", message->name,
message->signature);
errno = EINVAL;
goto err;
}
if (wl_map_reserve_new(objects, *p) < 0) {
printf("not a valid new object id (%d), "
2010-08-09 14:34:11 -04:00
"message %s(%s)\n",
*p, message->name, message->signature);
errno = EINVAL;
goto err;
2010-08-09 14:34:11 -04:00
}
p++;
break;
case 'a':
closure->types[i] = &ffi_type_pointer;
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",
*p, message->name, message->signature);
errno = EINVAL;
goto err;
2010-08-09 14:34:11 -04:00
}
array = (struct wl_array **) extra;
extra += sizeof *array;
closure->args[i] = array;
*array = (struct wl_array *) extra;
extra += sizeof **array;
(*array)->size = length;
(*array)->alloc = 0;
(*array)->data = p;
2010-08-09 14:34:11 -04:00
p = next;
break;
case 'h':
closure->types[i] = &ffi_type_sint;
fd = (int *) extra;
extra += sizeof *fd;
closure->args[i] = fd;
wl_buffer_copy(&connection->fds_in, fd, sizeof *fd);
connection->fds_in.tail += sizeof *fd;
break;
default:
printf("unknown type\n");
2010-08-09 14:34:11 -04:00
assert(0);
break;
}
}
closure->count = i;
ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI,
closure->count, &ffi_type_void, closure->types);
wl_connection_consume(connection, size);
return closure;
err:
closure->count = i;
wl_closure_destroy(closure);
wl_connection_consume(connection, size);
return NULL;
}
void
wl_closure_invoke(struct wl_closure *closure,
struct wl_object *target, void (*func)(void), void *data)
{
int result;
closure->args[0] = &data;
closure->args[1] = &target;
ffi_call(&closure->cif, func, &result, closure->args);
}
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;
struct argument_details arg;
const char *signature = message->signature;
int *fd;
count = arg_count_for_signature(signature) + 2;
for (i = 2; i < count; i++) {
signature = get_next_argument(signature, &arg);
if (arg.type != 'h')
continue;
fd = closure->args[i];
if (wl_connection_put_fd(connection, *fd)) {
fprintf(stderr, "request could not be marshaled: "
"can't send file descriptor");
return -1;
}
}
return 0;
}
int
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
{
uint32_t size;
if (copy_fds_to_connection(closure, connection))
return -1;
size = closure->start[1] >> 16;
return wl_connection_write(connection, closure->start, size);
}
int
wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
{
uint32_t size;
if (copy_fds_to_connection(closure, connection))
return -1;
size = closure->start[1] >> 16;
return wl_connection_queue(connection, closure->start, size);
}
2010-09-07 10:58:19 -04:00
void
wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
2010-09-07 10:58:19 -04:00
{
union wl_value *value;
int32_t si;
2010-09-07 10:58:19 -04:00
int i;
struct argument_details arg;
const char *signature = closure->message->signature;
struct timespec tp;
unsigned int time;
2010-09-07 10:58:19 -04: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(",
time / 1000.0,
send ? " -> " : "",
2010-09-07 10:58:19 -04:00
target->interface->name, target->id,
closure->message->name);
for (i = 2; i < closure->count; i++) {
signature = get_next_argument(signature, &arg);
2010-09-07 10:58:19 -04:00
if (i > 2)
fprintf(stderr, ", ");
value = closure->args[i];
switch (arg.type) {
2010-09-07 10:58:19 -04:00
case 'u':
fprintf(stderr, "%u", value->uint32);
2010-09-07 10:58:19 -04:00
break;
case 'i':
si = (int32_t) value->uint32;
fprintf(stderr, "%d", si);
break;
case 'f':
si = (int32_t) value->uint32;
fprintf(stderr, "%f", wl_fixed_to_double(si));
2010-09-07 10:58:19 -04:00
break;
case 's':
fprintf(stderr, "\"%s\"", value->string);
2010-09-07 10:58:19 -04:00
break;
case 'o':
if (value->object)
fprintf(stderr, "%s@%u",
value->object->interface->name,
value->object->id);
else
fprintf(stderr, "nil");
2010-09-07 10:58:19 -04:00
break;
case 'n':
fprintf(stderr, "new id %s@",
(closure->message->types[i - 2]) ?
closure->message->types[i - 2]->name :
"[unknown]");
if (send && value->new_id != 0)
fprintf(stderr, "%u", value->new_id);
else if (!send && value->object != NULL)
fprintf(stderr, "%u",
*((uint32_t *)value->object));
else
fprintf(stderr, "nil");
2010-09-07 10:58:19 -04:00
break;
case 'a':
fprintf(stderr, "array");
break;
case 'h':
fprintf(stderr, "fd %d", value->uint32);
2010-09-07 10:58:19 -04:00
break;
}
}
fprintf(stderr, ")\n");
}
void
wl_closure_destroy(struct wl_closure *closure)
{
free(closure);
}