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 <sys/types.h>
15 #ifdef HAVE_NETINET_IN_H
16 # include <netinet/in.h>
19 #ifdef HAVE_ARPA_INET_H
20 # include <arpa/inet.h>
26 #include "Ecore_Con.h"
27 #include "ecore_con_private.h"
29 typedef struct _Ecore_Con_FD Ecore_Con_FD;
30 typedef struct _Ecore_Con_CAres Ecore_Con_CAres;
34 Ecore_Fd_Handler *handler;
39 struct _Ecore_Con_CAres
41 Ecore_Con_Server *svr;
42 Ecore_Con_Info_Cb done_cb;
44 struct addrinfo hints;
45 Ecore_Con_Info *result;
58 static ares_channel info_channel;
59 static int info_init = 0;
60 static Eina_List *info_fds = NULL;
62 static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
67 static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
70 struct hostent *hostent);
71 static Eina_Bool _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
72 Ecore_Fd_Handler *fd_handler);
73 static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data);
76 _ecore_con_info_cares_state_cb(void *data,
81 _ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
82 const Ecore_Con_FD *fd2);
85 ecore_con_info_init(void)
87 struct ares_options opts;
91 if (ares_library_init(ARES_LIB_INIT_ALL))
94 opts.lookups = "fb"; /* hosts file then dns */
95 opts.sock_state_cb = _ecore_con_info_cares_state_cb;
97 if (ares_init_options(&info_channel, &opts,
98 ARES_OPT_LOOKUPS | ARES_OPT_SOCK_STATE_CB) != ARES_SUCCESS)
100 ares_library_cleanup();
110 ecore_con_info_shutdown(void)
115 /* Cancel all ongoing request */
116 ares_cancel(info_channel);
117 ares_destroy(info_channel);
120 ares_library_cleanup();
127 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
128 Ecore_Con_Info_Cb done_cb,
131 struct addrinfo hints;
133 memset(&hints, 0, sizeof(struct addrinfo));
135 hints.ai_family = AF_INET6;
137 hints.ai_family = AF_INET;
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;
146 return ecore_con_info_get(svr, done_cb, data, &hints);
150 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
151 Ecore_Con_Info_Cb done_cb,
154 struct addrinfo hints;
156 memset(&hints, 0, sizeof(struct addrinfo));
158 hints.ai_family = AF_INET6;
160 hints.ai_family = AF_INET;
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;
169 return ecore_con_info_get(svr, done_cb, data, &hints);
173 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
174 Ecore_Con_Info_Cb done_cb,
177 struct addrinfo hints;
179 memset(&hints, 0, sizeof(struct addrinfo));
181 hints.ai_family = AF_INET6;
183 hints.ai_family = AF_INET;
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;
192 return ecore_con_info_get(svr, done_cb, data, &hints);
196 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
197 Ecore_Con_Info_Cb done_cb,
200 struct addrinfo hints;
202 memset(&hints, 0, sizeof(struct addrinfo));
204 hints.ai_family = AF_INET6;
206 hints.ai_family = AF_INET;
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;
215 return ecore_con_info_get(svr, done_cb, data, &hints);
219 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
220 Ecore_Con_Info_Cb done_cb,
223 struct addrinfo hints;
225 memset(&hints, 0, sizeof(struct addrinfo));
227 hints.ai_family = AF_INET6;
229 hints.ai_family = AF_INET;
231 hints.ai_socktype = SOCK_DGRAM;
233 hints.ai_protocol = IPPROTO_UDP;
234 hints.ai_canonname = NULL;
235 hints.ai_next = NULL;
236 hints.ai_addr = NULL;
238 return ecore_con_info_get(svr, done_cb, data, &hints);
242 _ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
245 struct sockaddr *addr,
251 length = strlen(name) + 1;
255 arg->result = malloc(sizeof(Ecore_Con_Info) + length);
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;
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);
270 *arg->result->info.ai_canonname = '\0';
272 strcpy(arg->result->info.ai_canonname, name);
274 arg->result->info.ai_next = NULL;
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);
286 ecore_con_info_get(Ecore_Con_Server *svr,
287 Ecore_Con_Info_Cb done_cb,
289 struct addrinfo *hints)
291 Ecore_Con_CAres *cares;
293 int ai_family = AF_INET6;
295 int ai_family = AF_INET;
298 cares = calloc(1, sizeof(Ecore_Con_CAres));
303 cares->done_cb = done_cb;
308 ai_family = hints->ai_family;
309 memcpy(&cares->hints, hints, sizeof(struct addrinfo));
312 if (inet_pton(AF_INET, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v4) == 1)
314 cares->byaddr = EINA_TRUE;
315 cares->isv6 = EINA_FALSE;
316 ares_gethostbyaddr(info_channel, &cares->addr.v4,
317 sizeof(cares->addr.v4),
319 (ares_host_callback)_ecore_con_info_ares_host_cb,
323 else if (inet_pton(AF_INET6, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v6) == 1)
325 cares->byaddr = EINA_TRUE;
326 cares->isv6 = EINA_TRUE;
327 ares_gethostbyaddr(info_channel, &cares->addr.v6,
328 sizeof(cares->addr.v6),
330 (ares_host_callback)_ecore_con_info_ares_host_cb,
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,
342 svr->infos = eina_list_append(svr->infos, cares);
347 ecore_con_info_data_clear(void *info)
349 Ecore_Con_CAres *cares = info;
350 if (cares) cares->data = NULL;
354 _ecore_con_info_cares_timeout_cb(void *data __UNUSED__)
356 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
357 return ECORE_CALLBACK_RENEW;
361 _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
362 Ecore_Fd_Handler *fd_handler)
364 ares_socket_t read_fd, write_fd;
366 read_fd = write_fd = ARES_SOCKET_BAD;
368 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
370 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
373 ares_process_fd(info_channel, read_fd, write_fd);
375 return ECORE_CALLBACK_RENEW;
379 _ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
380 const Ecore_Con_FD *fd2)
382 return fd1->fd - fd2->fd;
386 _ecore_con_info_cares_state_cb(void *data __UNUSED__,
392 Ecore_Con_FD *search = NULL, *ecf = NULL;
394 search = eina_list_search_unsorted(info_fds,
395 (Eina_Compare_Cb)_ecore_con_info_fds_search, &ecf);
397 if (!(readable | writable))
399 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
402 info_fds = eina_list_remove(info_fds, search);
403 ecore_timer_del(search->timer);
404 ecore_main_fd_handler_del(search->handler);
412 search = malloc(sizeof(Ecore_Con_FD));
413 EINA_SAFETY_ON_NULL_RETURN(search);
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);
423 if (readable) flags |= ECORE_FD_READ;
424 if (writable) flags |= ECORE_FD_WRITE;
425 ecore_main_fd_handler_active_set(search->handler, flags);
429 _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
431 int timeouts __UNUSED__,
432 struct hostent *hostent)
434 struct sockaddr *addr;
437 /* Found something ? */
441 if (!hostent->h_addr_list[0])
447 switch (hostent->h_addrtype)
451 struct sockaddr_in *addri;
453 addrlen = sizeof(struct sockaddr_in);
454 addri = malloc(addrlen);
459 addri->sin_family = AF_INET;
460 addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
462 memcpy(&addri->sin_addr.s_addr,
463 hostent->h_addr_list[0], sizeof(struct in_addr));
465 addr = (struct sockaddr *)addri;
471 struct sockaddr_in6 *addri6;
473 addrlen = sizeof(struct sockaddr_in6);
474 addri6 = malloc(addrlen);
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;
484 memcpy(&addri6->sin6_addr.s6_addr,
485 hostent->h_addr_list[0], sizeof(struct in6_addr));
487 addr = (struct sockaddr *)addri6;
492 ERR("Unknown addrtype %i", hostent->h_addrtype);
496 if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype,
503 case ARES_ENOTFOUND: /* address notfound */
507 /* This happen when host doesn't have a reverse. */
510 struct sockaddr_in6 *addri6;
512 addrlen = sizeof(struct sockaddr_in6);
513 addri6 = malloc(addrlen);
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;
523 memcpy(&addri6->sin6_addr.s6_addr,
524 &arg->addr.v6, sizeof(struct in6_addr));
526 addr = (struct sockaddr *)addri6;
531 struct sockaddr_in *addri;
533 addrlen = sizeof(struct sockaddr_in);
534 addri = malloc(addrlen);
539 addri->sin_family = AF_INET;
540 addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
542 memcpy(&addri->sin_addr.s_addr,
543 &arg->addr.v4, sizeof(struct in_addr));
545 addr = (struct sockaddr *)addri;
548 if (!_ecore_con_info_ares_getnameinfo(arg,
550 arg->isv6 ? AF_INET6 :
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));
571 ERR("Unknown status returned by c-ares: %i assuming error", status);
572 ecore_con_event_server_error(arg->svr, ares_strerror(status));
579 ERR("Not enough memory");
584 ecore_con_server_infos_del(arg->data, arg);
585 arg->done_cb(arg->data, NULL);
591 _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
593 int timeouts __UNUSED__,
601 strcpy(arg->result->ip, node);
603 *arg->result->ip = '\0';
606 strcpy(arg->result->service, service);
608 *arg->result->service = '\0';
610 if (arg->data) arg->done_cb(arg->data, arg->result);
616 case ARES_EDESTRUCTION:
618 ecore_con_event_server_error(arg->svr, ares_strerror(status));
619 if (arg->data) arg->done_cb(arg->data, NULL);
623 free(arg->result->info.ai_addr);
625 if (arg->data) ecore_con_server_infos_del(arg->data, arg);