Add README for the adventurous, allow evdev override from getenv().
[profile/ivi/wayland.git] / connection.c
1 #include <stdlib.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <sys/uio.h>
7
8 #include "connection.h"
9
10 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
11
12 struct wl_buffer {
13         char data[4096];
14         int head, tail;
15 };
16
17 struct wl_connection {
18         struct wl_buffer in, out;
19         int fd;
20         void *data;
21         wl_connection_update_func_t update;
22 };
23
24 struct wl_connection *
25 wl_connection_create(int fd,
26                      wl_connection_update_func_t update,
27                      void *data)
28 {
29         struct wl_connection *connection;
30
31         connection = malloc(sizeof *connection);
32         memset(connection, 0, sizeof *connection);
33         connection->fd = fd;
34         connection->update = update;
35         connection->data = data;
36
37         connection->update(connection,
38                            WL_CONNECTION_READABLE,
39                            connection->data);
40
41         return connection;
42 }
43
44 void
45 wl_connection_destroy(struct wl_connection *connection)
46 {
47         free(connection);
48 }
49
50 void
51 wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
52 {
53         struct wl_buffer *b;
54         int tail, rest;
55
56         b = &connection->in;
57         tail = b->tail;
58         if (tail + size <= ARRAY_LENGTH(b->data)) {
59                 memcpy(data, b->data + tail, size);
60         } else { 
61                 rest = ARRAY_LENGTH(b->data) - tail;
62                 memcpy(data, b->data + tail, rest);
63                 memcpy(data + rest, b->data, size - rest);
64         }
65 }
66
67 void
68 wl_connection_consume(struct wl_connection *connection, size_t size)
69 {
70         struct wl_buffer *b;
71         int tail, rest;
72
73         b = &connection->in;
74         tail = b->tail;
75         if (tail + size <= ARRAY_LENGTH(b->data)) {
76                 b->tail += size;
77         } else { 
78                 rest = ARRAY_LENGTH(b->data) - tail;
79                 b->tail = size - rest;
80         }
81 }
82
83 int wl_connection_data(struct wl_connection *connection, uint32_t mask)
84 {
85         struct wl_buffer *b;
86         struct iovec iov[2];
87         int len, head, tail, count, size, available;
88
89         if (mask & WL_CONNECTION_READABLE) {
90                 b = &connection->in;
91                 head = connection->in.head;
92                 if (head < b->tail) {
93                         iov[0].iov_base = b->data + head;
94                         iov[0].iov_len = b->tail - head;
95                         count = 1;
96                 } else {
97                         size = ARRAY_LENGTH(b->data) - head;
98                         iov[0].iov_base = b->data + head;
99                         iov[0].iov_len = size;
100                         iov[1].iov_base = b->data;
101                         iov[1].iov_len = b->tail;
102                         count = 2;
103                 }
104                 len = readv(connection->fd, iov, count);
105                 if (len < 0) {
106                         fprintf(stderr,
107                                 "read error from connection %p: %m (%d)\n",
108                                 connection, errno);
109                         return -1;
110                 } else if (len == 0) {
111                         /* FIXME: Handle this better? */
112                         return -1;
113                 } else if (head + len <= ARRAY_LENGTH(b->data)) {
114                         b->head += len;
115                 } else {
116                         b->head = head + len - ARRAY_LENGTH(b->data);
117                 }
118
119                 /* We know we have data in the buffer at this point,
120                  * so if head equals tail, it means the buffer is
121                  * full. */
122
123                 available = b->head - b->tail;
124                 if (available == 0)
125                         available = sizeof b->data;
126                 else if (available < 0)
127                         available += ARRAY_LENGTH(b->data);
128         } else {
129                 available = 0;
130         }       
131
132         if (mask & WL_CONNECTION_WRITABLE) {
133                 b = &connection->out;
134                 tail = b->tail;
135                 if (tail < b->head) {
136                         iov[0].iov_base = b->data + tail;
137                         iov[0].iov_len = b->head - tail;
138                         count = 1;
139                 } else {
140                         size = ARRAY_LENGTH(b->data) - tail;
141                         iov[0].iov_base = b->data + tail;
142                         iov[0].iov_len = size;
143                         iov[1].iov_base = b->data;
144                         iov[1].iov_len = b->head;
145                         count = 2;
146                 }
147                 len = writev(connection->fd, iov, count);
148                 if (len < 0) {
149                         fprintf(stderr, "write error for connection %p: %m\n", connection);
150                         return -1;
151                 } else if (tail + len <= ARRAY_LENGTH(b->data)) {
152                         b->tail += len;
153                 } else {
154                         b->tail = tail + len - ARRAY_LENGTH(b->data);
155                 }
156
157                 /* We just took data out of the buffer, so at this
158                  * point if head equals tail, the buffer is empty. */
159
160                 if (b->tail == b->head)
161                         connection->update(connection,
162                                            WL_CONNECTION_READABLE,
163                                            connection->data);
164         }
165
166         return available;
167 }
168
169 void
170 wl_connection_write(struct wl_connection *connection, const void *data, size_t count)
171 {
172         struct wl_buffer *b;
173         size_t size;
174         int head;
175
176         b = &connection->out;
177         head = b->head;
178         if (head + count <= ARRAY_LENGTH(b->data)) {
179                 memcpy(b->data + head, data, count);
180                 b->head += count;
181         } else {
182                 size = ARRAY_LENGTH(b->data) - head;
183                 memcpy(b->data + head, data, size);
184                 memcpy(b->data, data + size, count - size);
185                 b->head = count - size;
186         }
187
188         if (b->tail == head)
189                 connection->update(connection,
190                                    WL_CONNECTION_READABLE |
191                                    WL_CONNECTION_WRITABLE,
192                                    connection->data);
193 }