diff options
Diffstat (limited to 'libraries/ecore/src/lib/ecore_con/ecore_con_info.c')
-rw-r--r-- | libraries/ecore/src/lib/ecore_con/ecore_con_info.c | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_con/ecore_con_info.c b/libraries/ecore/src/lib/ecore_con/ecore_con_info.c new file mode 100644 index 0000000..4ece6b0 --- /dev/null +++ b/libraries/ecore/src/lib/ecore_con/ecore_con_info.c | |||
@@ -0,0 +1,450 @@ | |||
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 | 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 | #if defined(__USE_ISOC99) && !defined(__UCLIBC__) | ||
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 | |||