6 * This version of ecore_con_info use c-ares to provide asynchronous dns lookup.
8 * Note: It doesn't fork nor does it use libc getaddrinfo.
9 * http://c-ares.haxx.se/docs.html
13 #include <arpa/inet.h>
17 #include "Ecore_Con.h"
18 #include "ecore_con_private.h"
20 typedef struct _Ecore_Con_FD Ecore_Con_FD;
21 typedef struct _Ecore_Con_CAres Ecore_Con_CAres;
25 Ecore_Fd_Handler *handler;
30 struct _Ecore_Con_CAres
32 Ecore_Con_Server *svr;
33 Ecore_Con_Info_Cb done_cb;
35 struct addrinfo hints;
36 Ecore_Con_Info *result;
47 static ares_channel info_channel;
48 static int info_init = 0;
49 static Eina_List *info_fds = NULL;
50 static int active = 0;
51 static Ecore_Timer *tm = NULL;
52 static fd_set info_readers, info_writers;
54 static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
59 static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
62 struct hostent *hostent);
63 static Eina_Bool _ecore_con_info_cares_fd_cb(void *data,
64 Ecore_Fd_Handler *fd_handler);
65 static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data);
66 static void _ecore_con_info_cares_clean(void);
69 ecore_con_info_init(void)
73 if (ares_library_init(ARES_LIB_INIT_ALL) != 0)
76 if (ares_init(&info_channel) != ARES_SUCCESS)
78 ares_library_cleanup();
88 ecore_con_info_shutdown(void)
93 /* Cancel all ongoing request */
94 ares_cancel(info_channel);
95 ares_destroy(info_channel);
97 /* Destroy FD handler here. */
99 ares_library_cleanup();
106 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
107 Ecore_Con_Info_Cb done_cb,
110 struct addrinfo hints;
112 memset(&hints, 0, sizeof(struct addrinfo));
113 hints.ai_family = AF_INET6;
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;
121 return ecore_con_info_get(svr, done_cb, data, &hints);
125 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
126 Ecore_Con_Info_Cb done_cb,
129 struct addrinfo hints;
131 memset(&hints, 0, sizeof(struct addrinfo));
132 hints.ai_family = AF_INET6;
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;
140 return ecore_con_info_get(svr, done_cb, data, &hints);
144 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
145 Ecore_Con_Info_Cb done_cb,
148 struct addrinfo hints;
150 memset(&hints, 0, sizeof(struct addrinfo));
151 hints.ai_family = AF_INET6;
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;
159 return ecore_con_info_get(svr, done_cb, data, &hints);
163 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
164 Ecore_Con_Info_Cb done_cb,
167 struct addrinfo hints;
169 memset(&hints, 0, sizeof(struct addrinfo));
170 hints.ai_family = AF_INET6;
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;
178 return ecore_con_info_get(svr, done_cb, data, &hints);
182 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
183 Ecore_Con_Info_Cb done_cb,
186 struct addrinfo hints;
188 memset(&hints, 0, sizeof(struct addrinfo));
189 hints.ai_family = AF_INET6;
190 hints.ai_socktype = SOCK_DGRAM;
192 hints.ai_protocol = IPPROTO_UDP;
193 hints.ai_canonname = NULL;
194 hints.ai_next = NULL;
195 hints.ai_addr = NULL;
197 return ecore_con_info_get(svr, done_cb, data, &hints);
201 _ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
204 struct sockaddr *addr,
210 length = strlen(name) + 1;
214 arg->result = malloc(sizeof(Ecore_Con_Info) + length);
218 /* FIXME: What to do when hint is not set ? */
219 arg->result->info.ai_flags = arg->hints.ai_flags;
220 arg->result->info.ai_socktype = arg->hints.ai_socktype;
221 arg->result->info.ai_protocol = arg->hints.ai_protocol;
223 arg->result->info.ai_family = addrtype;
224 arg->result->info.ai_addrlen = addrlen;
225 arg->result->info.ai_addr = addr;
226 arg->result->info.ai_canonname = (char *)(arg->result + 1);
229 *arg->result->info.ai_canonname = '\0';
231 strcpy(arg->result->info.ai_canonname, name);
233 arg->result->info.ai_next = NULL;
236 info_channel, addr, addrlen,
237 ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST |
238 ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
239 (ares_nameinfo_callback)_ecore_con_info_ares_nameinfo, arg);
245 ecore_con_info_get(Ecore_Con_Server *svr,
246 Ecore_Con_Info_Cb done_cb,
248 struct addrinfo *hints)
250 Ecore_Con_CAres *cares;
251 int ai_family = AF_INET6;
253 cares = calloc(1, sizeof(Ecore_Con_CAres));
258 cares->done_cb = done_cb;
263 ai_family = hints->ai_family;
264 memcpy(&cares->hints, hints, sizeof(struct addrinfo));
267 if (inet_pton(AF_INET, svr->name, &cares->addr.v4) == 1)
269 cares->byaddr = EINA_TRUE;
270 cares->isv6 = EINA_FALSE;
271 ares_gethostbyaddr(info_channel, &cares->addr.v4,
272 sizeof(cares->addr.v4),
274 (ares_host_callback)_ecore_con_info_ares_host_cb,
277 else if (inet_pton(AF_INET6, svr->name, &cares->addr.v6) == 1)
279 cares->byaddr = EINA_TRUE;
280 cares->isv6 = EINA_TRUE;
281 ares_gethostbyaddr(info_channel, &cares->addr.v6,
282 sizeof(cares->addr.v6),
284 (ares_host_callback)_ecore_con_info_ares_host_cb,
289 cares->byaddr = EINA_FALSE;
290 ares_gethostbyname(info_channel, svr->name, ai_family,
291 (ares_host_callback)_ecore_con_info_ares_host_cb,
295 _ecore_con_info_cares_clean();
301 _ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
302 const Ecore_Con_FD *fd2)
304 return fd1->fd - fd2->fd;
308 _ecore_con_info_fds_lookup(int fd)
311 Ecore_Con_FD *search;
315 search = eina_list_search_unsorted(
316 info_fds, (Eina_Compare_Cb)_ecore_con_info_fds_search, &fdl);
320 search->active = active;
328 _ecore_con_info_cares_clean(void)
330 fd_set readers, writers;
331 Eina_List *l, *l_next;
338 nfds = ares_fds(info_channel, &readers, &writers);
341 for (i = 0; i < nfds; ++i)
345 if (FD_ISSET(i, &readers))
346 flags |= ECORE_FD_READ;
348 if (FD_ISSET(i, &writers))
349 flags |= ECORE_FD_WRITE;
351 if (flags && (!_ecore_con_info_fds_lookup(i)))
353 ecf = malloc(sizeof(Ecore_Con_FD));
357 ecf->active = active;
358 ecf->handler = ecore_main_fd_handler_add(
359 i, ECORE_FD_WRITE | ECORE_FD_READ,
360 _ecore_con_info_cares_fd_cb,
362 info_fds = eina_list_append(info_fds, ecf);
367 info_readers = readers;
368 info_writers = writers;
370 EINA_LIST_FOREACH_SAFE(info_fds, l, l_next, ecf)
372 if (ecf->active != active)
374 if (ecf->handler) ecore_main_fd_handler_del(ecf->handler);
376 info_fds = eina_list_remove_list(info_fds, l);
391 ares_timeout(info_channel, NULL, &tv);
394 ecore_timer_delay(tm, tv.tv_sec);
397 ecore_timer_add((double)tv.tv_sec,
398 _ecore_con_info_cares_timeout_cb,
404 _ecore_con_info_cares_timeout_cb(void *data __UNUSED__)
406 ares_process(info_channel, &info_readers, &info_writers);
407 _ecore_con_info_cares_clean();
409 return ECORE_CALLBACK_RENEW;
413 _ecore_con_info_cares_fd_cb(void *data __UNUSED__,
414 Ecore_Fd_Handler *fd_handler __UNUSED__)
416 ares_process(info_channel, &info_readers, &info_writers);
417 _ecore_con_info_cares_clean();
419 return ECORE_CALLBACK_RENEW;
423 _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
425 int timeouts __UNUSED__,
426 struct hostent *hostent)
428 struct sockaddr *addr;
431 /* Found something ? */
435 if (!hostent->h_addr_list[0])
441 switch (hostent->h_addrtype)
445 struct sockaddr_in *addri;
447 addrlen = sizeof(struct sockaddr_in);
448 addri = malloc(addrlen);
453 addri->sin_family = AF_INET;
454 addri->sin_port = htons(arg->svr->port);
456 memcpy(&addri->sin_addr.s_addr,
457 hostent->h_addr_list[0], sizeof(struct in_addr));
459 addr = (struct sockaddr *)addri;
465 struct sockaddr_in6 *addri6;
467 addrlen = sizeof(struct sockaddr_in6);
468 addri6 = malloc(addrlen);
473 addri6->sin6_family = AF_INET6;
474 addri6->sin6_port = htons(arg->svr->port);
475 addri6->sin6_flowinfo = 0;
476 addri6->sin6_scope_id = 0;
478 memcpy(&addri6->sin6_addr.s6_addr,
479 hostent->h_addr_list[0], sizeof(struct in6_addr));
481 addr = (struct sockaddr *)addri6;
486 ERR("Unknown addrtype %i", hostent->h_addrtype);
490 if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype,
497 case ARES_ENOTFOUND: /* address notfound */
500 /* This happen when host doesn't have a reverse. */
503 struct sockaddr_in6 *addri6;
505 addrlen = sizeof(struct sockaddr_in6);
506 addri6 = malloc(addrlen);
511 addri6->sin6_family = AF_INET6;
512 addri6->sin6_port = htons(arg->svr->port);
513 addri6->sin6_flowinfo = 0;
514 addri6->sin6_scope_id = 0;
516 memcpy(&addri6->sin6_addr.s6_addr,
517 &arg->addr.v6, sizeof(struct in6_addr));
519 addr = (struct sockaddr *)addri6;
523 struct sockaddr_in *addri;
525 addrlen = sizeof(struct sockaddr_in);
526 addri = malloc(addrlen);
531 addri->sin_family = AF_INET;
532 addri->sin_port = htons(arg->svr->port);
534 memcpy(&addri->sin_addr.s_addr,
535 &arg->addr.v4, sizeof(struct in_addr));
537 addr = (struct sockaddr *)addri;
540 if (!_ecore_con_info_ares_getnameinfo(arg,
541 arg->isv6 ? AF_INET6 :
550 case ARES_ENOTIMP: /* unknown family */
551 case ARES_EBADNAME: /* not a valid internet address */
552 case ARES_ENOMEM: /* not enough memory */
553 case ARES_EDESTRUCTION: /* request canceled, shuting down */
554 case ARES_ENODATA: /* no data returned */
558 ERR("Unknown status returned by c-ares: %i assuming error",
566 ERR("Not enough memory");
569 arg->done_cb(arg->data, NULL);
574 _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
576 int timeouts __UNUSED__,
584 strcpy(arg->result->ip, node);
586 *arg->result->ip = '\0';
589 strcpy(arg->result->service, service);
591 *arg->result->service = '\0';
593 arg->done_cb(arg->data, arg->result);
599 case ARES_EDESTRUCTION:
601 arg->done_cb(arg->data, NULL);
605 free(arg->result->info.ai_addr);