Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_con / ecore_con_info.c
1 /*
2  * getaddrinfo with callback
3  *
4  * man getaddrinfo
5  *
6  */
7
8 #ifdef HAVE_CONFIG_H
9 # include <config.h>
10 #endif
11
12 #ifdef HAVE_ALLOCA_H
13 # include <alloca.h>
14 #elif defined __GNUC__
15 # define alloca __builtin_alloca
16 #elif defined _AIX
17 # define alloca __alloca
18 #elif defined _MSC_VER
19 # include <malloc.h>
20 # define alloca _alloca
21 #else
22 # include <stddef.h>
23 # ifdef  __cplusplus
24 extern "C"
25 # endif
26 void *alloca(size_t);
27 #endif
28
29 #include <string.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #ifdef __OpenBSD__
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_NETINET_IN_H
38 # include <netinet/in.h>
39 #endif
40
41 #ifdef HAVE_ARPA_INET_H
42 # include <arpa/inet.h>
43 #endif
44
45 #ifdef HAVE_ARPA_NAMESER_H
46 # include <arpa/nameser.h>
47 #endif
48
49 #ifdef HAVE_SYS_SOCKET_H
50 # include <sys/socket.h>
51 #endif
52
53 #ifdef HAVE_NETDB_H
54 # include <netdb.h>
55 #endif
56
57 #include <errno.h>
58
59 #include "Ecore.h"
60 #include "ecore_private.h"
61 #include "ecore_con_private.h"
62
63 typedef struct _CB_Data CB_Data;
64
65 struct _CB_Data
66 {
67                         EINA_INLIST;
68    Ecore_Con_Info_Cb    cb_done;
69    void                *data;
70    Ecore_Fd_Handler    *fdh;
71    pid_t                pid;
72    Ecore_Event_Handler *handler;
73    int                  fd2;
74 };
75
76 static void      _ecore_con_info_readdata(CB_Data *cbdata);
77 static void      _ecore_con_info_slave_free(CB_Data *cbdata);
78 static Eina_Bool _ecore_con_info_data_handler(void             *data,
79                                               Ecore_Fd_Handler *fd_handler);
80 static Eina_Bool _ecore_con_info_exit_handler(void    *data,
81                                               int type __UNUSED__,
82                                               void    *event);
83
84 static int info_init = 0;
85 static CB_Data *info_slaves = NULL;
86
87 int
88 ecore_con_info_init(void)
89 {
90    info_init++;
91    return info_init;
92 }
93
94 int
95 ecore_con_info_shutdown(void)
96 {
97    info_init--;
98    if (info_init == 0)
99      while (info_slaves) _ecore_con_info_slave_free(info_slaves);
100
101    return info_init;
102 }
103
104 int
105 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
106                            Ecore_Con_Info_Cb done_cb,
107                            void             *data)
108 {
109    struct addrinfo hints;
110
111    memset(&hints, 0, sizeof(struct addrinfo));
112    hints.ai_family = AF_UNSPEC;
113    hints.ai_socktype = SOCK_STREAM;
114    hints.ai_flags = AI_CANONNAME;
115    hints.ai_protocol = IPPROTO_TCP;
116    hints.ai_canonname = NULL;
117    hints.ai_next = NULL;
118    hints.ai_addr = NULL;
119
120    return ecore_con_info_get(svr, done_cb, data, &hints);
121 }
122
123 int
124 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
125                           Ecore_Con_Info_Cb done_cb,
126                           void             *data)
127 {
128    struct addrinfo hints;
129
130    memset(&hints, 0, sizeof(struct addrinfo));
131    hints.ai_family = AF_UNSPEC;
132    hints.ai_socktype = SOCK_STREAM;
133    hints.ai_flags = AI_PASSIVE;
134    hints.ai_protocol = IPPROTO_TCP;
135    hints.ai_canonname = NULL;
136    hints.ai_next = NULL;
137    hints.ai_addr = NULL;
138
139    return ecore_con_info_get(svr, done_cb, data, &hints);
140 }
141
142 int
143 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
144                            Ecore_Con_Info_Cb done_cb,
145                            void             *data)
146 {
147    struct addrinfo hints;
148
149    memset(&hints, 0, sizeof(struct addrinfo));
150    hints.ai_family = AF_UNSPEC;
151    hints.ai_socktype = SOCK_DGRAM;
152    hints.ai_flags = AI_CANONNAME;
153    hints.ai_protocol = IPPROTO_UDP;
154    hints.ai_canonname = NULL;
155    hints.ai_next = NULL;
156    hints.ai_addr = NULL;
157
158    return ecore_con_info_get(svr, done_cb, data, &hints);
159 }
160
161 int
162 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
163                           Ecore_Con_Info_Cb done_cb,
164                           void             *data)
165 {
166    struct addrinfo hints;
167
168    memset(&hints, 0, sizeof(struct addrinfo));
169    hints.ai_family = AF_UNSPEC;
170    hints.ai_socktype = SOCK_DGRAM;
171    hints.ai_flags = AI_PASSIVE;
172    hints.ai_protocol = IPPROTO_UDP;
173    hints.ai_canonname = NULL;
174    hints.ai_next = NULL;
175    hints.ai_addr = NULL;
176
177    return ecore_con_info_get(svr, done_cb, data, &hints);
178 }
179
180 int
181 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
182                             Ecore_Con_Info_Cb done_cb,
183                             void             *data)
184 {
185    struct addrinfo hints;
186
187    memset(&hints, 0, sizeof(struct addrinfo));
188    hints.ai_family = AF_UNSPEC;
189    hints.ai_socktype = SOCK_DGRAM;
190    hints.ai_flags = 0;
191    hints.ai_protocol = IPPROTO_UDP;
192    hints.ai_canonname = NULL;
193    hints.ai_next = NULL;
194    hints.ai_addr = NULL;
195
196    return ecore_con_info_get(svr, done_cb, data, &hints);
197 }
198
199 Eina_Bool
200 _ecore_fd_close_on_exec(int fd)
201 {
202 #ifdef HAVE_EXECVP
203    int flags;
204
205    flags = fcntl(fd, F_GETFD);
206    if (flags == -1)
207      return EINA_FALSE;
208
209    flags |= FD_CLOEXEC;
210    if (fcntl(fd, F_SETFD, flags) == -1)
211      return EINA_FALSE;
212    return EINA_TRUE;
213 #else
214    (void) fd;
215    return EINA_FALSE;
216 #endif
217 }
218
219 EAPI int
220 ecore_con_info_get(Ecore_Con_Server *svr,
221                    Ecore_Con_Info_Cb done_cb,
222                    void             *data,
223                    struct addrinfo  *hints)
224 {
225    CB_Data *cbdata;
226    int fd[2];
227
228    if (pipe(fd) < 0)
229      {
230         ecore_con_event_server_error(svr, strerror(errno));
231         return 0;
232      }
233
234    _ecore_fd_close_on_exec(fd[0]);
235    _ecore_fd_close_on_exec(fd[1]);
236
237    cbdata = calloc(1, sizeof(CB_Data));
238    if (!cbdata)
239      {
240         close(fd[0]);
241         close(fd[1]);
242         return 0;
243      }
244
245    cbdata->cb_done = done_cb;
246    cbdata->data = data;
247    cbdata->fd2 = fd[1];
248    if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ,
249                                                  _ecore_con_info_data_handler,
250                                                  cbdata,
251                                                  NULL, NULL)))
252      {
253         ecore_con_event_server_error(svr, "Memory allocation failure");
254         free(cbdata);
255         close(fd[0]);
256         close(fd[1]);
257         return 0;
258      }
259
260    if ((cbdata->pid = fork()) == 0)
261      {
262         Ecore_Con_Info *container;
263         struct addrinfo *result = NULL;
264         char service[NI_MAXSERV] = {0};
265         char hbuf[NI_MAXHOST] = {0};
266         char sbuf[NI_MAXSERV] = {0};
267         unsigned char *tosend = NULL;
268         int tosend_len;
269         int canonname_len = 0;
270
271         eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, service);
272         /* CHILD */
273         if (!getaddrinfo(svr->ecs ? svr->ecs->ip : svr->name, service, hints, &result) && result)
274           {
275              if (result->ai_canonname)
276                canonname_len = strlen(result->ai_canonname) + 1;
277
278              tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen +
279                canonname_len;
280
281              tosend = alloca(tosend_len);
282              memset(tosend, 0, tosend_len);
283
284              container = (Ecore_Con_Info *)tosend;
285              container->size = tosend_len;
286
287              memcpy(&container->info,
288                     result,
289                     sizeof(struct addrinfo));
290              memcpy(tosend + sizeof(Ecore_Con_Info),
291                     result->ai_addr,
292                     result->ai_addrlen);
293              if (result->ai_canonname) /* FIXME: else... */
294                memcpy(tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen,
295                       result->ai_canonname,
296                       canonname_len);
297
298              if (!getnameinfo(result->ai_addr, result->ai_addrlen,
299                               hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
300                               NI_NUMERICHOST | NI_NUMERICSERV))
301                {
302                   memcpy(container->ip, hbuf, sizeof(container->ip));
303                   memcpy(container->service, sbuf, sizeof(container->service));
304                }
305
306              if (write(fd[1], tosend, tosend_len) < 0) perror("write");
307           }
308
309         if (result)
310           freeaddrinfo(result);
311
312         if (write(fd[1], "", 1) < 0) perror("write");
313         close(fd[1]);
314 #if defined(__USE_ISOC99) && !defined(__UCLIBC__)
315         _Exit(0);
316 #else
317         _exit(0);
318 #endif
319      }
320
321    /* PARENT */
322    cbdata->handler =
323      ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler,
324                              cbdata);
325    close(fd[1]);
326    if (!cbdata->handler)
327      {
328         ecore_main_fd_handler_del(cbdata->fdh);
329         free(cbdata);
330         close(fd[0]);
331         return 0;
332      }
333
334    info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(
335                                                  info_slaves),
336                                                EINA_INLIST_GET(cbdata));
337    svr->infos = eina_list_append(svr->infos, cbdata);
338    return 1;
339 }
340
341 void
342 ecore_con_info_data_clear(void *info)
343 {
344    CB_Data *cbdata = info;
345    cbdata->data = NULL;
346 }
347
348 static void
349 _ecore_con_info_readdata(CB_Data *cbdata)
350 {
351    Ecore_Con_Info container;
352    Ecore_Con_Info *recv_info;
353    unsigned char *torecv;
354    int torecv_len;
355
356    ssize_t size;
357
358    size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container,
359                sizeof(Ecore_Con_Info));
360    if (size == sizeof(Ecore_Con_Info))
361      {
362         torecv_len = container.size;
363         torecv = malloc(torecv_len);
364
365         memcpy(torecv, &container, sizeof(Ecore_Con_Info));
366
367         size = read(ecore_main_fd_handler_fd_get(cbdata->fdh),
368                     torecv + sizeof(Ecore_Con_Info),
369                     torecv_len - sizeof(Ecore_Con_Info));
370         if ((size > 0) &&
371             ((size_t)size == torecv_len - sizeof(Ecore_Con_Info)))
372           {
373              recv_info = (Ecore_Con_Info *)torecv;
374
375              recv_info->info.ai_addr =
376                (struct sockaddr *)(torecv + sizeof(Ecore_Con_Info));
377              if ((size_t)torecv_len !=
378                  (sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen))
379                recv_info->info.ai_canonname = (char *)
380                  (torecv + sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen);
381              else
382                recv_info->info.ai_canonname = NULL;
383
384              recv_info->info.ai_next = NULL;
385
386              if (cbdata->data)
387                {
388                   cbdata->cb_done(cbdata->data, recv_info);
389                   ecore_con_server_infos_del(cbdata->data, cbdata);
390                }
391
392              free(torecv);
393           }
394         else
395           {
396              if (cbdata->data)
397                {
398                   cbdata->cb_done(cbdata->data, NULL);
399                   ecore_con_server_infos_del(cbdata->data, cbdata);
400                }
401           }
402      }
403    else
404      {
405         if (cbdata->data)
406           {
407              ecore_con_event_server_error(cbdata->data, strerror(errno));
408              cbdata->cb_done(cbdata->data, NULL);
409              ecore_con_server_infos_del(cbdata->data, cbdata);
410           }
411      }
412
413    cbdata->cb_done = NULL;
414 }
415
416 static void
417 _ecore_con_info_slave_free(CB_Data *cbdata)
418 {
419    info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves),
420                                                EINA_INLIST_GET(cbdata));
421    ecore_main_fd_handler_del(cbdata->fdh);
422    ecore_event_handler_del(cbdata->handler);
423    close(ecore_main_fd_handler_fd_get(cbdata->fdh));
424    if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
425    free(cbdata);
426 }
427
428 static Eina_Bool
429 _ecore_con_info_data_handler(void             *data,
430                              Ecore_Fd_Handler *fd_handler)
431 {
432    CB_Data *cbdata;
433
434    cbdata = data;
435    if (cbdata->cb_done)
436      {
437         if (ecore_main_fd_handler_active_get(fd_handler,
438                                              ECORE_FD_READ))
439           _ecore_con_info_readdata(cbdata);
440         else
441           {
442              if (cbdata->data)
443                {
444                   cbdata->cb_done(cbdata->data, NULL);
445                   cbdata->cb_done = NULL;
446                   ecore_con_server_infos_del(cbdata->data, cbdata);
447                }
448           }
449      }
450
451    _ecore_con_info_slave_free(cbdata);
452    return ECORE_CALLBACK_CANCEL;
453 }
454
455 static Eina_Bool
456 _ecore_con_info_exit_handler(void    *data,
457                              int type __UNUSED__,
458                              void    *event)
459 {
460    CB_Data *cbdata;
461    Ecore_Exe_Event_Del *ev;
462
463    ev = event;
464    cbdata = data;
465    if (cbdata->pid != ev->pid)
466      return ECORE_CALLBACK_RENEW;
467
468    return ECORE_CALLBACK_CANCEL; /* FIXME: Woot ??? */
469    _ecore_con_info_slave_free(cbdata);
470    return ECORE_CALLBACK_CANCEL;
471 }
472