let's make server work out of the box if u set:
[profile/ivi/evas.git] / src / lib / cserve2 / evas_cs2_client.c
1 #include "config.h"
2
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <sys/un.h>
6
7 #include <sys/mman.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10
11 #include <Eina.h>
12
13 #include "evas_cs2.h"
14 #include "evas_cs2_private.h"
15
16 #ifdef EVAS_CSERVE2
17
18 typedef void (*Op_Callback)(void *data, const void *msg);
19
20 struct _File_Entry {
21    unsigned int file_id;
22 };
23
24 struct _Client_Request {
25    Message_Type type;
26    unsigned int rid;
27    Op_Callback cb;
28    void *data;
29 };
30
31 typedef struct _File_Entry File_Entry;
32 typedef struct _Client_Request Client_Request;
33
34 static int cserve2_init = 0;
35 static int socketfd = -1;
36
37 static unsigned int _rid_count = 0;
38 static unsigned int _file_id = 0;
39 static unsigned int _data_id = 0;
40
41 static Eina_List *_requests = NULL;
42
43 static struct sockaddr_un socksize;
44 #ifndef UNIX_PATH_MAX
45 #define UNIX_PATH_MAX sizeof(socksize.sun_path)
46 #endif
47
48 static void
49 _socket_path_set(char *path)
50 {
51    char *env;
52    char buf[UNIX_PATH_MAX];
53
54    env = getenv("EVAS_CSERVE2_SOCKET");
55    if (env && env[0])
56      {
57         strncpy(path, env, UNIX_PATH_MAX - 1);
58         return;
59      }
60
61    snprintf(buf, sizeof(buf), "/tmp/.evas-cserve2-%x.socket", (int)getuid());
62    /* FIXME: check we can actually create this socket */
63    strcpy(path, buf);
64 #if 0   
65    env = getenv("XDG_RUNTIME_DIR");
66    if (!env || !env[0])
67      {
68         env = getenv("HOME");
69         if (!env || !env[0])
70           {
71              env = getenv("TMPDIR");
72              if (!env || !env[0])
73                env = "/tmp";
74           }
75      }
76
77    snprintf(buf, sizeof(buf), "%s/evas-cserve2-%x.socket", env, getuid());
78    /* FIXME: check we can actually create this socket */
79    strcpy(path, buf);
80 #endif   
81 }
82
83 static Eina_Bool
84 _server_connect(void)
85 {
86    int s, len;
87    struct sockaddr_un remote;
88
89    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
90      {
91         ERR("socket");
92         return EINA_FALSE;
93      }
94
95    remote.sun_family = AF_UNIX;
96    _socket_path_set(remote.sun_path);
97    len = strlen(remote.sun_path) + sizeof(remote.sun_family);
98    if (connect(s, (struct sockaddr *)&remote, len) == -1)
99      {
100         ERR("connect");
101         return EINA_FALSE;
102      }
103
104    fcntl(s, F_SETFL, O_NONBLOCK);
105
106    socketfd = s;
107
108    DBG("connected to cserve2 server.");
109    return EINA_TRUE;
110 }
111
112 static void
113 _server_disconnect(void)
114 {
115    close(socketfd);
116    socketfd = -1;
117 }
118
119 static void
120 _request_answer_add(Message_Type type, unsigned int rid, Op_Callback cb, void *data)
121 {
122    Client_Request *cr = calloc(1, sizeof(*cr));
123
124    cr->type = type;
125    cr->rid = rid;
126    cr->cb = cb;
127    cr->data = data;
128
129    _requests = eina_list_append(_requests, cr);
130 }
131
132 static Eina_Bool
133 _server_send(const void *buf, int size, Op_Callback cb, void *data)
134 {
135    const Msg_Base *msg;
136    if (send(socketfd, &size, sizeof(size), MSG_NOSIGNAL) == -1)
137      {
138         ERR("Couldn't send message size to server.");
139         return EINA_FALSE;
140      }
141    if (send(socketfd, buf, size, MSG_NOSIGNAL) == -1)
142      {
143         ERR("Couldn't send message body to server.");
144         return EINA_FALSE;
145      }
146
147    msg = buf;
148    switch (msg->type)
149      {
150       case CSERVE2_OPEN:
151       case CSERVE2_SETOPTS:
152       case CSERVE2_LOAD:
153       case CSERVE2_PRELOAD:
154          _request_answer_add(msg->type, msg->rid, cb, data);
155          break;
156       default:
157          break;
158      }
159
160    return EINA_TRUE;
161 }
162
163 static int sr_size = 0;
164 static int sr_got = 0;
165 static char *sr_buf = NULL;
166
167 static void *
168 _server_read(int *size)
169 {
170    int n;
171    void *ret;
172
173    if (sr_size)
174      goto get_data;
175
176    n = recv(socketfd, &sr_size, sizeof(sr_size), 0);
177    if (n < 0)
178      return NULL;
179
180    sr_buf = malloc(sr_size);
181
182 get_data:
183    n = recv(socketfd, sr_buf + sr_got, sr_size - sr_got, 0);
184    if (n < 0)
185      return NULL;
186
187    sr_got += n;
188    if (sr_got < sr_size)
189      return NULL;
190
191    *size = sr_size;
192    sr_size = 0;
193    sr_got = 0;
194    ret = sr_buf;
195    sr_buf = NULL;
196
197    return ret;
198 }
199
200 int
201 evas_cserve2_init(void)
202 {
203    if (cserve2_init++)
204      return cserve2_init;
205
206    DBG("Connecting to cserve2.");
207    if (!_server_connect())
208      {
209         cserve2_init = 0;
210         return 0;
211      }
212
213    return cserve2_init;
214 }
215
216 int
217 evas_cserve2_shutdown(void)
218 {
219    if ((--cserve2_init) > 0)
220      return cserve2_init;
221
222    DBG("Disconnecting from cserve2.");
223    _server_disconnect();
224
225    return cserve2_init;
226 }
227
228 int
229 evas_cserve2_use_get(void)
230 {
231    return cserve2_init;
232 }
233
234 static unsigned int
235 _next_rid(void)
236 {
237    if (!_rid_count)
238      _rid_count++;
239
240    return _rid_count++;
241 }
242
243 static unsigned int
244 _server_dispatch(void)
245 {
246    int size;
247    unsigned int rid;
248    Eina_List *l, *l_next;
249    Client_Request *cr;
250    Msg_Base *msg;
251
252    msg = _server_read(&size);
253    if (!msg)
254      return 0;
255
256    EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr)
257      {
258         if (cr->rid != msg->rid) // dispatch this answer
259           continue;
260
261         _requests = eina_list_remove_list(_requests, l);
262         if (cr->cb)
263           cr->cb(cr->data, msg);
264         free(cr);
265      }
266
267    rid = msg->rid;
268    free(msg);
269
270    return rid;
271 }
272
273 static void
274 _server_dispatch_until(unsigned int rid)
275 {
276    Eina_Bool done = EINA_FALSE;
277
278    while (!done)
279      {
280         if (_server_dispatch() == rid)
281           done = EINA_TRUE;
282      }
283 }
284
285 static void
286 _image_opened_cb(void *data, const void *msg_received)
287 {
288    const Msg_Base *answer = msg_received;
289    const Msg_Opened *msg = msg_received;
290    Image_Entry *ie = data;
291
292    ie->open_rid = 0;
293
294    if (answer->type == CSERVE2_ERROR)
295      {
296         const Msg_Error *msg_error = msg_received;
297         ERR("Couldn't open image: '%s':'%s'; error: %d",
298             ie->file, ie->key, msg_error->error);
299         free(ie->data1);
300         ie->data1 = NULL;
301         return;
302      }
303
304    ie->w = msg->image.w;
305    ie->h = msg->image.h;
306    ie->flags.alpha = msg->image.alpha;
307    ie->loop_hint = msg->image.loop_hint;
308    ie->loop_count = msg->image.loop_count;
309    ie->frame_count = msg->image.frame_count;
310 }
311
312 static void
313 _image_loaded_cb(void *data, const void *msg_received)
314 {
315    const Msg_Base *answer = msg_received;
316    const Msg_Loaded *msg = msg_received;
317    Image_Entry *ie = data;
318    Data_Entry *dentry = ie->data2;
319    const char *shmpath;
320
321    ie->load_rid = 0;
322
323    if (!ie->data2)
324      return;
325
326    if (answer->type == CSERVE2_ERROR)
327      {
328         const Msg_Error *msg_error = msg_received;
329         ERR("Couldn't load image: '%s':'%s'; error: %d",
330             ie->file, ie->key, msg_error->error);
331         free(ie->data2);
332         ie->data2 = NULL;
333         return;
334      }
335
336    shmpath = ((const char *)msg) + sizeof(*msg);
337
338    // dentry->shm.path = strdup(shmpath);
339    dentry->shm.mmap_offset = msg->shm.mmap_offset;
340    dentry->shm.use_offset = msg->shm.use_offset;
341    dentry->shm.mmap_size = msg->shm.mmap_size;
342    dentry->shm.image_size = msg->shm.image_size;
343
344    dentry->shm.f = eina_file_open(shmpath, EINA_TRUE);
345    if (!dentry->shm.f)
346      {
347         free(dentry);
348         ie->data2 = NULL;
349         return;
350      }
351
352    dentry->shm.data = eina_file_map_new(dentry->shm.f, EINA_FILE_WILLNEED,
353                                         dentry->shm.mmap_offset,
354                                         dentry->shm.mmap_size);
355
356    if (!dentry->shm.data)
357      {
358         eina_file_close(dentry->shm.f);
359         free(dentry);
360         ie->data2 = NULL;
361      }
362
363    if (ie->data2)
364      {
365         ie->flags.loaded = EINA_TRUE;
366         ie->flags.alpha_sparse = msg->alpha_sparse;
367      }
368 }
369
370 static void
371 _image_preloaded_cb(void *data, const void *msg_received)
372 {
373    const Msg_Base *answer = msg_received;
374    Image_Entry *ie = data;
375    Data_Entry *dentry = ie->data2;
376
377    DBG("Received PRELOADED for RID: %d", answer->rid);
378    ie->preload_rid = 0;
379
380    if (answer->type == CSERVE2_ERROR)
381      {
382         const Msg_Error *msg_error = msg_received;
383         ERR("Couldn't preload image: '%s':'%s'; error: %d",
384             ie->file, ie->key, msg_error->error);
385         dentry->preloaded_cb(data, EINA_FALSE);
386         dentry->preloaded_cb = NULL;
387         return;
388      }
389
390    if (dentry && (dentry->preloaded_cb))
391      {
392         dentry->preloaded_cb(data, EINA_TRUE);
393         dentry->preloaded_cb = NULL;
394      }
395 }
396
397 static const char *
398 _build_absolute_path(const char *path, char buf[], int size)
399 {
400    char *p;
401    int len;
402
403    if (!path)
404      return NULL;
405
406    p = buf;
407
408    if (path[0] == '/')
409      strncpy(p, path, size);
410    else if (path[0] == '~')
411      {
412         const char *home = getenv("HOME");
413         if (!home)
414           return NULL;
415         strncpy(p, home, size);
416         len = strlen(p);
417         size -= len + 1;
418         p += len;
419         p[0] = '/';
420         p++;
421         strncpy(p, path + 2, size);
422      }
423    else
424      {
425         if (!getcwd(p, size))
426           return NULL;
427         len = strlen(p);
428         size -= len + 1;
429         p += len;
430         p[0] = '/';
431         p++;
432         strncpy(p, path, size);
433      }
434
435    return buf;
436 }
437
438 static unsigned int
439 _image_open_server_send(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt __UNUSED__)
440 {
441    int flen, klen;
442    int size;
443    char *buf;
444    char filebuf[PATH_MAX];
445    Msg_Open msg_open;
446    File_Entry *fentry;
447
448    if (cserve2_init == 0)
449      {
450         ERR("Server not initialized.");
451         return 0;
452      }
453
454    if (!key) key = "";
455
456    _build_absolute_path(file, filebuf, sizeof(filebuf));
457
458    fentry = calloc(1, sizeof(*fentry));
459
460    memset(&msg_open, 0, sizeof(msg_open));
461
462    fentry->file_id = ++_file_id;
463    if (fentry->file_id == 0)
464      fentry->file_id = ++_file_id;
465
466    flen = strlen(filebuf) + 1;
467    klen = strlen(key) + 1;
468
469    msg_open.base.rid = _next_rid();
470    msg_open.base.type = CSERVE2_OPEN;
471    msg_open.file_id = fentry->file_id;
472    msg_open.path_offset = 0;
473    msg_open.key_offset = flen;
474
475    size = sizeof(msg_open) + flen + klen;
476    buf = malloc(size);
477    if (!buf) return EINA_FALSE;
478    memcpy(buf, &msg_open, sizeof(msg_open));
479    memcpy(buf + sizeof(msg_open), filebuf, flen);
480    memcpy(buf + sizeof(msg_open) + flen, key, klen);
481
482    if (!_server_send(buf, size, _image_opened_cb, ie))
483      {
484         ERR("Couldn't send message to server.");
485         free(buf);
486         return 0;
487      }
488
489    free(buf);
490    ie->data1 = fentry;
491
492    return msg_open.base.rid;
493 }
494
495 unsigned int
496 _image_setopts_server_send(Image_Entry *ie)
497 {
498    File_Entry *fentry;
499    Data_Entry *dentry;
500    Msg_Setopts msg;
501
502    if (cserve2_init == 0)
503      return 0;
504
505    fentry = ie->data1;
506
507    dentry = calloc(1, sizeof(*dentry));
508
509    memset(&msg, 0, sizeof(msg));
510    dentry->image_id = ++_data_id;
511    if (dentry->image_id == 0)
512      dentry->image_id = ++_data_id;
513
514    msg.base.rid = _next_rid();
515    msg.base.type = CSERVE2_SETOPTS;
516    msg.file_id = fentry->file_id;
517    msg.image_id = dentry->image_id;
518
519    if (!_server_send(&msg, sizeof(msg), 0, NULL))
520      return 0;
521
522    ie->data2 = dentry;
523
524    return msg.base.rid;
525 }
526
527 unsigned int
528 _image_load_server_send(Image_Entry *ie)
529 {
530    Data_Entry *dentry;
531    Msg_Load msg;
532
533    if (cserve2_init == 0)
534      return 0;
535
536    if (!ie->data1)
537      {
538         ERR("No data for opened file.");
539         return 0;
540      }
541
542    dentry = ie->data2;
543
544    memset(&msg, 0, sizeof(msg));
545
546    msg.base.rid = _next_rid();
547    msg.base.type = CSERVE2_LOAD;
548    msg.image_id = dentry->image_id;
549
550    if (!_server_send(&msg, sizeof(msg), _image_loaded_cb, ie))
551      return 0;
552
553    return msg.base.rid;
554 }
555
556 unsigned int
557 _image_preload_server_send(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
558 {
559    Data_Entry *dentry;
560    Msg_Preload msg;
561
562    if (cserve2_init == 0)
563      return 0;
564
565    dentry = ie->data2;
566    dentry->preloaded_cb = preloaded_cb;
567
568    memset(&msg, 0, sizeof(msg));
569
570    msg.base.rid = _next_rid();
571    msg.base.type = CSERVE2_PRELOAD;
572    msg.image_id = dentry->image_id;
573
574    if (!_server_send(&msg, sizeof(msg), _image_preloaded_cb, ie))
575      return 0;
576
577    return msg.base.rid;
578 }
579
580 unsigned int
581 _image_close_server_send(Image_Entry *ie)
582 {
583    Msg_Close msg;
584    File_Entry *fentry;
585
586    if (cserve2_init == 0)
587      return 0;
588
589    if (!ie->data1)
590      return 0;
591
592    fentry = ie->data1;
593
594    if (ie->data2)
595      {
596         Data_Entry *dentry = ie->data2;
597         if (dentry->shm.data)
598           eina_file_map_free(dentry->shm.f, dentry->shm.data);
599         if (dentry->shm.f)
600           eina_file_close(dentry->shm.f);
601         free(ie->data2);
602         ie->data2 = NULL;
603      }
604
605    memset(&msg, 0, sizeof(msg));
606    msg.base.rid = _next_rid();
607    msg.base.type = CSERVE2_CLOSE;
608    msg.file_id = fentry->file_id;
609
610    free(fentry);
611    ie->data1 = NULL;
612
613    if (!_server_send(&msg, sizeof(msg), NULL, NULL))
614      return 0;
615
616    return msg.base.rid;
617 }
618
619 unsigned int
620 _image_unload_server_send(Image_Entry *ie)
621 {
622    Msg_Unload msg;
623    Data_Entry *dentry;
624
625    if (cserve2_init == 0)
626      return 0;
627
628    if (!ie->data2)
629      return 0;
630
631    dentry = ie->data2;
632
633    if (dentry->shm.data)
634      eina_file_map_free(dentry->shm.f, dentry->shm.data);
635    if (dentry->shm.f)
636      eina_file_close(dentry->shm.f);
637
638    // if (dentry->shm.path)
639    //   free(dentry->shm.path);
640    memset(&msg, 0, sizeof(msg));
641    msg.base.rid = _next_rid();
642    msg.base.type = CSERVE2_UNLOAD;
643    msg.image_id = dentry->image_id;
644
645    free(dentry);
646    ie->data2 = NULL;
647
648    if (!_server_send(&msg, sizeof(msg), NULL, NULL))
649      return 0;
650
651    return msg.base.rid;
652 }
653
654 Eina_Bool
655 evas_cserve2_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
656 {
657    unsigned int rid;
658
659    rid = _image_open_server_send(ie, file, key, lopt);
660    if (!rid)
661      return EINA_FALSE;
662
663    ie->open_rid = rid;
664
665    _image_setopts_server_send(ie);
666
667    // _server_dispatch_until(rid);
668
669    if (ie->data1)
670      return EINA_TRUE;
671    else
672      return EINA_FALSE;
673 }
674
675 int
676 evas_cserve2_image_load_wait(Image_Entry *ie)
677 {
678    if (ie->open_rid)
679      {
680         _server_dispatch_until(ie->open_rid);
681         if (!ie->data1)
682           return CSERVE2_GENERIC;
683         return CSERVE2_NONE;
684      }
685    else
686      return CSERVE2_GENERIC;
687 }
688
689 Eina_Bool
690 evas_cserve2_image_data_load(Image_Entry *ie)
691 {
692    unsigned int rid;
693
694    rid = _image_load_server_send(ie);
695    if (!rid)
696      return EINA_FALSE;
697
698    ie->load_rid = rid;
699
700    if (ie->data2)
701      return EINA_TRUE;
702    else
703      return EINA_FALSE;
704 }
705
706 void
707 evas_cserve2_image_load_data_wait(Image_Entry *ie)
708 {
709    if (ie->load_rid)
710      _server_dispatch_until(ie->load_rid);
711 }
712
713 Eina_Bool
714 evas_cserve2_image_preload(Image_Entry *ie, void (*preloaded_cb)(void *im, Eina_Bool success))
715 {
716    unsigned int rid;
717
718    if (!ie->data1)
719      return EINA_FALSE;
720
721    rid = _image_preload_server_send(ie, preloaded_cb);
722    if (!rid)
723      return EINA_FALSE;
724
725    ie->preload_rid = rid;
726
727    return EINA_FALSE;
728 }
729
730 void
731 evas_cserve2_image_free(Image_Entry *ie)
732 {
733    if (!ie->data1)
734      return;
735
736    if (!_image_close_server_send(ie))
737      WRN("Couldn't send close message to cserve2.");
738 }
739
740 void
741 evas_cserve2_image_unload(Image_Entry *ie)
742 {
743    if (!ie->data2)
744      return;
745
746    if (!_image_unload_server_send(ie))
747      WRN("Couldn't send unload message to cserve2.");
748 }
749
750 void
751 evas_cserve2_dispatch(void)
752 {
753    _server_dispatch_until(0);
754 }
755 #endif