edb8b63773e48362f7a48b4a7a9f05803678ce7b
[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 "Ecore.h"
58 #include "ecore_private.h"
59 #include "ecore_con_private.h"
60
61 typedef struct _CB_Data CB_Data;
62
63 struct _CB_Data
64 {
65    EINA_INLIST;
66    Ecore_Con_Info_Cb cb_done;
67    void *data;
68    Ecore_Fd_Handler *fdh;
69    pid_t pid;
70    Ecore_Event_Handler *handler;
71    int fd2;
72 };
73
74
75 static void      _ecore_con_info_readdata(CB_Data *cbdata);
76 static void      _ecore_con_info_slave_free(CB_Data *cbdata);
77 static Eina_Bool _ecore_con_info_data_handler(void *data,
78                                               Ecore_Fd_Handler *fd_handler);
79 static Eina_Bool _ecore_con_info_exit_handler(void *data, int type __UNUSED__,
80                                               void *event);
81
82 static int info_init = 0;
83 static CB_Data *info_slaves = NULL;
84
85 int
86 ecore_con_info_init(void)
87 {
88    info_init++;
89    return info_init;
90 }
91
92 int
93 ecore_con_info_shutdown(void)
94 {
95    info_init--;
96    if (info_init == 0)
97       while (info_slaves) _ecore_con_info_slave_free(info_slaves);
98
99    return info_init;
100 }
101
102 int
103 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
104                            Ecore_Con_Info_Cb done_cb,
105                            void *data)
106 {
107    struct addrinfo hints;
108
109    memset(&hints, 0, sizeof(struct addrinfo));
110    hints.ai_family = AF_UNSPEC;
111    hints.ai_socktype = SOCK_STREAM;
112    hints.ai_flags = AI_CANONNAME;
113    hints.ai_protocol = IPPROTO_TCP;
114    hints.ai_canonname = NULL;
115    hints.ai_next = NULL;
116    hints.ai_addr = NULL;
117
118    return ecore_con_info_get(svr, done_cb, data, &hints);
119 }
120
121 int
122 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
123                           Ecore_Con_Info_Cb done_cb,
124                           void *data)
125 {
126    struct addrinfo hints;
127
128    memset(&hints, 0, sizeof(struct addrinfo));
129    hints.ai_family = AF_UNSPEC;
130    hints.ai_socktype = SOCK_STREAM;
131    hints.ai_flags = AI_PASSIVE;
132    hints.ai_protocol = IPPROTO_TCP;
133    hints.ai_canonname = NULL;
134    hints.ai_next = NULL;
135    hints.ai_addr = NULL;
136
137    return ecore_con_info_get(svr, done_cb, data, &hints);
138 }
139
140 int
141 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
142                            Ecore_Con_Info_Cb done_cb,
143                            void *data)
144 {
145    struct addrinfo hints;
146
147    memset(&hints, 0, sizeof(struct addrinfo));
148    hints.ai_family = AF_UNSPEC;
149    hints.ai_socktype = SOCK_DGRAM;
150    hints.ai_flags = AI_CANONNAME;
151    hints.ai_protocol = IPPROTO_UDP;
152    hints.ai_canonname = NULL;
153    hints.ai_next = NULL;
154    hints.ai_addr = NULL;
155
156    return ecore_con_info_get(svr, done_cb, data, &hints);
157 }
158
159 int
160 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
161                           Ecore_Con_Info_Cb done_cb,
162                           void *data)
163 {
164    struct addrinfo hints;
165
166    memset(&hints, 0, sizeof(struct addrinfo));
167    hints.ai_family = AF_UNSPEC;
168    hints.ai_socktype = SOCK_DGRAM;
169    hints.ai_flags = AI_PASSIVE;
170    hints.ai_protocol = IPPROTO_UDP;
171    hints.ai_canonname = NULL;
172    hints.ai_next = NULL;
173    hints.ai_addr = NULL;
174
175    return ecore_con_info_get(svr, done_cb, data, &hints);
176 }
177
178 int
179 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
180                             Ecore_Con_Info_Cb done_cb,
181                             void *data)
182 {
183    struct addrinfo hints;
184
185    memset(&hints, 0, sizeof(struct addrinfo));
186    hints.ai_family = AF_UNSPEC;
187    hints.ai_socktype = SOCK_DGRAM;
188    hints.ai_flags = 0;
189    hints.ai_protocol = IPPROTO_UDP;
190    hints.ai_canonname = NULL;
191    hints.ai_next = NULL;
192    hints.ai_addr = NULL;
193
194    return ecore_con_info_get(svr, done_cb, data, &hints);
195 }
196
197 EAPI int
198 ecore_con_info_get(Ecore_Con_Server *svr,
199                    Ecore_Con_Info_Cb done_cb,
200                    void *data,
201                    struct addrinfo *hints)
202 {
203    CB_Data *cbdata;
204    int fd[2];
205
206    if (pipe(fd) < 0)
207       return 0;
208
209    cbdata = calloc(1, sizeof(CB_Data));
210    if (!cbdata)
211      {
212         close(fd[0]);
213         close(fd[1]);
214         return 0;
215      }
216
217    cbdata->cb_done = done_cb;
218    cbdata->data = data;
219    cbdata->fd2 = fd[1];
220    if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ,
221                                                  _ecore_con_info_data_handler,
222                                                  cbdata,
223                                                  NULL, NULL)))
224      {
225         free(cbdata);
226         close(fd[0]);
227         close(fd[1]);
228         return 0;
229      }
230
231    if ((cbdata->pid = fork()) == 0)
232      {
233         Ecore_Con_Info *container;
234         struct addrinfo *result = NULL;
235         char service[NI_MAXSERV] = {0};
236         char hbuf[NI_MAXHOST] = {0};
237         char sbuf[NI_MAXSERV] = {0};
238         unsigned char *tosend = NULL;
239         int tosend_len;
240         int canonname_len = 0;
241         int err;
242
243         eina_convert_itoa(svr->port, service);
244         /* CHILD */
245         if (!getaddrinfo(svr->name, service, hints, &result) && result)
246           {
247              if (result->ai_canonname)
248                 canonname_len = strlen(result->ai_canonname) + 1;
249              
250              tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen +
251                 canonname_len;
252              
253              if (!(tosend = alloca(tosend_len))) goto on_error;
254              memset(tosend, 0, tosend_len);
255              
256              container = (Ecore_Con_Info *)tosend;
257              container->size = tosend_len;
258              
259              memcpy(&container->info,
260                     result,
261                     sizeof(struct addrinfo));
262              memcpy(tosend + sizeof(Ecore_Con_Info),
263                     result->ai_addr,
264                     result->ai_addrlen);
265              memcpy(tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen,
266                     result->ai_canonname,
267                     canonname_len);
268              
269              if (!getnameinfo(result->ai_addr, result->ai_addrlen,
270                               hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
271                               NI_NUMERICHOST | NI_NUMERICSERV))
272                {
273                   memcpy(container->ip,      hbuf, sizeof(container->ip));
274                   memcpy(container->service, sbuf, sizeof(container->service));
275                }
276              
277              err = write(fd[1], tosend, tosend_len);
278           }
279
280 on_error:
281         if (result)
282            freeaddrinfo(result);
283         
284         err = write(fd[1], "", 1);
285         close(fd[1]);
286 #ifdef __USE_ISOC99
287         _Exit(0);
288 #else
289         _exit(0);
290 #endif
291      }
292    
293    /* PARENT */
294    cbdata->handler =
295       ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler,
296                               cbdata);
297    close(fd[1]);
298    if (!cbdata->handler)
299      {
300         ecore_main_fd_handler_del(cbdata->fdh);
301         free(cbdata);
302         close(fd[0]);
303         return 0;
304      }
305    
306    info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(
307                                                                info_slaves),
308                                                EINA_INLIST_GET(cbdata));
309    return 1;
310 }
311
312 static void
313 _ecore_con_info_readdata(CB_Data *cbdata)
314 {
315    Ecore_Con_Info container;
316    Ecore_Con_Info *recv;
317    unsigned char *torecv;
318    int torecv_len;
319
320    ssize_t size;
321
322    size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container,
323                sizeof(Ecore_Con_Info));
324    if (size == sizeof(Ecore_Con_Info))
325      {
326         torecv_len = container.size;
327         torecv = malloc(torecv_len);
328         
329         memcpy(torecv, &container, sizeof(Ecore_Con_Info));
330         
331         size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), 
332                     torecv + sizeof(Ecore_Con_Info),
333                     torecv_len - sizeof(Ecore_Con_Info));
334         if ((size > 0) && 
335             ((size_t)size == torecv_len - sizeof(Ecore_Con_Info)))
336           {
337              recv = (Ecore_Con_Info *)torecv;
338
339              recv->info.ai_addr =
340                 (struct sockaddr *)(torecv + sizeof(Ecore_Con_Info));
341              if ((size_t)torecv_len !=
342                  (sizeof(Ecore_Con_Info) + recv->info.ai_addrlen))
343                 recv->info.ai_canonname =
344                 torecv + sizeof(Ecore_Con_Info) + recv->info.ai_addrlen;
345              else
346                 recv->info.ai_canonname = NULL;
347              
348              recv->info.ai_next = NULL;
349              
350              cbdata->cb_done(cbdata->data, recv);
351              
352              free(torecv);
353           }
354         else
355            cbdata->cb_done(cbdata->data, NULL);
356      }
357    else
358       cbdata->cb_done(cbdata->data, NULL);
359    
360    cbdata->cb_done = NULL;
361 }
362
363 static void
364 _ecore_con_info_slave_free(CB_Data *cbdata)
365 {
366    info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves),
367                                                EINA_INLIST_GET(cbdata));
368    ecore_main_fd_handler_del(cbdata->fdh);
369    close(ecore_main_fd_handler_fd_get(cbdata->fdh));
370    ecore_event_handler_del(cbdata->handler);
371    free(cbdata);
372 }
373
374 static Eina_Bool
375 _ecore_con_info_data_handler(void *data, Ecore_Fd_Handler *fd_handler)
376 {
377    CB_Data *cbdata;
378
379    cbdata = data;
380    if (cbdata->cb_done)
381      {
382         if (ecore_main_fd_handler_active_get(fd_handler,
383                                              ECORE_FD_READ))
384            _ecore_con_info_readdata(cbdata);
385         else
386           {
387              cbdata->cb_done(cbdata->data, NULL);
388              cbdata->cb_done = NULL;
389           }
390      }
391
392    _ecore_con_info_slave_free(cbdata);
393    return ECORE_CALLBACK_CANCEL;
394 }
395
396 static Eina_Bool
397 _ecore_con_info_exit_handler(void *data, int type __UNUSED__, void *event)
398 {
399    CB_Data *cbdata;
400    Ecore_Exe_Event_Del *ev;
401
402    ev = event;
403    cbdata = data;
404    if (cbdata->pid != ev->pid)
405       return ECORE_CALLBACK_RENEW;
406
407    return ECORE_CALLBACK_CANCEL; /* FIXME: Woot ??? */
408    _ecore_con_info_slave_free(cbdata);
409    return ECORE_CALLBACK_CANCEL;
410 }