2 * Copyright © 2008 Kristian Høgsberg
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
34 #include "wayland-util.h"
35 #include "connection.h"
37 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
44 struct wl_connection {
45 struct wl_buffer in, out;
48 wl_connection_update_func_t update;
51 struct wl_connection *
52 wl_connection_create(int fd,
53 wl_connection_update_func_t update,
56 struct wl_connection *connection;
58 connection = malloc(sizeof *connection);
59 memset(connection, 0, sizeof *connection);
61 connection->update = update;
62 connection->data = data;
64 connection->update(connection,
65 WL_CONNECTION_READABLE,
72 wl_connection_destroy(struct wl_connection *connection)
74 close(connection->fd);
79 wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
86 if (tail + size <= ARRAY_LENGTH(b->data)) {
87 memcpy(data, b->data + tail, size);
89 rest = ARRAY_LENGTH(b->data) - tail;
90 memcpy(data, b->data + tail, rest);
91 memcpy(data + rest, b->data, size - rest);
96 wl_connection_consume(struct wl_connection *connection, size_t size)
103 if (tail + size <= ARRAY_LENGTH(b->data)) {
106 rest = ARRAY_LENGTH(b->data) - tail;
107 b->tail = size - rest;
111 int wl_connection_data(struct wl_connection *connection, uint32_t mask)
115 int len, head, tail, count, size, available;
117 if (mask & WL_CONNECTION_READABLE) {
119 head = connection->in.head;
120 if (head < b->tail) {
121 iov[0].iov_base = b->data + head;
122 iov[0].iov_len = b->tail - head;
125 size = ARRAY_LENGTH(b->data) - head;
126 iov[0].iov_base = b->data + head;
127 iov[0].iov_len = size;
128 iov[1].iov_base = b->data;
129 iov[1].iov_len = b->tail;
133 len = readv(connection->fd, iov, count);
134 } while (len < 0 && errno == EINTR);
137 "read error from connection %p: %m (%d)\n",
140 } else if (len == 0) {
141 /* FIXME: Handle this better? */
143 } else if (head + len <= ARRAY_LENGTH(b->data)) {
146 b->head = head + len - ARRAY_LENGTH(b->data);
149 /* We know we have data in the buffer at this point,
150 * so if head equals tail, it means the buffer is
153 available = b->head - b->tail;
155 available = sizeof b->data;
156 else if (available < 0)
157 available += ARRAY_LENGTH(b->data);
162 if (mask & WL_CONNECTION_WRITABLE) {
163 b = &connection->out;
165 if (tail < b->head) {
166 iov[0].iov_base = b->data + tail;
167 iov[0].iov_len = b->head - tail;
170 size = ARRAY_LENGTH(b->data) - tail;
171 iov[0].iov_base = b->data + tail;
172 iov[0].iov_len = size;
173 iov[1].iov_base = b->data;
174 iov[1].iov_len = b->head;
178 len = writev(connection->fd, iov, count);
179 } while (len < 0 && errno == EINTR);
181 fprintf(stderr, "write error for connection %p: %m\n", connection);
183 } else if (tail + len <= ARRAY_LENGTH(b->data)) {
186 b->tail = tail + len - ARRAY_LENGTH(b->data);
189 /* We just took data out of the buffer, so at this
190 * point if head equals tail, the buffer is empty. */
192 if (b->tail == b->head)
193 connection->update(connection,
194 WL_CONNECTION_READABLE,
202 wl_connection_write(struct wl_connection *connection, const void *data, size_t count)
208 b = &connection->out;
210 if (head + count <= ARRAY_LENGTH(b->data)) {
211 memcpy(b->data + head, data, count);
214 size = ARRAY_LENGTH(b->data) - head;
215 memcpy(b->data + head, data, size);
216 memcpy(b->data, data + size, count - size);
217 b->head = count - size;
221 connection->update(connection,
222 WL_CONNECTION_READABLE |
223 WL_CONNECTION_WRITABLE,
228 wl_connection_vmarshal(struct wl_connection *connection,
229 struct wl_object *sender,
230 uint32_t opcode, va_list ap,
231 const struct wl_message *message)
233 struct wl_object *object;
234 uint32_t args[32], length, *p, size;
235 struct wl_array *array;
239 count = strlen(message->signature);
240 assert(count <= ARRAY_LENGTH(args));
243 for (i = 0; i < count; i++) {
244 switch (message->signature[i]) {
247 *p++ = va_arg(ap, uint32_t);
250 s = va_arg(ap, const char *);
253 memcpy(p, s, length);
254 p += DIV_ROUNDUP(length, sizeof(*p));
258 object = va_arg(ap, struct wl_object *);
259 *p++ = object ? object->id : 0;
262 array = va_arg(ap, struct wl_array *);
263 if (array == NULL || array->size == 0) {
268 memcpy(p, array->data, array->size);
269 p = (void *) p + array->size;
277 size = (p - args) * sizeof *p;
278 args[0] = sender->id;
279 args[1] = opcode | (size << 16);
280 wl_connection_write(connection, args, size);
284 wl_connection_demarshal(struct wl_connection *connection,
286 struct wl_hash_table *objects,
288 void *data, struct wl_object *target,
289 const struct wl_message *message)
293 uint32_t *p, *next, *end, result, length;
294 int i, count, ret = 0;
300 struct wl_array *array;
303 struct wl_object *object;
306 count = strlen(message->signature) + 2;
307 if (count > ARRAY_LENGTH(types)) {
308 printf("too many args (%d)\n", count);
312 if (sizeof buffer < size) {
313 printf("request too big, should malloc tmp buffer here\n");
317 types[0] = &ffi_type_pointer;
318 values[0].object = data;
319 args[0] = &values[0];
321 types[1] = &ffi_type_pointer;
322 values[1].object = target;
323 args[1] = &values[1];
325 wl_connection_copy(connection, buffer, size);
327 end = (uint32_t *) ((char *) (p + size));
328 for (i = 2; i < count; i++) {
330 printf("message too short, "
331 "object (%d), message %s(%s)\n",
332 *p, message->name, message->signature);
338 switch (message->signature[i - 2]) {
341 types[i] = &ffi_type_uint32;
342 values[i].uint32 = *p++;
345 types[i] = &ffi_type_pointer;
348 next = p + DIV_ROUNDUP(length, sizeof *p);
350 printf("message too short, "
351 "object (%d), message %s(%s)\n",
352 *p, message->name, message->signature);
358 values[i].string = malloc(length + 1);
359 if (values[i].string == NULL) {
364 memcpy(values[i].string, p, length);
365 values[i].string[length] = '\0';
369 types[i] = &ffi_type_pointer;
370 object = wl_hash_table_lookup(objects, *p);
371 if (object == NULL && *p != 0) {
372 printf("unknown object (%d), message %s(%s)\n",
373 *p, message->name, message->signature);
378 values[i].object = object;
382 types[i] = &ffi_type_uint32;
383 values[i].new_id = *p;
384 object = wl_hash_table_lookup(objects, *p);
385 if (object != NULL) {
386 printf("not a new object (%d), "
388 *p, message->name, message->signature);
396 types[i] = &ffi_type_pointer;
399 next = p + DIV_ROUNDUP(length, sizeof *p);
401 printf("message too short, "
402 "object (%d), message %s(%s)\n",
403 *p, message->name, message->signature);
410 malloc(length + sizeof *values[i].array);
411 if (values[i].array == NULL) {
416 values[i].array->size = length;
417 values[i].array->alloc = 0;
418 values[i].array->data = values[i].array + 1;
419 memcpy(values[i].array->data, p, length);
423 printf("unknown type\n");
427 args[i] = &values[i];
430 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
431 ffi_call(&cif, func, &result, args);
435 for (i = 2; i < count; i++) {
436 switch (message->signature[i - 2]) {
438 free(values[i].string);
441 free(values[i].array);