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
32 #include "wayland-util.h"
33 #include "connection.h"
35 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
42 struct wl_connection {
43 struct wl_buffer in, out;
46 wl_connection_update_func_t update;
49 struct wl_connection *
50 wl_connection_create(int fd,
51 wl_connection_update_func_t update,
54 struct wl_connection *connection;
56 connection = malloc(sizeof *connection);
57 memset(connection, 0, sizeof *connection);
59 connection->update = update;
60 connection->data = data;
62 connection->update(connection,
63 WL_CONNECTION_READABLE,
70 wl_connection_destroy(struct wl_connection *connection)
76 wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
83 if (tail + size <= ARRAY_LENGTH(b->data)) {
84 memcpy(data, b->data + tail, size);
86 rest = ARRAY_LENGTH(b->data) - tail;
87 memcpy(data, b->data + tail, rest);
88 memcpy(data + rest, b->data, size - rest);
93 wl_connection_consume(struct wl_connection *connection, size_t size)
100 if (tail + size <= ARRAY_LENGTH(b->data)) {
103 rest = ARRAY_LENGTH(b->data) - tail;
104 b->tail = size - rest;
108 int wl_connection_data(struct wl_connection *connection, uint32_t mask)
112 int len, head, tail, count, size, available;
114 if (mask & WL_CONNECTION_READABLE) {
116 head = connection->in.head;
117 if (head < b->tail) {
118 iov[0].iov_base = b->data + head;
119 iov[0].iov_len = b->tail - head;
122 size = ARRAY_LENGTH(b->data) - head;
123 iov[0].iov_base = b->data + head;
124 iov[0].iov_len = size;
125 iov[1].iov_base = b->data;
126 iov[1].iov_len = b->tail;
130 len = readv(connection->fd, iov, count);
131 } while (len < 0 && errno == EINTR);
134 "read error from connection %p: %m (%d)\n",
137 } else if (len == 0) {
138 /* FIXME: Handle this better? */
140 } else if (head + len <= ARRAY_LENGTH(b->data)) {
143 b->head = head + len - ARRAY_LENGTH(b->data);
146 /* We know we have data in the buffer at this point,
147 * so if head equals tail, it means the buffer is
150 available = b->head - b->tail;
152 available = sizeof b->data;
153 else if (available < 0)
154 available += ARRAY_LENGTH(b->data);
159 if (mask & WL_CONNECTION_WRITABLE) {
160 b = &connection->out;
162 if (tail < b->head) {
163 iov[0].iov_base = b->data + tail;
164 iov[0].iov_len = b->head - tail;
167 size = ARRAY_LENGTH(b->data) - tail;
168 iov[0].iov_base = b->data + tail;
169 iov[0].iov_len = size;
170 iov[1].iov_base = b->data;
171 iov[1].iov_len = b->head;
175 len = writev(connection->fd, iov, count);
176 } while (len < 0 && errno == EINTR);
178 fprintf(stderr, "write error for connection %p: %m\n", connection);
180 } else if (tail + len <= ARRAY_LENGTH(b->data)) {
183 b->tail = tail + len - ARRAY_LENGTH(b->data);
186 /* We just took data out of the buffer, so at this
187 * point if head equals tail, the buffer is empty. */
189 if (b->tail == b->head)
190 connection->update(connection,
191 WL_CONNECTION_READABLE,
199 wl_connection_write(struct wl_connection *connection, const void *data, size_t count)
205 b = &connection->out;
207 if (head + count <= ARRAY_LENGTH(b->data)) {
208 memcpy(b->data + head, data, count);
211 size = ARRAY_LENGTH(b->data) - head;
212 memcpy(b->data + head, data, size);
213 memcpy(b->data, data + size, count - size);
214 b->head = count - size;
218 connection->update(connection,
219 WL_CONNECTION_READABLE |
220 WL_CONNECTION_WRITABLE,
225 wl_connection_vmarshal(struct wl_connection *connection,
226 struct wl_object *sender,
227 uint32_t opcode, va_list ap,
228 const struct wl_message *message)
230 struct wl_object *object;
231 uint32_t args[32], length, *p, size;
232 struct wl_array *array;
236 count = strlen(message->signature);
237 assert(count <= ARRAY_LENGTH(args));
240 for (i = 0; i < count; i++) {
241 switch (message->signature[i]) {
244 *p++ = va_arg(ap, uint32_t);
247 s = va_arg(ap, const char *);
250 memcpy(p, s, length);
251 p += DIV_ROUNDUP(length, sizeof(*p));
255 object = va_arg(ap, struct wl_object *);
256 *p++ = object ? object->id : 0;
259 array = va_arg(ap, struct wl_array *);
260 if (array == NULL || array->size == 0) {
265 memcpy(p, array->data, array->size);
266 p = (void *) p + array->size;
274 size = (p - args) * sizeof *p;
275 args[0] = sender->id;
276 args[1] = opcode | (size << 16);
277 wl_connection_write(connection, args, size);
281 wl_connection_demarshal(struct wl_connection *connection,
283 struct wl_hash_table *objects,
285 void *data, struct wl_object *target,
286 const struct wl_message *message)
290 uint32_t *p, result, length;
297 struct wl_array *array;
300 struct wl_object *object;
303 count = strlen(message->signature) + 2;
304 if (count > ARRAY_LENGTH(types)) {
305 printf("too many args (%d)\n", count);
309 if (sizeof buffer < size) {
310 printf("request too big, should malloc tmp buffer here\n");
314 types[0] = &ffi_type_pointer;
315 values[0].object = data;
316 args[0] = &values[0];
318 types[1] = &ffi_type_pointer;
319 values[1].object = target;
320 args[1] = &values[1];
322 wl_connection_copy(connection, buffer, size);
324 for (i = 2; i < count; i++) {
325 switch (message->signature[i - 2]) {
328 types[i] = &ffi_type_uint32;
329 values[i].uint32 = *p++;
332 types[i] = &ffi_type_pointer;
334 values[i].string = malloc(length + 1);
335 if (values[i].string == NULL) {
336 /* FIXME: Send NO_MEMORY */
339 memcpy(values[i].string, p, length);
340 values[i].string[length] = '\0';
341 p += DIV_ROUNDUP(length, sizeof *p);
344 types[i] = &ffi_type_pointer;
345 object = wl_hash_table_lookup(objects, *p);
346 if (object == NULL && *p != 0)
347 printf("unknown object (%d), message %s(%s)\n",
348 *p, message->name, message->signature);
349 values[i].object = object;
353 types[i] = &ffi_type_uint32;
354 values[i].new_id = *p;
355 object = wl_hash_table_lookup(objects, *p);
357 printf("object already exists (%d)\n", *p);
361 types[i] = &ffi_type_pointer;
363 values[i].array = malloc(length + sizeof *values[i].array);
364 if (values[i].array == NULL) {
365 /* FIXME: Send NO_MEMORY */
368 values[i].array->size = length;
369 values[i].array->alloc = 0;
370 values[i].array->data = values[i].array + 1;
371 memcpy(values[i].array->data, p, length);
372 p += DIV_ROUNDUP(length, sizeof *p);
375 printf("unknown type\n");
378 args[i] = &values[i];
381 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
382 ffi_call(&cif, func, &result, args);
384 for (i = 2; i < count; i++) {
385 switch (message->signature[i - 2]) {
387 free(values[i].string);
390 free(values[i].array);