aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore_con/ecore_con_ares.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ecore/src/lib/ecore_con/ecore_con_ares.c')
-rw-r--r--libraries/ecore/src/lib/ecore_con/ecore_con_ares.c628
1 files changed, 0 insertions, 628 deletions
diff --git a/libraries/ecore/src/lib/ecore_con/ecore_con_ares.c b/libraries/ecore/src/lib/ecore_con/ecore_con_ares.c
deleted file mode 100644
index 5dfe70b..0000000
--- a/libraries/ecore/src/lib/ecore_con/ecore_con_ares.c
+++ /dev/null
@@ -1,628 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5/*
6 * This version of ecore_con_info use c-ares to provide asynchronous dns lookup.
7 *
8 * Note: It doesn't fork nor does it use libc getaddrinfo.
9 * http://c-ares.haxx.se/docs.html
10 */
11
12#include <string.h>
13#include <sys/types.h>
14
15#ifdef HAVE_NETINET_IN_H
16# include <netinet/in.h>
17#endif
18
19#ifdef HAVE_ARPA_INET_H
20# include <arpa/inet.h>
21#endif
22
23#include <ares.h>
24
25#include "Ecore.h"
26#include "Ecore_Con.h"
27#include "ecore_con_private.h"
28
29typedef struct _Ecore_Con_FD Ecore_Con_FD;
30typedef struct _Ecore_Con_CAres Ecore_Con_CAres;
31
32struct _Ecore_Con_FD
33{
34 Ecore_Fd_Handler *handler;
35 Ecore_Timer *timer;
36 int fd;
37};
38
39struct _Ecore_Con_CAres
40{
41 Ecore_Con_Server *svr;
42 Ecore_Con_Info_Cb done_cb;
43 void *data;
44 struct addrinfo hints;
45 Ecore_Con_Info *result;
46
47 union {
48 struct in_addr v4;
49#ifdef HAVE_IPV6
50 struct in6_addr v6;
51#endif
52 } addr;
53
54 Eina_Bool byaddr : 1;
55 Eina_Bool isv6 : 1;
56};
57
58static ares_channel info_channel;
59static int info_init = 0;
60static Eina_List *info_fds = NULL;
61
62static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
63 int status,
64 int timeouts,
65 char *node,
66 char *service);
67static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
68 int status,
69 int timeouts,
70 struct hostent *hostent);
71static Eina_Bool _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
72 Ecore_Fd_Handler *fd_handler);
73static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data);
74
75static void
76_ecore_con_info_cares_state_cb(void *data,
77 ares_socket_t fd,
78 int readable,
79 int writable);
80static int
81_ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
82 const Ecore_Con_FD *fd2);
83
84int
85ecore_con_info_init(void)
86{
87 struct ares_options opts;
88
89 if (!info_init)
90 {
91 if (ares_library_init(ARES_LIB_INIT_ALL))
92 return 0;
93
94 opts.lookups = "fb"; /* hosts file then dns */
95 opts.sock_state_cb = _ecore_con_info_cares_state_cb;
96
97 if (ares_init_options(&info_channel, &opts,
98 ARES_OPT_LOOKUPS | ARES_OPT_SOCK_STATE_CB) != ARES_SUCCESS)
99 {
100 ares_library_cleanup();
101 return 0;
102 }
103 }
104
105 info_init++;
106 return info_init;
107}
108
109int
110ecore_con_info_shutdown(void)
111{
112 info_init--;
113 if (info_init == 0)
114 {
115 /* Cancel all ongoing request */
116 ares_cancel(info_channel);
117 ares_destroy(info_channel);
118
119 /* Shutdown ares */
120 ares_library_cleanup();
121 }
122
123 return info_init;
124}
125
126int
127ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
128 Ecore_Con_Info_Cb done_cb,
129 void *data)
130{
131 struct addrinfo hints;
132
133 memset(&hints, 0, sizeof(struct addrinfo));
134#ifdef HAVE_IPV6
135 hints.ai_family = AF_INET6;
136#else
137 hints.ai_family = AF_INET;
138#endif
139 hints.ai_socktype = SOCK_STREAM;
140 hints.ai_flags = AI_CANONNAME;
141 hints.ai_protocol = IPPROTO_TCP;
142 hints.ai_canonname = NULL;
143 hints.ai_next = NULL;
144 hints.ai_addr = NULL;
145
146 return ecore_con_info_get(svr, done_cb, data, &hints);
147}
148
149int
150ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
151 Ecore_Con_Info_Cb done_cb,
152 void *data)
153{
154 struct addrinfo hints;
155
156 memset(&hints, 0, sizeof(struct addrinfo));
157#ifdef HAVE_IPV6
158 hints.ai_family = AF_INET6;
159#else
160 hints.ai_family = AF_INET;
161#endif
162 hints.ai_socktype = SOCK_STREAM;
163 hints.ai_flags = AI_PASSIVE;
164 hints.ai_protocol = IPPROTO_TCP;
165 hints.ai_canonname = NULL;
166 hints.ai_next = NULL;
167 hints.ai_addr = NULL;
168
169 return ecore_con_info_get(svr, done_cb, data, &hints);
170}
171
172int
173ecore_con_info_udp_connect(Ecore_Con_Server *svr,
174 Ecore_Con_Info_Cb done_cb,
175 void *data)
176{
177 struct addrinfo hints;
178
179 memset(&hints, 0, sizeof(struct addrinfo));
180#ifdef HAVE_IPV6
181 hints.ai_family = AF_INET6;
182#else
183 hints.ai_family = AF_INET;
184#endif
185 hints.ai_socktype = SOCK_DGRAM;
186 hints.ai_flags = AI_CANONNAME;
187 hints.ai_protocol = IPPROTO_UDP;
188 hints.ai_canonname = NULL;
189 hints.ai_next = NULL;
190 hints.ai_addr = NULL;
191
192 return ecore_con_info_get(svr, done_cb, data, &hints);
193}
194
195int
196ecore_con_info_udp_listen(Ecore_Con_Server *svr,
197 Ecore_Con_Info_Cb done_cb,
198 void *data)
199{
200 struct addrinfo hints;
201
202 memset(&hints, 0, sizeof(struct addrinfo));
203#ifdef HAVE_IPV6
204 hints.ai_family = AF_INET6;
205#else
206 hints.ai_family = AF_INET;
207#endif
208 hints.ai_socktype = SOCK_DGRAM;
209 hints.ai_flags = AI_PASSIVE;
210 hints.ai_protocol = IPPROTO_UDP;
211 hints.ai_canonname = NULL;
212 hints.ai_next = NULL;
213 hints.ai_addr = NULL;
214
215 return ecore_con_info_get(svr, done_cb, data, &hints);
216}
217
218int
219ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
220 Ecore_Con_Info_Cb done_cb,
221 void *data)
222{
223 struct addrinfo hints;
224
225 memset(&hints, 0, sizeof(struct addrinfo));
226#ifdef HAVE_IPV6
227 hints.ai_family = AF_INET6;
228#else
229 hints.ai_family = AF_INET;
230#endif
231 hints.ai_socktype = SOCK_DGRAM;
232 hints.ai_flags = 0;
233 hints.ai_protocol = IPPROTO_UDP;
234 hints.ai_canonname = NULL;
235 hints.ai_next = NULL;
236 hints.ai_addr = NULL;
237
238 return ecore_con_info_get(svr, done_cb, data, &hints);
239}
240
241static Eina_Bool
242_ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
243 int addrtype,
244 const char *name,
245 struct sockaddr *addr,
246 int addrlen)
247{
248 int length = 0;
249
250 if (name)
251 length = strlen(name) + 1;
252 else
253 length = 1;
254
255 arg->result = malloc(sizeof(Ecore_Con_Info) + length);
256 if (!arg->result)
257 return EINA_FALSE;
258
259 /* FIXME: What to do when hint is not set ? */
260 arg->result->info.ai_flags = arg->hints.ai_flags;
261 arg->result->info.ai_socktype = arg->hints.ai_socktype;
262 arg->result->info.ai_protocol = arg->hints.ai_protocol;
263
264 arg->result->info.ai_family = addrtype;
265 arg->result->info.ai_addrlen = addrlen;
266 arg->result->info.ai_addr = addr;
267 arg->result->info.ai_canonname = (char *)(arg->result + 1);
268
269 if (!name)
270 *arg->result->info.ai_canonname = '\0';
271 else
272 strcpy(arg->result->info.ai_canonname, name);
273
274 arg->result->info.ai_next = NULL;
275
276 ares_getnameinfo(
277 info_channel, addr, addrlen,
278 ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST |
279 ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
280 (ares_nameinfo_callback)_ecore_con_info_ares_nameinfo, arg);
281
282 return EINA_TRUE;
283}
284
285EAPI int
286ecore_con_info_get(Ecore_Con_Server *svr,
287 Ecore_Con_Info_Cb done_cb,
288 void *data,
289 struct addrinfo *hints)
290{
291 Ecore_Con_CAres *cares;
292#ifdef HAVE_IPV6
293 int ai_family = AF_INET6;
294#else
295 int ai_family = AF_INET;
296#endif
297
298 cares = calloc(1, sizeof(Ecore_Con_CAres));
299 if (!cares)
300 return 0;
301
302 cares->svr = svr;
303 cares->done_cb = done_cb;
304 cares->data = data;
305
306 if (hints)
307 {
308 ai_family = hints->ai_family;
309 memcpy(&cares->hints, hints, sizeof(struct addrinfo));
310 }
311
312 if (inet_pton(AF_INET, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v4) == 1)
313 {
314 cares->byaddr = EINA_TRUE;
315 cares->isv6 = EINA_FALSE;
316 ares_gethostbyaddr(info_channel, &cares->addr.v4,
317 sizeof(cares->addr.v4),
318 AF_INET,
319 (ares_host_callback)_ecore_con_info_ares_host_cb,
320 cares);
321 }
322#ifdef HAVE_IPV6
323 else if (inet_pton(AF_INET6, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v6) == 1)
324 {
325 cares->byaddr = EINA_TRUE;
326 cares->isv6 = EINA_TRUE;
327 ares_gethostbyaddr(info_channel, &cares->addr.v6,
328 sizeof(cares->addr.v6),
329 AF_INET6,
330 (ares_host_callback)_ecore_con_info_ares_host_cb,
331 cares);
332 }
333#endif
334 else
335 {
336 cares->byaddr = EINA_FALSE;
337 ares_gethostbyname(info_channel, svr->ecs ? svr->ecs->ip : svr->name, ai_family,
338 (ares_host_callback)_ecore_con_info_ares_host_cb,
339 cares);
340 }
341
342 svr->infos = eina_list_append(svr->infos, cares);
343 return 1;
344}
345
346void
347ecore_con_info_data_clear(void *info)
348{
349 Ecore_Con_CAres *cares = info;
350 if (cares) cares->data = NULL;
351}
352
353static Eina_Bool
354_ecore_con_info_cares_timeout_cb(void *data __UNUSED__)
355{
356 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
357 return ECORE_CALLBACK_RENEW;
358}
359
360static Eina_Bool
361_ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
362 Ecore_Fd_Handler *fd_handler)
363{
364 ares_socket_t read_fd, write_fd;
365
366 read_fd = write_fd = ARES_SOCKET_BAD;
367
368 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
369 read_fd = ecf->fd;
370 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
371 write_fd = ecf->fd;
372
373 ares_process_fd(info_channel, read_fd, write_fd);
374
375 return ECORE_CALLBACK_RENEW;
376}
377
378static int
379_ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
380 const Ecore_Con_FD *fd2)
381{
382 return fd1->fd - fd2->fd;
383}
384
385static void
386_ecore_con_info_cares_state_cb(void *data __UNUSED__,
387 ares_socket_t fd,
388 int readable,
389 int writable)
390{
391 int flags = 0;
392 Ecore_Con_FD *search = NULL, *ecf = NULL;
393
394 search = eina_list_search_unsorted(info_fds,
395 (Eina_Compare_Cb)_ecore_con_info_fds_search, &ecf);
396
397 if (!(readable | writable))
398 {
399 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
400 if (search)
401 {
402 info_fds = eina_list_remove(info_fds, search);
403 ecore_timer_del(search->timer);
404 ecore_main_fd_handler_del(search->handler);
405 free(search);
406 }
407 return;
408 }
409
410 if (!search)
411 {
412 search = malloc(sizeof(Ecore_Con_FD));
413 EINA_SAFETY_ON_NULL_RETURN(search);
414
415 search->fd = fd;
416 search->handler = ecore_main_fd_handler_add(fd, ECORE_FD_WRITE | ECORE_FD_READ,
417 (Ecore_Fd_Cb)_ecore_con_info_cares_fd_cb, search, NULL, NULL);
418 /* c-ares default timeout is 5 seconds */
419 search->timer = ecore_timer_add(5, _ecore_con_info_cares_timeout_cb, NULL);
420 info_fds = eina_list_append(info_fds, search);
421 }
422
423 if (readable) flags |= ECORE_FD_READ;
424 if (writable) flags |= ECORE_FD_WRITE;
425 ecore_main_fd_handler_active_set(search->handler, flags);
426}
427
428static void
429_ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
430 int status,
431 int timeouts __UNUSED__,
432 struct hostent *hostent)
433{
434 struct sockaddr *addr;
435 int addrlen;
436
437 /* Found something ? */
438 switch (status)
439 {
440 case ARES_SUCCESS:
441 if (!hostent->h_addr_list[0])
442 {
443 ERR("No IP found");
444 goto on_error;
445 }
446
447 switch (hostent->h_addrtype)
448 {
449 case AF_INET:
450 {
451 struct sockaddr_in *addri;
452
453 addrlen = sizeof(struct sockaddr_in);
454 addri = malloc(addrlen);
455
456 if (!addri)
457 goto on_mem_error;
458
459 addri->sin_family = AF_INET;
460 addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
461
462 memcpy(&addri->sin_addr.s_addr,
463 hostent->h_addr_list[0], sizeof(struct in_addr));
464
465 addr = (struct sockaddr *)addri;
466 break;
467 }
468#ifdef HAVE_IPV6
469 case AF_INET6:
470 {
471 struct sockaddr_in6 *addri6;
472
473 addrlen = sizeof(struct sockaddr_in6);
474 addri6 = malloc(addrlen);
475
476 if (!addri6)
477 goto on_mem_error;
478
479 addri6->sin6_family = AF_INET6;
480 addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
481 addri6->sin6_flowinfo = 0;
482 addri6->sin6_scope_id = 0;
483
484 memcpy(&addri6->sin6_addr.s6_addr,
485 hostent->h_addr_list[0], sizeof(struct in6_addr));
486
487 addr = (struct sockaddr *)addri6;
488 break;
489 }
490#endif
491 default:
492 ERR("Unknown addrtype %i", hostent->h_addrtype);
493 goto on_error;
494 }
495
496 if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype,
497 hostent->h_name,
498 addr, addrlen))
499 goto on_error;
500
501 break;
502
503 case ARES_ENOTFOUND: /* address notfound */
504 if (arg->byaddr)
505 {
506#ifdef HAVE_IPV6
507 /* This happen when host doesn't have a reverse. */
508 if (arg->isv6)
509 {
510 struct sockaddr_in6 *addri6;
511
512 addrlen = sizeof(struct sockaddr_in6);
513 addri6 = malloc(addrlen);
514
515 if (!addri6)
516 goto on_mem_error;
517
518 addri6->sin6_family = AF_INET6;
519 addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
520 addri6->sin6_flowinfo = 0;
521 addri6->sin6_scope_id = 0;
522
523 memcpy(&addri6->sin6_addr.s6_addr,
524 &arg->addr.v6, sizeof(struct in6_addr));
525
526 addr = (struct sockaddr *)addri6;
527 }
528 else
529#endif
530 {
531 struct sockaddr_in *addri;
532
533 addrlen = sizeof(struct sockaddr_in);
534 addri = malloc(addrlen);
535
536 if (!addri)
537 goto on_mem_error;
538
539 addri->sin_family = AF_INET;
540 addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
541
542 memcpy(&addri->sin_addr.s_addr,
543 &arg->addr.v4, sizeof(struct in_addr));
544
545 addr = (struct sockaddr *)addri;
546 }
547
548 if (!_ecore_con_info_ares_getnameinfo(arg,
549#ifdef HAVE_IPV6
550 arg->isv6 ? AF_INET6 :
551#endif
552 AF_INET,
553 NULL, addr,
554 addrlen))
555 goto on_error;
556
557 break;
558 }
559
560 case ARES_ENOTIMP: /* unknown family */
561 case ARES_EBADNAME: /* not a valid internet address */
562 case ARES_ENOMEM: /* not enough memory */
563 case ARES_EDESTRUCTION: /* request canceled, shuting down */
564 case ARES_ENODATA: /* no data returned */
565 case ARES_ECONNREFUSED: /* connection refused */
566 case ARES_ETIMEOUT: /* connection timed out */
567 ecore_con_event_server_error(arg->svr, ares_strerror(status));
568 goto on_error;
569
570 default:
571 ERR("Unknown status returned by c-ares: %i assuming error", status);
572 ecore_con_event_server_error(arg->svr, ares_strerror(status));
573 goto on_error;
574 }
575
576 return;
577
578on_mem_error:
579 ERR("Not enough memory");
580
581on_error:
582 if (arg->data)
583 {
584 ecore_con_server_infos_del(arg->data, arg);
585 arg->done_cb(arg->data, NULL);
586 }
587 free(arg);
588}
589
590static void
591_ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
592 int status,
593 int timeouts __UNUSED__,
594 char *node,
595 char *service)
596{
597 switch (status)
598 {
599 case ARES_SUCCESS:
600 if (node)
601 strcpy(arg->result->ip, node);
602 else
603 *arg->result->ip = '\0';
604
605 if (service)
606 strcpy(arg->result->service, service);
607 else
608 *arg->result->service = '\0';
609
610 if (arg->data) arg->done_cb(arg->data, arg->result);
611 break;
612
613 case ARES_ENOTIMP:
614 case ARES_ENOTFOUND:
615 case ARES_ENOMEM:
616 case ARES_EDESTRUCTION:
617 case ARES_EBADFLAGS:
618 ecore_con_event_server_error(arg->svr, ares_strerror(status));
619 if (arg->data) arg->done_cb(arg->data, NULL);
620 break;
621 }
622
623 free(arg->result->info.ai_addr);
624 free(arg->result);
625 if (arg->data) ecore_con_server_infos_del(arg->data, arg);
626 free(arg);
627}
628