Ecore: ecore_con : make ecore_con work on Windows
[framework/uifw/ecore.git] / src / lib / ecore_con / ecore_con_local_win32.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <process.h>
6
7 #include <Evil.h>
8 #include <Ecore.h>
9
10 #include "Ecore_Con.h"
11 #include "ecore_con_private.h"
12
13 #define BUFSIZE 512
14
15
16 static int _ecore_con_local_init_count = 0;
17
18 int
19 ecore_con_local_init(void)
20 {
21    if (++_ecore_con_local_init_count != 1)
22      return _ecore_con_local_init_count;
23
24    return _ecore_con_local_init_count;
25 }
26
27 int
28 ecore_con_local_shutdown(void)
29 {
30    if (--_ecore_con_local_init_count != 0)
31      return _ecore_con_local_init_count;
32
33    return _ecore_con_local_init_count;
34 }
35
36
37 static Eina_Bool
38 _ecore_con_local_win32_server_read_client_handler(void *data, Ecore_Win32_Handler *wh)
39 {
40   Ecore_Con_Client *cl;
41   void *buf;
42   DWORD n;
43   Eina_Bool broken_pipe = EINA_FALSE;
44
45   cl = (Ecore_Con_Client *)data;
46
47   if (!ResetEvent(cl->host_server->event_read))
48     return ECORE_CALLBACK_RENEW;
49
50   buf = malloc(cl->host_server->nbr_bytes);
51   if (!buf)
52     return ECORE_CALLBACK_RENEW;
53
54   if (ReadFile(cl->host_server->pipe, buf, cl->host_server->nbr_bytes, &n, NULL))
55     {
56        if (!cl->delete_me)
57          ecore_con_event_client_data(cl, buf, cl->host_server->nbr_bytes, EINA_FALSE);
58        cl->host_server->want_write = 1;
59     }
60   else
61     {
62       if (GetLastError() == ERROR_BROKEN_PIPE)
63         broken_pipe = EINA_TRUE;
64     }
65
66   if (broken_pipe)
67     {
68 #if 0
69        char *msg;
70
71        msg = evil_last_error_get();
72        if (msg)
73          {
74             ecore_con_event_client_error(cl, msg);
75             free(msg);
76          }
77 #endif
78        if (!cl->delete_me)
79          ecore_con_event_client_del(cl);
80        cl->dead = EINA_TRUE;
81        return ECORE_CALLBACK_CANCEL;
82     }
83
84   if (cl->host_server->want_write)
85     ecore_con_local_win32_client_flush(cl);
86
87    ecore_main_win32_handler_del(wh);
88
89   return ECORE_CALLBACK_DONE;
90 }
91
92 static Eina_Bool
93 _ecore_con_local_win32_server_peek_client_handler(void *data, Ecore_Win32_Handler *wh)
94 {
95    Ecore_Con_Client *cl;
96 #if 0
97    char *msg;
98 #endif
99
100    cl = (Ecore_Con_Client *)data;
101
102    if (!ResetEvent(cl->host_server->event_peek))
103      return ECORE_CALLBACK_RENEW;
104
105 #if 0
106    msg = evil_last_error_get();
107    if (msg)
108      {
109         ecore_con_event_server_error(cl->host_server, msg);
110         free(msg);
111      }
112 #endif
113    if (!cl->host_server->delete_me)
114      ecore_con_event_server_del(cl->host_server);
115    cl->host_server->dead = EINA_TRUE;
116    return ECORE_CALLBACK_CANCEL;
117
118    ecore_main_win32_handler_del(wh);
119
120    return ECORE_CALLBACK_DONE;
121 }
122
123 static Eina_Bool
124 _ecore_con_local_win32_client_peek_server_handler(void *data, Ecore_Win32_Handler *wh)
125 {
126    Ecore_Con_Server *svr;
127 #if 0
128    char *msg;
129 #endif
130
131    svr = (Ecore_Con_Server *)data;
132
133    if (!ResetEvent(svr->event_peek))
134      return ECORE_CALLBACK_RENEW;
135 #if 0
136    msg = evil_last_error_get();
137    if (msg)
138      {
139         ecore_con_event_server_error(svr, msg);
140         free(msg);
141      }
142 #endif
143    if (!svr->delete_me)
144      ecore_con_event_server_del(svr);
145    svr->dead = EINA_TRUE;
146    return ECORE_CALLBACK_CANCEL;
147
148    ecore_main_win32_handler_del(wh);
149
150    return ECORE_CALLBACK_DONE;
151 }
152
153 static Eina_Bool
154 _ecore_con_local_win32_client_read_server_handler(void *data, Ecore_Win32_Handler *wh)
155 {
156   Ecore_Con_Server *svr;
157   void *buf;
158   DWORD n;
159   Eina_Bool broken_pipe = EINA_FALSE;
160
161   svr = (Ecore_Con_Server *)data;
162
163   if (!ResetEvent(svr->event_read))
164     return ECORE_CALLBACK_RENEW;
165
166   buf = malloc(svr->nbr_bytes);
167   if (!buf)
168     return ECORE_CALLBACK_RENEW;
169
170   if (ReadFile(svr->pipe, buf, svr->nbr_bytes, &n, NULL))
171     {
172        if (!svr->delete_me)
173          ecore_con_event_server_data(svr, buf, svr->nbr_bytes, EINA_FALSE);
174        svr->want_write = 1;
175     }
176   else
177     {
178       if (GetLastError() == ERROR_BROKEN_PIPE)
179         broken_pipe = EINA_TRUE;
180     }
181
182   if (broken_pipe)
183     {
184 #if 0
185        char *msg;
186
187        msg = evil_last_error_get();
188        if (msg)
189          {
190             ecore_con_event_server_error(svr, msg);
191             free(msg);
192          }
193 #endif
194        if (!svr->delete_me)
195          ecore_con_event_server_del(svr);
196        svr->dead = EINA_TRUE;
197        return ECORE_CALLBACK_CANCEL;
198     }
199
200   if (svr->want_write)
201     ecore_con_local_win32_server_flush(svr);
202
203    ecore_main_win32_handler_del(wh);
204
205   return ECORE_CALLBACK_DONE;
206 }
207
208 /* thread to read data sent by the server to the client */
209 static unsigned int __stdcall
210 _ecore_con_local_win32_client_read_server_thread(void *data)
211 {
212    Ecore_Con_Server *svr;
213    DWORD nbr_bytes = 0;
214
215    svr = (Ecore_Con_Server *)data;
216
217    svr->read_stopped = EINA_FALSE;
218
219    while (!svr->read_stop)
220      {
221         if (PeekNamedPipe(svr->pipe, NULL, 0, NULL, &nbr_bytes, NULL))
222           {
223              if (nbr_bytes <= 0)
224                continue;
225
226              svr->nbr_bytes = nbr_bytes;
227              if (!SetEvent(svr->event_read))
228                continue;
229           }
230         else
231           {
232              if (GetLastError() == ERROR_BROKEN_PIPE)
233                {
234                   if (!SetEvent(svr->event_peek))
235                     continue;
236                   break;
237                }
238           }
239      }
240
241    printf(" ### %s\n", __FUNCTION__);
242    svr->read_stopped = EINA_TRUE;
243    _endthreadex(0);
244    return 0;
245 }
246
247 /* thread to read data sent by the client to the server */
248 static unsigned int __stdcall
249 _ecore_con_local_win32_server_read_client_thread(void *data)
250 {
251    Ecore_Con_Client *cl;
252    DWORD nbr_bytes = 0;
253
254    cl = (Ecore_Con_Client *)data;
255
256    cl->host_server->read_stopped = EINA_FALSE;
257
258    while (!cl->host_server->read_stop)
259      {
260         if (PeekNamedPipe(cl->host_server->pipe, NULL, 0, NULL, &nbr_bytes, NULL))
261           {
262              if (nbr_bytes <= 0)
263                continue;
264
265              cl->host_server->nbr_bytes = nbr_bytes;
266              if (!SetEvent(cl->host_server->event_read))
267                continue;
268           }
269         else
270           {
271              if (GetLastError() == ERROR_BROKEN_PIPE)
272                {
273                   if (!SetEvent(cl->host_server->event_peek))
274                     continue;
275                   break;
276                }
277           }
278      }
279
280    printf(" ### %s\n", __FUNCTION__);
281    cl->host_server->read_stopped = EINA_TRUE;
282    _endthreadex(0);
283    return 0;
284 }
285
286 static Eina_Bool
287 _ecore_con_local_win32_client_add(void *data, Ecore_Win32_Handler *wh)
288 {
289    Ecore_Con_Client *cl = NULL;
290    Ecore_Con_Server *svr;
291    Ecore_Win32_Handler *handler_read;
292    Ecore_Win32_Handler *handler_peek;
293
294    svr = (Ecore_Con_Server *)data;
295
296    if (!svr->pipe)
297      return ECORE_CALLBACK_CANCEL;
298
299    if (svr->dead)
300      return ECORE_CALLBACK_CANCEL;
301
302    if (svr->delete_me)
303      return ECORE_CALLBACK_CANCEL;
304
305    if ((svr->client_limit >= 0) && (!svr->reject_excess_clients) &&
306        (svr->client_count >= (unsigned int)svr->client_limit))
307      return ECORE_CALLBACK_CANCEL;
308
309    cl = calloc(1, sizeof(Ecore_Con_Client));
310    if (!cl)
311      {
312         ERR("allocation failed");
313         return ECORE_CALLBACK_CANCEL;
314      }
315
316    cl->host_server = svr;
317    ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
318
319    cl->host_server->event_read = CreateEvent(NULL, TRUE, FALSE, NULL);
320    if (!cl->host_server->event_read)
321      {
322         ERR("Can not create event read");
323         goto free_cl;
324      }
325
326    handler_read = ecore_main_win32_handler_add(cl->host_server->event_read,
327                                                _ecore_con_local_win32_server_read_client_handler,
328                                                cl);
329    if (!handler_read)
330      {
331         ERR("Can not create handler read");
332         goto close_event_read;
333      }
334
335    cl->host_server->event_peek = CreateEvent(NULL, TRUE, FALSE, NULL);
336    if (!cl->host_server->event_peek)
337      {
338         ERR("Can not create event peek");
339         goto del_handler_read;
340      }
341
342    handler_peek = ecore_main_win32_handler_add(cl->host_server->event_peek,
343                                                _ecore_con_local_win32_server_peek_client_handler,
344                                                cl);
345    if (!handler_peek)
346      {
347         ERR("Can not create handler peek");
348         goto close_event_peek;
349      }
350
351    cl->host_server->read_stopped = EINA_TRUE;
352    cl->host_server->thread_read = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_server_read_client_thread, cl, CREATE_SUSPENDED, NULL);
353    if (!cl->host_server->thread_read)
354      {
355         ERR("Can not launch thread");
356         goto del_handler_peek;
357      }
358
359    svr->clients = eina_list_append(svr->clients, cl);
360    svr->client_count++;
361
362    if (!cl->delete_me)
363      ecore_con_event_client_add(cl);
364
365    ecore_main_win32_handler_del(wh);
366
367    ResumeThread(cl->host_server->thread_read);
368    return ECORE_CALLBACK_DONE;
369
370  del_handler_peek:
371    ecore_main_win32_handler_del(handler_peek);
372  close_event_peek:
373    CloseHandle(cl->host_server->event_peek);
374  del_handler_read:
375    ecore_main_win32_handler_del(handler_read);
376  close_event_read:
377    CloseHandle(cl->host_server->event_read);
378  free_cl:
379    free(cl);
380
381    return ECORE_CALLBACK_CANCEL;
382 }
383
384 static unsigned int __stdcall
385 _ecore_con_local_win32_listening(void *data)
386 {
387    Ecore_Con_Server *svr;
388    BOOL res;
389
390    svr = (Ecore_Con_Server *)data;
391
392    while (1)
393      {
394         res = ConnectNamedPipe(svr->pipe, NULL);
395         if (!res)
396           {
397              ERR("Opening the connection to the client failed");
398              CloseHandle(svr->pipe);
399              svr->pipe = NULL;
400           }
401         break;
402      }
403
404    DBG("Client connected");
405
406    printf(" ### %s\n", __FUNCTION__);
407    _endthreadex(0);
408    return 0;
409 }
410
411 Eina_Bool
412 ecore_con_local_listen(Ecore_Con_Server *svr)
413 {
414    char buf[256];
415    HANDLE thread_listening;
416    Ecore_Win32_Handler *handler;
417
418    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
419      {
420         ERR("Your system does not support abstract sockets!");
421         return EINA_FALSE;
422      }
423
424    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
425      snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", svr->name);
426    else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
427      {
428         const char *computername;
429
430         computername = getenv("CoMPUTERNAME");
431         snprintf(buf, sizeof(buf), "\\\\%s\\pipe\\%s", computername, svr->name);
432      }
433
434    svr->path = strdup(buf);
435    if (!svr->path)
436      {
437         ERR("Allocation failed");
438         return EINA_FALSE;
439      }
440
441    /*
442     * synchronuous
443     * block mode
444     * wait mode
445     */
446    svr->pipe = CreateNamedPipe(svr->path,
447                                PIPE_ACCESS_DUPLEX,
448                                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
449                                PIPE_UNLIMITED_INSTANCES,
450                                BUFSIZE,
451                                BUFSIZE,
452                                5000,
453                                NULL);
454    if (svr->pipe == INVALID_HANDLE_VALUE)
455      {
456         ERR("Creation of the named pipe failed");
457         goto free_path;
458      }
459
460    /*
461     * We use ConnectNamedPipe() to wait for a client to connect.
462     * As the function is blocking, to let the main loop continuing
463     * its iterations, we call ConnectNamedPipe() in a thread
464     */
465    thread_listening = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_listening, svr, CREATE_SUSPENDED, NULL);
466    if (!thread_listening)
467      {
468         ERR("Creation of the listening thread failed");
469         goto close_pipe;
470      }
471
472    handler = ecore_main_win32_handler_add(thread_listening,
473                                           _ecore_con_local_win32_client_add,
474                                           svr);
475    if (!handler)
476      {
477         ERR("Creation of the client add handler failed");
478         goto del_handler;
479      }
480
481    svr->read_stopped = EINA_TRUE;
482    ResumeThread(thread_listening);
483
484    return EINA_TRUE;
485
486  del_handler:
487    ecore_main_win32_handler_del(handler);
488  close_pipe:
489    CloseHandle(svr->pipe);
490  free_path:
491    free(svr->path);
492    svr->path = NULL;
493
494    return EINA_FALSE;
495 }
496
497 void
498 ecore_con_local_win32_server_del(Ecore_Con_Server *svr)
499 {
500    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
501      return;
502
503    if (((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) &&
504        ((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM))
505      return;
506
507    svr->read_stop = 1;
508    while (!svr->read_stopped)
509      Sleep(100);
510
511    if (svr->event_peek)
512      CloseHandle(svr->event_peek);
513    svr->event_peek = NULL;
514    if (svr->event_read)
515      CloseHandle(svr->event_read);
516    svr->event_read = NULL;
517    free(svr->path);
518    svr->path = NULL;
519    if (svr->pipe)
520      CloseHandle(svr->pipe);
521    svr->pipe = NULL;
522 }
523
524 void
525 ecore_con_local_win32_client_del(Ecore_Con_Client *cl)
526 {
527    if ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
528      return;
529
530    if (((cl->host_server->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) &&
531        ((cl->host_server->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM))
532      return;
533
534    cl->host_server->read_stop = 1;
535    while (!cl->host_server->read_stopped)
536      Sleep(100);
537
538    if (cl->host_server->event_peek)
539      CloseHandle(cl->host_server->event_peek);
540    cl->host_server->event_peek = NULL;
541    if (cl->host_server->event_read)
542      CloseHandle(cl->host_server->event_read);
543    cl->host_server->event_read = NULL;
544    free(cl->host_server->path);
545    cl->host_server->path = NULL;
546    if (cl->host_server->pipe)
547      CloseHandle(cl->host_server->pipe);
548    cl->host_server->pipe = NULL;
549 }
550
551 Eina_Bool
552 ecore_con_local_connect(Ecore_Con_Server *svr,
553                         Eina_Bool (*cb_done)(void *data,
554                                              Ecore_Fd_Handler *fd_handler),
555                         void (*cb_free)(void *data, void *ev))
556 {
557    char buf[256];
558    Ecore_Win32_Handler *handler_read;
559    Ecore_Win32_Handler *handler_peek;
560
561    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
562      {
563         ERR("Your system does not support abstract sockets!");
564         return EINA_FALSE;
565      }
566
567    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER)
568      snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", svr->name);
569    else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)
570      {
571         const char *computername;
572
573         computername = getenv("COMPUTERNAME");
574         snprintf(buf, sizeof(buf), "\\\\%s\\pipe\\%s", computername, svr->name);
575      }
576
577    while (1)
578      {
579         svr->pipe = CreateFile(buf,
580                                GENERIC_READ | GENERIC_WRITE,
581                                0,
582                                NULL,
583                                OPEN_EXISTING,
584                                0,
585                                NULL);
586         if (svr->pipe != INVALID_HANDLE_VALUE)
587           break;
588
589         /* if pipe not busy, we exit */
590         if (GetLastError() != ERROR_PIPE_BUSY)
591           {
592              ERR("Connection to a server failed");
593              return EINA_FALSE;
594         }
595
596         /* pipe busy, so we wait for it */
597         if (!WaitNamedPipe(buf, NMPWAIT_WAIT_FOREVER))
598           {
599              ERR("Can not wait for a server");
600              goto close_pipe;
601           }
602      }
603
604    svr->path = strdup(buf);
605    if (!svr->path)
606      {
607         ERR("Allocation failed");
608         goto close_pipe;
609      }
610
611    svr->event_read = CreateEvent(NULL, TRUE, FALSE, NULL);
612    if (!svr->event_read)
613      {
614         ERR("Can not create event read");
615         goto free_path;
616      }
617
618    handler_read = ecore_main_win32_handler_add(svr->event_read,
619                                                _ecore_con_local_win32_client_read_server_handler,
620                                                svr);
621    if (!handler_read)
622      {
623         ERR("Can not create handler read");
624         goto close_event_read;
625      }
626
627    svr->event_peek = CreateEvent(NULL, TRUE, FALSE, NULL);
628    if (!svr->event_peek)
629      {
630         ERR("Can not create event peek");
631         goto del_handler_read;
632      }
633
634    handler_peek = ecore_main_win32_handler_add(svr->event_peek,
635                                                _ecore_con_local_win32_client_peek_server_handler,
636                                                svr);
637    if (!handler_peek)
638      {
639         ERR("Can not create handler peek");
640         goto close_event_peek;
641      }
642
643    svr->thread_read = (HANDLE)_beginthreadex(NULL, 0, _ecore_con_local_win32_client_read_server_thread, svr, CREATE_SUSPENDED, NULL);
644    if (!svr->thread_read)
645      {
646         ERR("Can not launch thread");
647         goto del_handler_peek;
648      }
649
650    if (!svr->delete_me)
651      {
652         Ecore_Con_Event_Server_Add *e;
653
654         e = calloc(1, sizeof(Ecore_Con_Event_Server_Add));
655         if (e)
656           {
657              svr->event_count++;
658              e->server = svr;
659              ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e,
660                              cb_free, NULL);
661           }
662      }
663
664    ResumeThread(svr->thread_read);
665
666    return EINA_TRUE;
667
668  del_handler_peek:
669    ecore_main_win32_handler_del(handler_peek);
670  close_event_peek:
671    CloseHandle(svr->event_peek);
672  del_handler_read:
673    ecore_main_win32_handler_del(handler_read);
674  close_event_read:
675    CloseHandle(svr->event_read);
676  free_path:
677    free(svr->path);
678    svr->path = NULL;
679  close_pipe:
680    CloseHandle(svr->pipe);
681
682    return EINA_FALSE;
683 }
684
685 Eina_Bool
686 ecore_con_local_win32_server_flush(Ecore_Con_Server *svr)
687 {
688    int num;
689    BOOL res;
690    DWORD written;
691
692    /* This check should never be true */
693    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
694      return EINA_TRUE;
695
696    if (((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_USER) &&
697        ((svr->type & ECORE_CON_TYPE) != ECORE_CON_LOCAL_SYSTEM))
698      return EINA_FALSE;
699
700    num = svr->write_buf_size - svr->write_buf_offset;
701    if (num <= 0) return EINA_TRUE;
702
703    res = WriteFile(svr->pipe, svr->write_buf + svr->write_buf_offset, num, &written, NULL);
704    if (!res)
705      {
706         char *msg;
707
708         msg = evil_last_error_get();
709         if (msg)
710           {
711              ecore_con_event_server_error(svr, msg);
712              free(msg);
713           }
714         if (!svr->delete_me)
715           ecore_con_event_server_del(svr);
716         svr->dead = EINA_TRUE;
717      }
718
719    svr->write_buf_offset += written;
720    if (svr->write_buf_offset >= svr->write_buf_size)
721      {
722         svr->write_buf_size = 0;
723         svr->write_buf_offset = 0;
724         free(svr->write_buf);
725         svr->write_buf = NULL;
726         svr->want_write = 0;
727      }
728    else if (written < (DWORD)num)
729      svr->want_write = 1;
730
731    return EINA_TRUE;
732 }
733
734 Eina_Bool
735 ecore_con_local_win32_client_flush(Ecore_Con_Client *cl)
736 {
737    Ecore_Con_Type type;
738    int num;
739    BOOL res;
740    DWORD written;
741
742    type = cl->host_server->type & ECORE_CON_TYPE;
743
744    /* This check should never be true */
745    if (type == ECORE_CON_LOCAL_ABSTRACT)
746      return EINA_TRUE;
747
748    if ((type != ECORE_CON_LOCAL_USER) &&
749        (type != ECORE_CON_LOCAL_SYSTEM))
750      return EINA_FALSE;
751
752    num = cl->buf_size - cl->buf_offset;
753    if (num <= 0) return EINA_TRUE;
754
755    res = WriteFile(cl->host_server->pipe, cl->buf + cl->buf_offset, num, &written, NULL);
756    if (!res)
757      {
758         char *msg;
759
760         msg = evil_last_error_get();
761         if (msg)
762           {
763              ecore_con_event_client_error(cl, msg);
764              free(msg);
765           }
766         if (!cl->delete_me)
767           ecore_con_event_client_del(cl);
768         cl->dead = EINA_TRUE;
769      }
770
771    cl->buf_offset += written;
772    if (cl->buf_offset >= cl->buf_size)
773      {
774         cl->buf_size = 0;
775         cl->buf_offset = 0;
776         free(cl->buf);
777         cl->buf = NULL;
778         cl->host_server->want_write = 0;
779      }
780    else if (written < (DWORD)num)
781      cl->host_server->want_write = 1;
782
783    return EINA_TRUE;
784 }