aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/cserve/evas_cs_server.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/evas/src/lib/cserve/evas_cs_server.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/cserve/evas_cs_server.c b/libraries/evas/src/lib/cserve/evas_cs_server.c
new file mode 100644
index 0000000..3b5d8b9
--- /dev/null
+++ b/libraries/evas/src/lib/cserve/evas_cs_server.c
@@ -0,0 +1,380 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include "evas_cs.h"
6
7#ifdef EVAS_CSERVE
8
9EAPI Server *
10evas_cserve_server_add(void)
11{
12 Server *s;
13 char buf[PATH_MAX];
14 struct sockaddr_un socket_unix;
15 struct linger lin;
16 mode_t pmode;
17 int socket_unix_len;
18
19 s = calloc(1, sizeof(Server));
20 if (!s) return NULL;
21 s->ch[0].fd = -1;
22 snprintf(buf, sizeof(buf), "/tmp/.evas-cserve-%x", getuid());
23 s->socket_path = strdup(buf);
24 if (!s->socket_path)
25 {
26 free(s);
27 return NULL;
28 }
29 pmode = umask(~(S_IRUSR | S_IWUSR));
30 start:
31 s->ch[0].fd = socket(AF_UNIX, SOCK_STREAM, 0);
32 if (s->ch[0].fd < 0) goto error;
33 if (fcntl(s->ch[0].fd, F_SETFL, O_NONBLOCK) < 0) goto error;
34 if (fcntl(s->ch[0].fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
35 lin.l_onoff = 1;
36 lin.l_linger = 0;
37 if (setsockopt(s->ch[0].fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)
38 goto error;
39 socket_unix.sun_family = AF_UNIX;
40 strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
41 socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
42 if (bind(s->ch[0].fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
43 {
44 if ((connect(s->ch[0].fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) &&
45 (unlink(s->socket_path) >= 0))
46 {
47 close(s->ch[0].fd);
48 goto start;
49 }
50 else
51 goto error;
52 }
53 if (listen(s->ch[0].fd, 4096) < 0) goto error;
54 umask(pmode);
55 return s;
56 error:
57 umask(pmode);
58 if (s->ch[0].fd >= 0) close(s->ch[0].fd);
59 free(s->socket_path);
60 free(s);
61 return NULL;
62}
63
64EAPI void
65evas_cserve_server_del(Server *s)
66{
67 Client *c;
68
69 EINA_LIST_FREE(s->clients, c)
70 {
71 LKL(c->lock);
72 close(c->fd);
73 if (c->buf) free(c->buf);
74 if (c->inbuf) free(c->inbuf);
75 LKD(c->lock);
76 free(c);
77 }
78 close(s->ch[0].fd);
79 unlink(s->socket_path);
80 free(s->socket_path);
81 free(s);
82}
83
84static void
85server_accept(Server *s)
86{
87 Client *c;
88 int new_fd;
89 struct sockaddr_in incoming;
90 size_t size_in;
91
92 size_in = sizeof(struct sockaddr_in);
93 new_fd = accept(s->ch[0].fd, (struct sockaddr *)&incoming, (socklen_t *)&size_in);
94 if (new_fd < 0) return;
95 fcntl(new_fd, F_SETFL, O_NONBLOCK);
96 fcntl(new_fd, F_SETFD, FD_CLOEXEC);
97 c = calloc(1, sizeof(Client));
98 if (!c)
99 {
100 close(new_fd);
101 return;
102 }
103 c->server = s;
104 c->fd = new_fd;
105 LKI(c->lock);
106 s->clients = eina_list_append(s->clients, c);
107}
108
109static void
110client_flush(Client *c)
111{
112 int num;
113
114 num = write(c->fd, c->buf, c->bufsize);
115 if (num < 0)
116 {
117 c->dead = 1;
118 return;
119 }
120 if (num < c->bufsize)
121 {
122 unsigned char *buf;
123
124 buf = malloc(c->bufsize - num);
125 if (buf)
126 {
127 memcpy(buf, c->buf + num, c->bufsize - num);
128 free(c->buf);
129 c->bufsize = c->bufsize - num;
130 c->bufalloc = c->bufsize;
131 c->buf = buf;
132 }
133 }
134 else
135 {
136 free(c->buf);
137 c->buf = NULL;
138 c->bufsize = 0;
139 c->bufalloc = 0;
140 }
141}
142
143static void
144client_buf_add(Client *c, unsigned char *data, int size)
145{
146 int newsize;
147 unsigned char *buf;
148
149 newsize = c->bufsize + size;
150 if (newsize > c->bufalloc)
151 {
152 c->bufalloc = newsize + 16384;
153 buf = realloc(c->buf, c->bufalloc);
154 if (buf) c->buf = buf;
155 else return;
156 }
157 memcpy(c->buf + c->bufsize, data, size);
158 c->bufsize += size;
159}
160
161static void
162client_write(Client *c, unsigned char *data, int size)
163{
164 int num;
165
166 if (!c->buf)
167 {
168 num = write(c->fd, data, size);
169 if (num != size)
170 client_buf_add(c, data + num, size - num);
171 }
172 else
173 {
174 client_buf_add(c, data, size);
175 }
176}
177
178EAPI void
179evas_cserve_client_send(Client *c, int opcode, int size, unsigned char *data)
180{
181 unsigned char *data2;
182 int *ints;
183
184 data2 = malloc(size + (sizeof(int) * 3));
185 if (!data2) return;
186 ints = (int *)data2;
187 ints[0] = size;
188 ints[1] = opcode;
189// LKL(c->lock);
190 c->req_to++;
191 ints[2] = c->req_to;
192 memcpy(data2 + (sizeof(int) * 3), data, size);
193 client_write(c, data2, size + (sizeof(int) * 3));
194// LKU(c->lock);
195 free(data2);
196}
197
198static void
199server_message_handle(Server *s, Client *c, int opcode, int size, unsigned char *data)
200{
201 if (s->func) s->func(s->data, s, c, opcode, size, data);
202}
203
204EAPI void
205evas_cserve_server_message_handler_set(Server *s, int (*func) (void *fdata, Server *s, Client *c, int opcode, int size, unsigned char *data), void *data)
206{
207 s->func = func;
208 s->data = data;
209}
210
211static int
212server_parse(Server *s, Client *c)
213{
214 int *ints;
215 unsigned char *data, *newbuf;
216
217 if (c->inbufsize < (int)sizeof(int)) return 0;
218 ints = (int *)((c->inbuf));
219 if ((ints[0] < 0) || (ints[0] > (1024 * 1024)))
220 return 0;
221 if (c->inbufsize < (ints[0] + ((int)sizeof(int) * 3)))
222 {
223 return 0;
224 }
225 data = c->inbuf + (sizeof(int) * 3);
226 if (ints[2] != (c->req_from + 1))
227 {
228 ERR("EEK! sequence number mismatch from client with pid: %i."
229 "---- num %i is not 1 more than %i"
230 ,
231 c->pid, ints[2], c->req_from);
232 return 0;
233 }
234 c->req_from++;
235 server_message_handle(s, c, ints[1], ints[0], data);
236 c->inbufalloc -= ints[0] + (sizeof(int) * 3);
237 if (c->inbufalloc == 0)
238 {
239 free(c->inbuf);
240 c->inbuf = NULL;
241 c->inbufsize = 0;
242 return 0;
243 }
244 newbuf = malloc(c->inbufalloc);
245 if (!newbuf)
246 {
247 c->inbufalloc += ints[0] + (sizeof(int) * 3);
248 /* fixme - bad situation */
249 return 0;
250 }
251 memcpy(newbuf, c->inbuf + ints[0] + (sizeof(int) * 3), c->inbufalloc);
252 c->inbufsize -= ints[0] + (sizeof(int) * 3);
253 free(c->inbuf);
254 c->inbuf = newbuf;
255 return 1;
256}
257
258static void
259server_data(Server *s, Client *c, unsigned char *data, int size)
260{
261 if (!c->inbuf)
262 {
263 c->inbuf = malloc(size);
264 if (c->inbuf)
265 {
266 memcpy(c->inbuf, data, size);
267 c->inbufalloc = size;
268 c->inbufsize = size;
269 }
270 else
271 {
272 /* fixme - bad situation */
273 return;
274 }
275 }
276 else
277 {
278 int size2;
279
280 size2 = c->inbufsize + size;
281 if (size2 > c->inbufalloc)
282 {
283 unsigned char *newbuf;
284
285 c->inbufalloc = size2;
286 newbuf = realloc(c->inbuf, c->inbufalloc);
287 if (newbuf) c->inbuf = newbuf;
288 else size2 = 0;
289 }
290 if (size2 > 0)
291 {
292 memcpy(c->inbuf + c->inbufsize, data, size);
293 c->inbufsize = size2;
294 }
295 else
296 {
297 /* fixme - bad situation */
298 return;
299 }
300 }
301 while (server_parse(s, c));
302}
303
304EAPI void
305evas_cserve_server_wait(Server *s, int timeout)
306{
307 fd_set rset, wset, xset;
308 int maxfd;
309 int ret;
310 struct timeval to;
311 Eina_List *l, *dead = NULL;
312 Client *c;
313
314 maxfd = 0;
315 FD_ZERO(&rset);
316 FD_ZERO(&wset);
317 FD_ZERO(&xset);
318 FD_SET(s->ch[0].fd, &rset);
319 if (s->ch[0].fd > maxfd) maxfd = s->ch[0].fd;
320 EINA_LIST_FOREACH(s->clients, l, c)
321 {
322 FD_SET(c->fd, &rset);
323 if (c->buf)
324 FD_SET(c->fd, &wset);
325 if (c->fd > maxfd) maxfd = c->fd;
326 }
327 if (timeout > 0)
328 {
329 to.tv_sec = timeout / 1000000;
330 to.tv_usec = timeout % 1000000;
331 ret = select(maxfd + 1, &rset, &wset, &xset, &to);
332 }
333 else
334 ret = select(maxfd + 1, &rset, &wset, &xset, NULL);
335 if (ret < 1) return;
336
337 EINA_LIST_FOREACH(s->clients, l, c)
338 {
339 if (c->dead) continue;
340 if (FD_ISSET(c->fd, &rset))
341 {
342 unsigned char buf[16384];
343 int num;
344
345 errno = 0;
346 num = read(c->fd, buf, sizeof(buf));
347 if (num <= 0)
348 {
349 c->dead = 1;
350 dead = eina_list_append(dead, c);
351 }
352 else if (num > 0)
353 {
354 server_data(s, c, buf, num);
355 }
356 }
357 else if (FD_ISSET(c->fd, &wset))
358 {
359 client_flush(c);
360 if (c->dead) dead = eina_list_append(dead, c);
361 }
362 }
363 if (FD_ISSET(s->ch[0].fd, &rset))
364 {
365 server_accept(s);
366 }
367 EINA_LIST_FREE(dead, c)
368 {
369 LKL(c->lock);
370 if (c->func) c->func(c->data, c);
371 s->clients = eina_list_remove(s->clients, c);
372 close(c->fd);
373 if (c->buf) free(c->buf);
374 if (c->inbuf) free(c->inbuf);
375 LKD(c->lock);
376 free(c);
377 }
378}
379
380#endif