Drop libdrm CFLAGS where no longer necessary.
[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         const char *s;
233         int i, count;
234
235         count = strlen(message->signature);
236         assert(count <= ARRAY_LENGTH(args));
237
238         p = &args[2];
239         for (i = 0; i < count; i++) {
240                 switch (message->signature[i]) {
241                 case 'u':
242                 case 'i':
243                         *p++ = va_arg(ap, uint32_t);
244                         break;
245                 case 's':
246                         s = va_arg(ap, const char *);
247                         length = strlen(s);
248                         *p++ = length;
249                         memcpy(p, s, length);
250                         p += DIV_ROUNDUP(length, sizeof(*p));
251                         break;
252                 case 'o':
253                 case 'n':
254                         object = va_arg(ap, struct wl_object *);
255                         *p++ = object->id;
256                         break;
257                 default:
258                         assert(0);
259                         break;
260                 }
261         }
262
263         size = (p - args) * sizeof *p;
264         args[0] = sender->id;
265         args[1] = opcode | (size << 16);
266         wl_connection_write(connection, args, size);
267 }
268
269 void
270 wl_connection_demarshal(struct wl_connection *connection,
271                         uint32_t size,
272                         struct wl_hash *objects,
273                         void (*func)(void),
274                         void *data, struct wl_object *target,
275                         const struct wl_message *message)
276 {
277         ffi_type *types[20];
278         ffi_cif cif;
279         uint32_t *p, result, length;
280         int i, count;
281         union {
282                 uint32_t uint32;
283                 char *string;
284                 void *object;
285                 uint32_t new_id;
286         } values[20];
287         void *args[20];
288         struct wl_object *object;
289         uint32_t buffer[64];
290
291         count = strlen(message->signature) + 2;
292         if (count > ARRAY_LENGTH(types)) {
293                 printf("too many args (%d)\n", count);
294                 return;
295         }
296
297         if (sizeof buffer < size) {
298                 printf("request too big, should malloc tmp buffer here\n");
299                 return;
300         }
301
302         types[0] = &ffi_type_pointer;
303         values[0].object = data;
304         args[0] =  &values[0];
305
306         types[1] = &ffi_type_pointer;
307         values[1].object = target;
308         args[1] =  &values[1];
309
310         wl_connection_copy(connection, buffer, size);
311         p = &buffer[2];
312         for (i = 2; i < count; i++) {
313                 switch (message->signature[i - 2]) {
314                 case 'u':
315                 case 'i':
316                         types[i] = &ffi_type_uint32;
317                         values[i].uint32 = *p++;
318                         break;
319                 case 's':
320                         types[i] = &ffi_type_pointer;
321                         length = *p++;
322                         values[i].string = malloc(length + 1);
323                         if (values[i].string == NULL) {
324                                 /* FIXME: Send NO_MEMORY */
325                                 return;
326                         }
327                         memcpy(values[i].string, p, length);
328                         values[i].string[length] = '\0';
329                         p += DIV_ROUNDUP(length, sizeof *p);
330                         break;
331                 case 'o':
332                         types[i] = &ffi_type_pointer;
333                         object = wl_hash_lookup(objects, *p);
334                         if (object == NULL)
335                                 printf("unknown object (%d)\n", *p);
336                         values[i].object = object;
337                         p++;
338                         break;
339                 case 'n':
340                         types[i] = &ffi_type_uint32;
341                         values[i].new_id = *p;
342                         object = wl_hash_lookup(objects, *p);
343                         if (object != NULL)
344                                 printf("object already exists (%d)\n", *p);
345                         p++;
346                         break;
347                 default:
348                         printf("unknown type\n");
349                         break;
350                 }
351                 args[i] = &values[i];
352         }
353
354         ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
355         ffi_call(&cif, func, &result, args);
356
357         for (i = 2; i < count; i++) {
358                 switch (message->signature[i - 2]) {
359                 case 's':
360                         free(values[i].string);
361                         break;
362                 }
363         }
364 }