Generate client side marshal stubs from protocol spec
[profile/ivi/wayland.git] / connection.c
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  *
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.
13  *
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
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <sys/uio.h>
29 #include <ffi.h>
30 #include <assert.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33
34 #include "wayland-util.h"
35 #include "connection.h"
36
37 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
38
39 struct wl_buffer {
40         char data[4096];
41         int head, tail;
42 };
43
44 struct wl_connection {
45         struct wl_buffer in, out;
46         int fd;
47         void *data;
48         wl_connection_update_func_t update;
49 };
50
51 struct wl_connection *
52 wl_connection_create(int fd,
53                      wl_connection_update_func_t update,
54                      void *data)
55 {
56         struct wl_connection *connection;
57
58         connection = malloc(sizeof *connection);
59         memset(connection, 0, sizeof *connection);
60         connection->fd = fd;
61         connection->update = update;
62         connection->data = data;
63
64         connection->update(connection,
65                            WL_CONNECTION_READABLE,
66                            connection->data);
67
68         return connection;
69 }
70
71 void
72 wl_connection_destroy(struct wl_connection *connection)
73 {
74         close(connection->fd);
75         free(connection);
76 }
77
78 void
79 wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
80 {
81         struct wl_buffer *b;
82         int tail, rest;
83
84         b = &connection->in;
85         tail = b->tail;
86         if (tail + size <= ARRAY_LENGTH(b->data)) {
87                 memcpy(data, b->data + tail, size);
88         } else { 
89                 rest = ARRAY_LENGTH(b->data) - tail;
90                 memcpy(data, b->data + tail, rest);
91                 memcpy(data + rest, b->data, size - rest);
92         }
93 }
94
95 void
96 wl_connection_consume(struct wl_connection *connection, size_t size)
97 {
98         struct wl_buffer *b;
99         int tail, rest;
100
101         b = &connection->in;
102         tail = b->tail;
103         if (tail + size <= ARRAY_LENGTH(b->data)) {
104                 b->tail += size;
105         } else { 
106                 rest = ARRAY_LENGTH(b->data) - tail;
107                 b->tail = size - rest;
108         }
109 }
110
111 int wl_connection_data(struct wl_connection *connection, uint32_t mask)
112 {
113         struct wl_buffer *b;
114         struct iovec iov[2];
115         int len, head, tail, count, size, available;
116
117         if (mask & WL_CONNECTION_READABLE) {
118                 b = &connection->in;
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;
123                         count = 1;
124                 } else {
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;
130                         count = 2;
131                 }
132                 do {
133                         len = readv(connection->fd, iov, count);
134                 } while (len < 0 && errno == EINTR);
135                 if (len < 0) {
136                         fprintf(stderr,
137                                 "read error from connection %p: %m (%d)\n",
138                                 connection, errno);
139                         return -1;
140                 } else if (len == 0) {
141                         /* FIXME: Handle this better? */
142                         return -1;
143                 } else if (head + len <= ARRAY_LENGTH(b->data)) {
144                         b->head += len;
145                 } else {
146                         b->head = head + len - ARRAY_LENGTH(b->data);
147                 }
148
149                 /* We know we have data in the buffer at this point,
150                  * so if head equals tail, it means the buffer is
151                  * full. */
152
153                 available = b->head - b->tail;
154                 if (available == 0)
155                         available = sizeof b->data;
156                 else if (available < 0)
157                         available += ARRAY_LENGTH(b->data);
158         } else {
159                 available = 0;
160         }       
161
162         if (mask & WL_CONNECTION_WRITABLE) {
163                 b = &connection->out;
164                 tail = b->tail;
165                 if (tail < b->head) {
166                         iov[0].iov_base = b->data + tail;
167                         iov[0].iov_len = b->head - tail;
168                         count = 1;
169                 } else {
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;
175                         count = 2;
176                 }
177                 do {
178                         len = writev(connection->fd, iov, count);
179                 } while (len < 0 && errno == EINTR);
180                 if (len < 0) {
181                         fprintf(stderr, "write error for connection %p: %m\n", connection);
182                         return -1;
183                 } else if (tail + len <= ARRAY_LENGTH(b->data)) {
184                         b->tail += len;
185                 } else {
186                         b->tail = tail + len - ARRAY_LENGTH(b->data);
187                 }
188
189                 /* We just took data out of the buffer, so at this
190                  * point if head equals tail, the buffer is empty. */
191
192                 if (b->tail == b->head)
193                         connection->update(connection,
194                                            WL_CONNECTION_READABLE,
195                                            connection->data);
196         }
197
198         return available;
199 }
200
201 void
202 wl_connection_write(struct wl_connection *connection, const void *data, size_t count)
203 {
204         struct wl_buffer *b;
205         size_t size;
206         int head;
207
208         b = &connection->out;
209         head = b->head;
210         if (head + count <= ARRAY_LENGTH(b->data)) {
211                 memcpy(b->data + head, data, count);
212                 b->head += count;
213         } else {
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;
218         }
219
220         if (b->tail == head)
221                 connection->update(connection,
222                                    WL_CONNECTION_READABLE |
223                                    WL_CONNECTION_WRITABLE,
224                                    connection->data);
225 }
226
227 void
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)
232 {
233         struct wl_object *object;
234         uint32_t args[32], length, *p, size;
235         struct wl_array *array;
236         const char *s;
237         int i, count;
238
239         count = strlen(message->signature);
240         assert(count <= ARRAY_LENGTH(args));
241
242         p = &args[2];
243         for (i = 0; i < count; i++) {
244                 switch (message->signature[i]) {
245                 case 'u':
246                 case 'i':
247                         *p++ = va_arg(ap, uint32_t);
248                         break;
249                 case 's':
250                         s = va_arg(ap, const char *);
251                         length = strlen(s);
252                         *p++ = length;
253                         memcpy(p, s, length);
254                         p += DIV_ROUNDUP(length, sizeof(*p));
255                         break;
256                 case 'o':
257                 case 'n':
258                         object = va_arg(ap, struct wl_object *);
259                         *p++ = object ? object->id : 0;
260                         break;
261                 case 'a':
262                         array = va_arg(ap, struct wl_array *);
263                         if (array == NULL || array->size == 0) {
264                                 *p++ = 0;
265                                 break;
266                         }
267                         *p++ = array->size;
268                         memcpy(p, array->data, array->size);
269                         p = (void *) p + array->size;
270                         break;
271                 default:
272                         assert(0);
273                         break;
274                 }
275         }
276
277         size = (p - args) * sizeof *p;
278         args[0] = sender->id;
279         args[1] = opcode | (size << 16);
280         wl_connection_write(connection, args, size);
281 }
282
283 int
284 wl_connection_demarshal(struct wl_connection *connection,
285                         uint32_t size,
286                         struct wl_hash_table *objects,
287                         void (*func)(void),
288                         void *data, struct wl_object *target,
289                         const struct wl_message *message)
290 {
291         ffi_type *types[20];
292         ffi_cif cif;
293         uint32_t *p, *next, *end, result, length;
294         int i, count, ret = 0;
295         union {
296                 uint32_t uint32;
297                 char *string;
298                 void *object;
299                 uint32_t new_id;
300                 struct wl_array *array;
301         } values[20];
302         void *args[20];
303         struct wl_object *object;
304         uint32_t buffer[64];
305
306         count = strlen(message->signature) + 2;
307         if (count > ARRAY_LENGTH(types)) {
308                 printf("too many args (%d)\n", count);
309                 assert(0);
310         }
311
312         if (sizeof buffer < size) {
313                 printf("request too big, should malloc tmp buffer here\n");
314                 assert(0);
315         }
316
317         types[0] = &ffi_type_pointer;
318         values[0].object = data;
319         args[0] =  &values[0];
320
321         types[1] = &ffi_type_pointer;
322         values[1].object = target;
323         args[1] =  &values[1];
324
325         wl_connection_copy(connection, buffer, size);
326         p = &buffer[2];
327         end = (uint32_t *) ((char *) (p + size));
328         for (i = 2; i < count; i++) {
329                 if (p + 1 > end) {
330                         printf("message too short, "
331                                "object (%d), message %s(%s)\n",
332                                *p, message->name, message->signature);
333                         errno = EINVAL;
334                         ret = -1;
335                         goto out;
336                 }
337
338                 switch (message->signature[i - 2]) {
339                 case 'u':
340                 case 'i':
341                         types[i] = &ffi_type_uint32;
342                         values[i].uint32 = *p++;
343                         break;
344                 case 's':
345                         types[i] = &ffi_type_pointer;
346                         length = *p++;
347
348                         next = p + DIV_ROUNDUP(length, sizeof *p);
349                         if (next > end) {
350                                 printf("message too short, "
351                                        "object (%d), message %s(%s)\n",
352                                        *p, message->name, message->signature);
353                                 errno = EINVAL;
354                                 ret = -1;
355                                 goto out;
356                         }
357
358                         values[i].string = malloc(length + 1);
359                         if (values[i].string == NULL) {
360                                 errno = ENOMEM;
361                                 ret = -1;
362                                 goto out;
363                         }
364                         memcpy(values[i].string, p, length);
365                         values[i].string[length] = '\0';
366                         p = next;
367                         break;
368                 case 'o':
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);
374                                 errno = EINVAL;
375                                 ret = -1;
376                                 goto out;
377                         }
378                         values[i].object = object;
379                         p++;
380                         break;
381                 case 'n':
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), "
387                                        "message %s(%s)\n",
388                                        *p, message->name, message->signature);
389                                 errno = EINVAL;
390                                 ret = -1;
391                                 goto out;
392                         }
393                         p++;
394                         break;
395                 case 'a':
396                         types[i] = &ffi_type_pointer;
397                         length = *p++;
398
399                         next = p + DIV_ROUNDUP(length, sizeof *p);
400                         if (next > end) {
401                                 printf("message too short, "
402                                        "object (%d), message %s(%s)\n",
403                                        *p, message->name, message->signature);
404                                 errno = EINVAL;
405                                 ret = -1;
406                                 goto out;
407                         }
408
409                         values[i].array =
410                                 malloc(length + sizeof *values[i].array);
411                         if (values[i].array == NULL) {
412                                 errno = ENOMEM;
413                                 ret = -1;
414                                 goto out;
415                         }
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);
420                         p = next;
421                         break;
422                 default:
423                         printf("unknown type\n");
424                         assert(0);
425                         break;
426                 }
427                 args[i] = &values[i];
428         }
429
430         ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
431         ffi_call(&cif, func, &result, args);
432
433  out:
434         count = i;
435         for (i = 2; i < count; i++) {
436                 switch (message->signature[i - 2]) {
437                 case 's':
438                         free(values[i].string);
439                         break;
440                 case 'a':
441                         free(values[i].array);
442                         break;
443                 }
444         }
445
446         return ret;
447 }