Update TODO list
[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
32 #include "wayland-util.h"
33 #include "connection.h"
34
35 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
36
37 struct wl_buffer {
38         char data[4096];
39         int head, tail;
40 };
41
42 struct wl_connection {
43         struct wl_buffer in, out;
44         int fd;
45         void *data;
46         wl_connection_update_func_t update;
47 };
48
49 struct wl_connection *
50 wl_connection_create(int fd,
51                      wl_connection_update_func_t update,
52                      void *data)
53 {
54         struct wl_connection *connection;
55
56         connection = malloc(sizeof *connection);
57         memset(connection, 0, sizeof *connection);
58         connection->fd = fd;
59         connection->update = update;
60         connection->data = data;
61
62         connection->update(connection,
63                            WL_CONNECTION_READABLE,
64                            connection->data);
65
66         return connection;
67 }
68
69 void
70 wl_connection_destroy(struct wl_connection *connection)
71 {
72         free(connection);
73 }
74
75 void
76 wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
77 {
78         struct wl_buffer *b;
79         int tail, rest;
80
81         b = &connection->in;
82         tail = b->tail;
83         if (tail + size <= ARRAY_LENGTH(b->data)) {
84                 memcpy(data, b->data + tail, size);
85         } else { 
86                 rest = ARRAY_LENGTH(b->data) - tail;
87                 memcpy(data, b->data + tail, rest);
88                 memcpy(data + rest, b->data, size - rest);
89         }
90 }
91
92 void
93 wl_connection_consume(struct wl_connection *connection, size_t size)
94 {
95         struct wl_buffer *b;
96         int tail, rest;
97
98         b = &connection->in;
99         tail = b->tail;
100         if (tail + size <= ARRAY_LENGTH(b->data)) {
101                 b->tail += size;
102         } else { 
103                 rest = ARRAY_LENGTH(b->data) - tail;
104                 b->tail = size - rest;
105         }
106 }
107
108 int wl_connection_data(struct wl_connection *connection, uint32_t mask)
109 {
110         struct wl_buffer *b;
111         struct iovec iov[2];
112         int len, head, tail, count, size, available;
113
114         if (mask & WL_CONNECTION_READABLE) {
115                 b = &connection->in;
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;
120                         count = 1;
121                 } else {
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;
127                         count = 2;
128                 }
129                 do {
130                         len = readv(connection->fd, iov, count);
131                 } while (len < 0 && errno == EINTR);
132                 if (len < 0) {
133                         fprintf(stderr,
134                                 "read error from connection %p: %m (%d)\n",
135                                 connection, errno);
136                         return -1;
137                 } else if (len == 0) {
138                         /* FIXME: Handle this better? */
139                         return -1;
140                 } else if (head + len <= ARRAY_LENGTH(b->data)) {
141                         b->head += len;
142                 } else {
143                         b->head = head + len - ARRAY_LENGTH(b->data);
144                 }
145
146                 /* We know we have data in the buffer at this point,
147                  * so if head equals tail, it means the buffer is
148                  * full. */
149
150                 available = b->head - b->tail;
151                 if (available == 0)
152                         available = sizeof b->data;
153                 else if (available < 0)
154                         available += ARRAY_LENGTH(b->data);
155         } else {
156                 available = 0;
157         }       
158
159         if (mask & WL_CONNECTION_WRITABLE) {
160                 b = &connection->out;
161                 tail = b->tail;
162                 if (tail < b->head) {
163                         iov[0].iov_base = b->data + tail;
164                         iov[0].iov_len = b->head - tail;
165                         count = 1;
166                 } else {
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;
172                         count = 2;
173                 }
174                 do {
175                         len = writev(connection->fd, iov, count);
176                 } while (len < 0 && errno == EINTR);
177                 if (len < 0) {
178                         fprintf(stderr, "write error for connection %p: %m\n", connection);
179                         return -1;
180                 } else if (tail + len <= ARRAY_LENGTH(b->data)) {
181                         b->tail += len;
182                 } else {
183                         b->tail = tail + len - ARRAY_LENGTH(b->data);
184                 }
185
186                 /* We just took data out of the buffer, so at this
187                  * point if head equals tail, the buffer is empty. */
188
189                 if (b->tail == b->head)
190                         connection->update(connection,
191                                            WL_CONNECTION_READABLE,
192                                            connection->data);
193         }
194
195         return available;
196 }
197
198 void
199 wl_connection_write(struct wl_connection *connection, const void *data, size_t count)
200 {
201         struct wl_buffer *b;
202         size_t size;
203         int head;
204
205         b = &connection->out;
206         head = b->head;
207         if (head + count <= ARRAY_LENGTH(b->data)) {
208                 memcpy(b->data + head, data, count);
209                 b->head += count;
210         } else {
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;
215         }
216
217         if (b->tail == head)
218                 connection->update(connection,
219                                    WL_CONNECTION_READABLE |
220                                    WL_CONNECTION_WRITABLE,
221                                    connection->data);
222 }
223
224 void
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)
229 {
230         struct wl_object *object;
231         uint32_t args[32], length, *p, size;
232         struct wl_array *array;
233         const char *s;
234         int i, count;
235
236         count = strlen(message->signature);
237         assert(count <= ARRAY_LENGTH(args));
238
239         p = &args[2];
240         for (i = 0; i < count; i++) {
241                 switch (message->signature[i]) {
242                 case 'u':
243                 case 'i':
244                         *p++ = va_arg(ap, uint32_t);
245                         break;
246                 case 's':
247                         s = va_arg(ap, const char *);
248                         length = strlen(s);
249                         *p++ = length;
250                         memcpy(p, s, length);
251                         p += DIV_ROUNDUP(length, sizeof(*p));
252                         break;
253                 case 'o':
254                 case 'n':
255                         object = va_arg(ap, struct wl_object *);
256                         *p++ = object ? object->id : 0;
257                         break;
258                 case 'a':
259                         array = va_arg(ap, struct wl_array *);
260                         if (array == NULL || array->size == 0) {
261                                 *p++ = 0;
262                                 break;
263                         }
264                         *p++ = array->size;
265                         memcpy(p, array->data, array->size);
266                         p = (void *) p + array->size;
267                         break;
268                 default:
269                         assert(0);
270                         break;
271                 }
272         }
273
274         size = (p - args) * sizeof *p;
275         args[0] = sender->id;
276         args[1] = opcode | (size << 16);
277         wl_connection_write(connection, args, size);
278 }
279
280 void
281 wl_connection_demarshal(struct wl_connection *connection,
282                         uint32_t size,
283                         struct wl_hash_table *objects,
284                         void (*func)(void),
285                         void *data, struct wl_object *target,
286                         const struct wl_message *message)
287 {
288         ffi_type *types[20];
289         ffi_cif cif;
290         uint32_t *p, result, length;
291         int i, count;
292         union {
293                 uint32_t uint32;
294                 char *string;
295                 void *object;
296                 uint32_t new_id;
297                 struct wl_array *array;
298         } values[20];
299         void *args[20];
300         struct wl_object *object;
301         uint32_t buffer[64];
302
303         count = strlen(message->signature) + 2;
304         if (count > ARRAY_LENGTH(types)) {
305                 printf("too many args (%d)\n", count);
306                 return;
307         }
308
309         if (sizeof buffer < size) {
310                 printf("request too big, should malloc tmp buffer here\n");
311                 return;
312         }
313
314         types[0] = &ffi_type_pointer;
315         values[0].object = data;
316         args[0] =  &values[0];
317
318         types[1] = &ffi_type_pointer;
319         values[1].object = target;
320         args[1] =  &values[1];
321
322         wl_connection_copy(connection, buffer, size);
323         p = &buffer[2];
324         for (i = 2; i < count; i++) {
325                 switch (message->signature[i - 2]) {
326                 case 'u':
327                 case 'i':
328                         types[i] = &ffi_type_uint32;
329                         values[i].uint32 = *p++;
330                         break;
331                 case 's':
332                         types[i] = &ffi_type_pointer;
333                         length = *p++;
334                         values[i].string = malloc(length + 1);
335                         if (values[i].string == NULL) {
336                                 /* FIXME: Send NO_MEMORY */
337                                 return;
338                         }
339                         memcpy(values[i].string, p, length);
340                         values[i].string[length] = '\0';
341                         p += DIV_ROUNDUP(length, sizeof *p);
342                         break;
343                 case 'o':
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)\n", *p);
348                         values[i].object = object;
349                         p++;
350                         break;
351                 case 'n':
352                         types[i] = &ffi_type_uint32;
353                         values[i].new_id = *p;
354                         object = wl_hash_table_lookup(objects, *p);
355                         if (object != NULL)
356                                 printf("object already exists (%d)\n", *p);
357                         p++;
358                         break;
359                 case 'a':
360                         types[i] = &ffi_type_pointer;
361                         length = *p++;
362                         values[i].array = malloc(length + sizeof *values[i].array);
363                         if (values[i].array == NULL) {
364                                 /* FIXME: Send NO_MEMORY */
365                                 return;
366                         }
367                         values[i].array->size = length;
368                         values[i].array->alloc = 0;
369                         values[i].array->data = values[i].array + 1;
370                         memcpy(values[i].array->data, p, length);
371                         p += DIV_ROUNDUP(length, sizeof *p);
372                         break;
373                 default:
374                         printf("unknown type\n");
375                         break;
376                 }
377                 args[i] = &values[i];
378         }
379
380         ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
381         ffi_call(&cif, func, &result, args);
382
383         for (i = 2; i < count; i++) {
384                 switch (message->signature[i - 2]) {
385                 case 's':
386                         free(values[i].string);
387                         break;
388                 case 'a':
389                         free(values[i].array);
390                         break;
391                 }
392         }
393 }