| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											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]); | 
					
						
							|  |  |  | 		} 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') | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 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); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } |