svn update: 60286 (latest:60286)
[profile/ivi/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_ARPA_INET_H
38 # include <arpa/inet.h>
39 #endif
40
41 #ifdef HAVE_ARPA_NAMESER_H
42 # include <arpa/nameser.h>
43 #endif
44
45 #ifdef HAVE_NETINET_IN_H
46 # include <netinet/in.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 EAPI int
200 ecore_con_info_get(Ecore_Con_Server *svr,
201                    Ecore_Con_Info_Cb done_cb,
202                    void             *data,
203                    struct addrinfo  *hints)
204 {
205    CB_Data *cbdata;
206    int fd[2];
207
208    if (pipe(fd) < 0)
209      {
210         ecore_con_event_server_error(svr, strerror(errno));
211         return 0;
212      }
213
214    cbdata = calloc(1, sizeof(CB_Data));
215    if (!cbdata)
216      {
217         close(fd[0]);
218         close(fd[1]);
219         return 0;
220      }
221
222    cbdata->cb_done = done_cb;
223    cbdata->data = data;
224    cbdata->fd2 = fd[1];
225    if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ,
226                                                  _ecore_con_info_data_handler,
227                                                  cbdata,
228                                                  NULL, NULL)))
229      {
230         ecore_con_event_server_error(svr, "Memory allocation failure");
231         free(cbdata);
232         close(fd[0]);
233         close(fd[1]);
234         return 0;
235      }
236
237    if ((cbdata->pid = fork()) == 0)
238      {
239         Ecore_Con_Info *container;
240         struct addrinfo *result = NULL;
241         char service[NI_MAXSERV] = {0};
242         char hbuf[NI_MAXHOST] = {0};
243         char sbuf[NI_MAXSERV] = {0};
244         unsigned char *tosend = NULL;
245         int tosend_len;
246         int canonname_len = 0;
247         int err;
248
249         eina_convert_itoa(svr->port, service);
250         /* CHILD */
251         if (!getaddrinfo(svr->name, service, hints, &result) && result)
252           {
253              if (result->ai_canonname)
254                canonname_len = strlen(result->ai_canonname) + 1;
255
256              tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen +
257                canonname_len;
258
259              tosend = alloca(tosend_len);
260              memset(tosend, 0, tosend_len);
261
262              container = (Ecore_Con_Info *)tosend;
263              container->size = tosend_len;
264
265              memcpy(&container->info,
266                     result,
267                     sizeof(struct addrinfo));
268              memcpy(tosend + sizeof(Ecore_Con_Info),
269                     result->ai_addr,
270                     result->ai_addrlen);
271              if (result->ai_canonname) /* FIXME: else... */
272                memcpy(tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen,
273                       result->ai_canonname,
274                       canonname_len);
275
276              if (!getnameinfo(result->ai_addr, result->ai_addrlen,
277                               hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
278                               NI_NUMERICHOST | NI_NUMERICSERV))
279                {
280                   memcpy(container->ip, hbuf, sizeof(container->ip));
281                   memcpy(container->service, sbuf, sizeof(container->service));
282                }
283
284              err = write(fd[1], tosend, tosend_len);
285           }
286
287         if (result)
288           freeaddrinfo(result);
289
290         err = write(fd[1], "", 1);
291         close(fd[1]);
292 #ifdef __USE_ISOC99
293         _Exit(0);
294 #else
295         _exit(0);
296 #endif
297      }
298
299    /* PARENT */
300    cbdata->handler =
301      ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler,
302                              cbdata);
303    close(fd[1]);
304    if (!cbdata->handler)
305      {
306         ecore_main_fd_handler_del(cbdata->fdh);
307         free(cbdata);
308         close(fd[0]);
309         return 0;
310      }
311
312    info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(
313                                                  info_slaves),
314                                                EINA_INLIST_GET(cbdata));
315    svr->infos = eina_list_append(svr->infos, cbdata);
316    return 1;
317 }
318
319 void
320 ecore_con_info_data_clear(void *info)
321 {
322    CB_Data *cbdata = info;
323    cbdata->data = NULL;
324 }
325
326 static void
327 _ecore_con_info_readdata(CB_Data *cbdata)
328 {
329    Ecore_Con_Info container;
330    Ecore_Con_Info *recv_info;
331    unsigned char *torecv;
332    int torecv_len;
333
334    ssize_t size;
335
336    size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container,
337                sizeof(Ecore_Con_Info));
338    if (size == sizeof(Ecore_Con_Info))
339      {
340         torecv_len = container.size;
341         torecv = malloc(torecv_len);
342
343         memcpy(torecv, &container, sizeof(Ecore_Con_Info));
344
345         size = read(ecore_main_fd_handler_fd_get(cbdata->fdh),
346                     torecv + sizeof(Ecore_Con_Info),
347                     torecv_len - sizeof(Ecore_Con_Info));
348         if ((size > 0) &&
349             ((size_t)size == torecv_len - sizeof(Ecore_Con_Info)))
350           {
351              recv_info = (Ecore_Con_Info *)torecv;
352
353              recv_info->info.ai_addr =
354                (struct sockaddr *)(torecv + sizeof(Ecore_Con_Info));
355              if ((size_t)torecv_len !=
356                  (sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen))
357                recv_info->info.ai_canonname = (char *)
358                  (torecv + sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen);
359              else
360                recv_info->info.ai_canonname = NULL;
361
362              recv_info->info.ai_next = NULL;
363
364              if (cbdata->data)
365                {
366                   cbdata->cb_done(cbdata->data, recv_info);
367                   ecore_con_server_infos_del(cbdata->data, cbdata);
368                }
369
370              free(torecv);
371           }
372         else
373           {
374              if (cbdata->data)
375                {
376                   cbdata->cb_done(cbdata->data, NULL);
377                   ecore_con_server_infos_del(cbdata->data, cbdata);
378                }
379           }
380      }
381    else
382      {
383         if (cbdata->data)
384           {
385              ecore_con_event_server_error(cbdata->data, strerror(errno));
386              cbdata->cb_done(cbdata->data, NULL);
387              ecore_con_server_infos_del(cbdata->data, cbdata);
388           }
389      }
390
391    cbdata->cb_done = NULL;
392 }
393
394 static void
395 _ecore_con_info_slave_free(CB_Data *cbdata)
396 {
397    info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves),
398                                                EINA_INLIST_GET(cbdata));
399    ecore_main_fd_handler_del(cbdata->fdh);
400    ecore_event_handler_del(cbdata->handler);
401    close(ecore_main_fd_handler_fd_get(cbdata->fdh));
402    if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
403    free(cbdata);
404 }
405
406 static Eina_Bool
407 _ecore_con_info_data_handler(void             *data,
408                              Ecore_Fd_Handler *fd_handler)
409 {
410    CB_Data *cbdata;
411
412    cbdata = data;
413    if (cbdata->cb_done)
414      {
415         if (ecore_main_fd_handler_active_get(fd_handler,
416                                              ECORE_FD_READ))
417           _ecore_con_info_readdata(cbdata);
418         else
419           {
420              if (cbdata->data)
421                {
422                   cbdata->cb_done(cbdata->data, NULL);
423                   cbdata->cb_done = NULL;
424                   ecore_con_server_infos_del(cbdata->data, cbdata);
425                }
426           }
427      }
428
429    _ecore_con_info_slave_free(cbdata);
430    return ECORE_CALLBACK_CANCEL;
431 }
432
433 static Eina_Bool
434 _ecore_con_info_exit_handler(void    *data,
435                              int type __UNUSED__,
436                              void    *event)
437 {
438    CB_Data *cbdata;
439    Ecore_Exe_Event_Del *ev;
440
441    ev = event;
442    cbdata = data;
443    if (cbdata->pid != ev->pid)
444      return ECORE_CALLBACK_RENEW;
445
446    return ECORE_CALLBACK_CANCEL; /* FIXME: Woot ??? */
447    _ecore_con_info_slave_free(cbdata);
448    return ECORE_CALLBACK_CANCEL;
449 }
450