svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore_con / ecore_con_info.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 /*
6  * getaddrinfo with callback
7  *
8  * man getaddrinfo
9  *
10  */
11
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15
16 #ifdef HAVE_ALLOCA_H
17 # include <alloca.h>
18 #elif defined __GNUC__
19 # define alloca __builtin_alloca
20 #elif defined _AIX
21 # define alloca __alloca
22 #elif defined _MSC_VER
23 # include <malloc.h>
24 # define alloca _alloca
25 #else
26 # include <stddef.h>
27 # ifdef  __cplusplus
28 extern "C"
29 # endif
30 void *alloca (size_t);
31 #endif
32
33 #include <string.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #ifdef __OpenBSD__
38 # include <sys/types.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_NETINET_IN_H
50 # include <netinet/in.h>
51 #endif
52
53 #ifdef HAVE_SYS_SOCKET_H
54 # include <sys/socket.h>
55 #endif
56
57 #ifdef HAVE_NETDB_H
58 # include <netdb.h>
59 #endif
60
61 #include "Ecore.h"
62 #include "ecore_private.h"
63 #include "ecore_con_private.h"
64
65 typedef struct _CB_Data CB_Data;
66
67 struct _CB_Data
68 {
69    EINA_INLIST;
70    Ecore_Con_Info_Cb cb_done;
71    void *data;
72    Ecore_Fd_Handler *fdh;
73    pid_t pid;
74    Ecore_Event_Handler *handler;
75    int fd2;
76 };
77
78
79 static void _ecore_con_info_readdata(CB_Data *cbdata);
80 static void _ecore_con_info_slave_free(CB_Data *cbdata);
81 static int _ecore_con_info_data_handler(void *data, Ecore_Fd_Handler *fd_handler);
82 static int _ecore_con_info_exit_handler(void *data, int type __UNUSED__, 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      {
100         while (info_slaves) _ecore_con_info_slave_free(info_slaves);
101      }
102    return info_init;
103 }
104
105 int
106 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
107                            Ecore_Con_Info_Cb done_cb,
108                            void *data)
109 {
110    struct addrinfo hints;
111
112    memset(&hints, 0, sizeof(struct addrinfo));
113    hints.ai_family = AF_UNSPEC;
114    hints.ai_socktype = SOCK_STREAM;
115    hints.ai_flags = AI_CANONNAME;
116    hints.ai_protocol = IPPROTO_TCP;
117    hints.ai_canonname = NULL;
118    hints.ai_next = NULL;
119    hints.ai_addr = NULL;
120
121    return ecore_con_info_get(svr, done_cb, data, &hints);
122 }
123
124 int
125 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
126                           Ecore_Con_Info_Cb done_cb,
127                           void *data)
128 {
129    struct addrinfo hints;
130
131    memset(&hints, 0, sizeof(struct addrinfo));
132    hints.ai_family = AF_UNSPEC;
133    hints.ai_socktype = SOCK_STREAM;
134    hints.ai_flags = AI_PASSIVE;
135    hints.ai_protocol = IPPROTO_TCP;
136    hints.ai_canonname = NULL;
137    hints.ai_next = NULL;
138    hints.ai_addr = NULL;
139
140    return ecore_con_info_get(svr, done_cb, data, &hints);
141 }
142
143 int
144 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
145                            Ecore_Con_Info_Cb done_cb,
146                            void *data)
147 {
148    struct addrinfo hints;
149
150    memset(&hints, 0, sizeof(struct addrinfo));
151    hints.ai_family = AF_UNSPEC;
152    hints.ai_socktype = SOCK_DGRAM;
153    hints.ai_flags = AI_CANONNAME;
154    hints.ai_protocol = IPPROTO_UDP;
155    hints.ai_canonname = NULL;
156    hints.ai_next = NULL;
157    hints.ai_addr = NULL;
158
159    return ecore_con_info_get(svr, done_cb, data, &hints);
160 }
161
162 int
163 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
164                           Ecore_Con_Info_Cb done_cb,
165                           void *data)
166 {
167    struct addrinfo hints;
168
169    memset(&hints, 0, sizeof(struct addrinfo));
170    hints.ai_family = AF_UNSPEC;
171    hints.ai_socktype = SOCK_DGRAM;
172    hints.ai_flags = AI_PASSIVE;
173    hints.ai_protocol = IPPROTO_UDP;
174    hints.ai_canonname = NULL;
175    hints.ai_next = NULL;
176    hints.ai_addr = NULL;
177
178    return ecore_con_info_get(svr, done_cb, data, &hints);
179 }
180
181 int
182 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
183                            Ecore_Con_Info_Cb done_cb,
184                            void *data)
185 {
186    struct addrinfo hints;
187
188    memset(&hints, 0, sizeof(struct addrinfo));
189    hints.ai_family = AF_UNSPEC;
190    hints.ai_socktype = SOCK_DGRAM;
191    hints.ai_flags = 0;
192    hints.ai_protocol = IPPROTO_UDP;
193    hints.ai_canonname = NULL;
194    hints.ai_next = NULL;
195    hints.ai_addr = NULL;
196
197    return ecore_con_info_get(svr, done_cb, data, &hints);
198 }
199
200 EAPI int
201 ecore_con_info_get(Ecore_Con_Server *svr,
202                    Ecore_Con_Info_Cb done_cb,
203                    void *data,
204                    struct addrinfo *hints)
205 {
206    CB_Data *cbdata;
207    int fd[2];
208
209    if (pipe(fd) < 0) return 0;
210    cbdata = calloc(1, sizeof(CB_Data));
211    if (!cbdata)
212      {
213         close(fd[0]);
214         close(fd[1]);
215         return 0;
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];
236         char hbuf[NI_MAXHOST];
237         char sbuf[NI_MAXSERV];
238         void *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             tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen + canonname_len;
250
251             if (!(tosend = alloca(tosend_len)))
252               goto on_error;
253
254             container = (Ecore_Con_Info *)tosend;
255
256             container->size = tosend_len;
257
258             memcpy(&container->info, result, sizeof(struct addrinfo));
259             memcpy((char *)tosend + sizeof(Ecore_Con_Info), result->ai_addr, result->ai_addrlen);
260             memcpy((char *)tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen, result->ai_canonname, canonname_len);
261
262             if (!getnameinfo(result->ai_addr, result->ai_addrlen,
263                              hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
264                              NI_NUMERICHOST | NI_NUMERICSERV))
265               {
266                 memcpy(container->ip, hbuf, sizeof(container->ip));
267                 memcpy(container->service, sbuf, sizeof(container->service));
268               }
269             err = write(fd[1], tosend, tosend_len);
270           }
271
272 on_error:
273         if (result)
274           freeaddrinfo(result);
275         err = write(fd[1], "", 1);
276         close(fd[1]);
277 # ifdef __USE_ISOC99
278         _Exit(0);
279 # else
280         _exit(0);
281 # endif
282      }
283    /* PARENT */
284    cbdata->handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler, cbdata);
285    close(fd[1]);
286    if (!cbdata->handler)
287      {
288         ecore_main_fd_handler_del(cbdata->fdh);
289         free(cbdata);
290         close(fd[0]);
291         return 0;
292      }
293    info_slaves = (CB_Data *) eina_inlist_append(EINA_INLIST_GET(info_slaves), EINA_INLIST_GET(cbdata));
294    return 1;
295 }
296
297 static void
298 _ecore_con_info_readdata(CB_Data *cbdata)
299 {
300    Ecore_Con_Info container;
301    Ecore_Con_Info *recv;
302    void *torecv;
303    int torecv_len;
304
305    ssize_t size;
306
307    size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container,
308                sizeof(Ecore_Con_Info));
309    if (size == sizeof(Ecore_Con_Info))
310      {
311         torecv_len = container.size;
312         torecv = malloc(torecv_len);
313
314         memcpy(torecv, &container, sizeof(Ecore_Con_Info));
315
316         size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), (char *)torecv + sizeof(Ecore_Con_Info),
317                     torecv_len - sizeof(Ecore_Con_Info));
318         if ((size > 0) && ((size_t)size == torecv_len - sizeof(Ecore_Con_Info)))
319           {
320             recv = (Ecore_Con_Info *)torecv;
321
322             recv->info.ai_addr = (struct sockaddr *)((char *)torecv + sizeof(Ecore_Con_Info));
323             if ((size_t)torecv_len != (sizeof(Ecore_Con_Info) + recv->info.ai_addrlen))
324               recv->info.ai_canonname = (char *)torecv + sizeof(Ecore_Con_Info) + recv->info.ai_addrlen;
325             else
326               recv->info.ai_canonname = NULL;
327             recv->info.ai_next = NULL;
328
329             cbdata->cb_done(cbdata->data, recv);
330
331             free(torecv);
332           }
333         else
334           cbdata->cb_done(cbdata->data, NULL);
335      }
336    else
337      cbdata->cb_done(cbdata->data, NULL);
338    cbdata->cb_done = NULL;
339 }
340
341 static void
342 _ecore_con_info_slave_free(CB_Data *cbdata)
343 {
344    info_slaves = (CB_Data *) eina_inlist_remove(EINA_INLIST_GET(info_slaves), EINA_INLIST_GET(cbdata));
345    close(ecore_main_fd_handler_fd_get(cbdata->fdh));
346    ecore_main_fd_handler_del(cbdata->fdh);
347    ecore_event_handler_del(cbdata->handler);
348    free(cbdata);
349 }
350
351 static int
352 _ecore_con_info_data_handler(void *data, Ecore_Fd_Handler *fd_handler)
353 {
354    CB_Data *cbdata;
355
356    cbdata = data;
357    if (cbdata->cb_done)
358      {
359         if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
360           _ecore_con_info_readdata(cbdata);
361         else
362           {
363              cbdata->cb_done(cbdata->data, NULL);
364              cbdata->cb_done = NULL;
365           }
366      }
367    _ecore_con_info_slave_free(cbdata);
368    return 0;
369 }
370
371 static int
372 _ecore_con_info_exit_handler(void *data, int type __UNUSED__, void *event)
373 {
374    CB_Data *cbdata;
375    Ecore_Exe_Event_Del *ev;
376
377    ev = event;
378    cbdata = data;
379    if (cbdata->pid != ev->pid) return 1;
380    return 0;
381    _ecore_con_info_slave_free(cbdata);
382    return 0;
383 }