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
14 #ifdef HAVE_ARPA_INET_H
15 # include <arpa/inet.h>
21 #include "Ecore_Con.h"
22 #include "ecore_con_private.h"
24 typedef struct _Ecore_Con_FD Ecore_Con_FD;
25 typedef struct _Ecore_Con_CAres Ecore_Con_CAres;
29 Ecore_Fd_Handler *handler;
34 struct _Ecore_Con_CAres
36 Ecore_Con_Server *svr;
37 Ecore_Con_Info_Cb done_cb;
39 struct addrinfo hints;
40 Ecore_Con_Info *result;
51 static ares_channel info_channel;
52 static int info_init = 0;
53 static Eina_List *info_fds = NULL;
55 static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
60 static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
63 struct hostent *hostent);
64 static Eina_Bool _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
65 Ecore_Fd_Handler *fd_handler);
66 static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data);
69 _ecore_con_info_cares_state_cb(void *data,
74 _ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
75 const Ecore_Con_FD *fd2);
78 ecore_con_info_init(void)
80 struct ares_options opts;
84 if (ares_library_init(ARES_LIB_INIT_ALL))
87 opts.lookups = "fb"; /* hosts file then dns */
88 opts.sock_state_cb = _ecore_con_info_cares_state_cb;
90 if (ares_init_options(&info_channel, &opts,
91 ARES_OPT_LOOKUPS | ARES_OPT_SOCK_STATE_CB) != ARES_SUCCESS)
93 ares_library_cleanup();
103 ecore_con_info_shutdown(void)
108 /* Cancel all ongoing request */
109 ares_cancel(info_channel);
110 ares_destroy(info_channel);
113 ares_library_cleanup();
120 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
121 Ecore_Con_Info_Cb done_cb,
124 struct addrinfo hints;
126 memset(&hints, 0, sizeof(struct addrinfo));
127 hints.ai_family = AF_INET6;
128 hints.ai_socktype = SOCK_STREAM;
129 hints.ai_flags = AI_CANONNAME;
130 hints.ai_protocol = IPPROTO_TCP;
131 hints.ai_canonname = NULL;
132 hints.ai_next = NULL;
133 hints.ai_addr = NULL;
135 return ecore_con_info_get(svr, done_cb, data, &hints);
139 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
140 Ecore_Con_Info_Cb done_cb,
143 struct addrinfo hints;
145 memset(&hints, 0, sizeof(struct addrinfo));
146 hints.ai_family = AF_INET6;
147 hints.ai_socktype = SOCK_STREAM;
148 hints.ai_flags = AI_PASSIVE;
149 hints.ai_protocol = IPPROTO_TCP;
150 hints.ai_canonname = NULL;
151 hints.ai_next = NULL;
152 hints.ai_addr = NULL;
154 return ecore_con_info_get(svr, done_cb, data, &hints);
158 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
159 Ecore_Con_Info_Cb done_cb,
162 struct addrinfo hints;
164 memset(&hints, 0, sizeof(struct addrinfo));
165 hints.ai_family = AF_INET6;
166 hints.ai_socktype = SOCK_DGRAM;
167 hints.ai_flags = AI_CANONNAME;
168 hints.ai_protocol = IPPROTO_UDP;
169 hints.ai_canonname = NULL;
170 hints.ai_next = NULL;
171 hints.ai_addr = NULL;
173 return ecore_con_info_get(svr, done_cb, data, &hints);
177 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
178 Ecore_Con_Info_Cb done_cb,
181 struct addrinfo hints;
183 memset(&hints, 0, sizeof(struct addrinfo));
184 hints.ai_family = AF_INET6;
185 hints.ai_socktype = SOCK_DGRAM;
186 hints.ai_flags = AI_PASSIVE;
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_mcast_listen(Ecore_Con_Server *svr,
197 Ecore_Con_Info_Cb done_cb,
200 struct addrinfo hints;
202 memset(&hints, 0, sizeof(struct addrinfo));
203 hints.ai_family = AF_INET6;
204 hints.ai_socktype = SOCK_DGRAM;
206 hints.ai_protocol = IPPROTO_UDP;
207 hints.ai_canonname = NULL;
208 hints.ai_next = NULL;
209 hints.ai_addr = NULL;
211 return ecore_con_info_get(svr, done_cb, data, &hints);
215 _ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
218 struct sockaddr *addr,
224 length = strlen(name) + 1;
228 arg->result = malloc(sizeof(Ecore_Con_Info) + length);
232 /* FIXME: What to do when hint is not set ? */
233 arg->result->info.ai_flags = arg->hints.ai_flags;
234 arg->result->info.ai_socktype = arg->hints.ai_socktype;
235 arg->result->info.ai_protocol = arg->hints.ai_protocol;
237 arg->result->info.ai_family = addrtype;
238 arg->result->info.ai_addrlen = addrlen;
239 arg->result->info.ai_addr = addr;
240 arg->result->info.ai_canonname = (char *)(arg->result + 1);
243 *arg->result->info.ai_canonname = '\0';
245 strcpy(arg->result->info.ai_canonname, name);
247 arg->result->info.ai_next = NULL;
250 info_channel, addr, addrlen,
251 ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST |
252 ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
253 (ares_nameinfo_callback)_ecore_con_info_ares_nameinfo, arg);
259 ecore_con_info_get(Ecore_Con_Server *svr,
260 Ecore_Con_Info_Cb done_cb,
262 struct addrinfo *hints)
264 Ecore_Con_CAres *cares;
265 int ai_family = AF_INET6;
267 cares = calloc(1, sizeof(Ecore_Con_CAres));
272 cares->done_cb = done_cb;
277 ai_family = hints->ai_family;
278 memcpy(&cares->hints, hints, sizeof(struct addrinfo));
281 if (inet_pton(AF_INET, svr->name, &cares->addr.v4) == 1)
283 cares->byaddr = EINA_TRUE;
284 cares->isv6 = EINA_FALSE;
285 ares_gethostbyaddr(info_channel, &cares->addr.v4,
286 sizeof(cares->addr.v4),
288 (ares_host_callback)_ecore_con_info_ares_host_cb,
291 else if (inet_pton(AF_INET6, svr->name, &cares->addr.v6) == 1)
293 cares->byaddr = EINA_TRUE;
294 cares->isv6 = EINA_TRUE;
295 ares_gethostbyaddr(info_channel, &cares->addr.v6,
296 sizeof(cares->addr.v6),
298 (ares_host_callback)_ecore_con_info_ares_host_cb,
303 cares->byaddr = EINA_FALSE;
304 ares_gethostbyname(info_channel, svr->name, ai_family,
305 (ares_host_callback)_ecore_con_info_ares_host_cb,
309 svr->infos = eina_list_append(svr->infos, cares);
314 ecore_con_info_data_clear(void *info)
316 Ecore_Con_CAres *cares = info;
321 _ecore_con_info_cares_timeout_cb(void *data __UNUSED__)
323 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
324 return ECORE_CALLBACK_RENEW;
328 _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
329 Ecore_Fd_Handler *fd_handler)
331 ares_socket_t read_fd, write_fd;
333 read_fd = write_fd = ARES_SOCKET_BAD;
335 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
337 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
340 ares_process_fd(info_channel, read_fd, write_fd);
342 return ECORE_CALLBACK_RENEW;
346 _ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
347 const Ecore_Con_FD *fd2)
349 return fd1->fd - fd2->fd;
353 _ecore_con_info_cares_state_cb(void *data __UNUSED__,
359 Ecore_Con_FD *search = NULL, *ecf = NULL;
361 search = eina_list_search_unsorted(info_fds,
362 (Eina_Compare_Cb)_ecore_con_info_fds_search, &ecf);
364 if (!(readable | writable))
366 ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
369 info_fds = eina_list_remove(info_fds, search);
370 ecore_timer_del(search->timer);
371 ecore_main_fd_handler_del(search->handler);
379 search = malloc(sizeof(Ecore_Con_FD));
380 EINA_SAFETY_ON_NULL_RETURN(search);
383 search->handler = ecore_main_fd_handler_add(fd, ECORE_FD_WRITE | ECORE_FD_READ,
384 (Ecore_Fd_Cb)_ecore_con_info_cares_fd_cb, search, NULL, NULL);
385 /* c-ares default timeout is 5 seconds */
386 search->timer = ecore_timer_add(5, _ecore_con_info_cares_timeout_cb, NULL);
387 info_fds = eina_list_append(info_fds, search);
390 if (readable) flags |= ECORE_FD_READ;
391 if (writable) flags |= ECORE_FD_WRITE;
392 ecore_main_fd_handler_active_set(search->handler, flags);
396 _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
398 int timeouts __UNUSED__,
399 struct hostent *hostent)
401 struct sockaddr *addr;
404 /* Found something ? */
408 if (!hostent->h_addr_list[0])
414 switch (hostent->h_addrtype)
418 struct sockaddr_in *addri;
420 addrlen = sizeof(struct sockaddr_in);
421 addri = malloc(addrlen);
426 addri->sin_family = AF_INET;
427 addri->sin_port = htons(arg->svr->port);
429 memcpy(&addri->sin_addr.s_addr,
430 hostent->h_addr_list[0], sizeof(struct in_addr));
432 addr = (struct sockaddr *)addri;
438 struct sockaddr_in6 *addri6;
440 addrlen = sizeof(struct sockaddr_in6);
441 addri6 = malloc(addrlen);
446 addri6->sin6_family = AF_INET6;
447 addri6->sin6_port = htons(arg->svr->port);
448 addri6->sin6_flowinfo = 0;
449 addri6->sin6_scope_id = 0;
451 memcpy(&addri6->sin6_addr.s6_addr,
452 hostent->h_addr_list[0], sizeof(struct in6_addr));
454 addr = (struct sockaddr *)addri6;
459 ERR("Unknown addrtype %i", hostent->h_addrtype);
463 if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype,
470 case ARES_ENOTFOUND: /* address notfound */
473 /* This happen when host doesn't have a reverse. */
476 struct sockaddr_in6 *addri6;
478 addrlen = sizeof(struct sockaddr_in6);
479 addri6 = malloc(addrlen);
484 addri6->sin6_family = AF_INET6;
485 addri6->sin6_port = htons(arg->svr->port);
486 addri6->sin6_flowinfo = 0;
487 addri6->sin6_scope_id = 0;
489 memcpy(&addri6->sin6_addr.s6_addr,
490 &arg->addr.v6, sizeof(struct in6_addr));
492 addr = (struct sockaddr *)addri6;
496 struct sockaddr_in *addri;
498 addrlen = sizeof(struct sockaddr_in);
499 addri = malloc(addrlen);
504 addri->sin_family = AF_INET;
505 addri->sin_port = htons(arg->svr->port);
507 memcpy(&addri->sin_addr.s_addr,
508 &arg->addr.v4, sizeof(struct in_addr));
510 addr = (struct sockaddr *)addri;
513 if (!_ecore_con_info_ares_getnameinfo(arg,
514 arg->isv6 ? AF_INET6 :
523 case ARES_ENOTIMP: /* unknown family */
524 case ARES_EBADNAME: /* not a valid internet address */
525 case ARES_ENOMEM: /* not enough memory */
526 case ARES_EDESTRUCTION: /* request canceled, shuting down */
527 case ARES_ENODATA: /* no data returned */
528 case ARES_ECONNREFUSED: /* connection refused */
529 case ARES_ETIMEOUT: /* connection timed out */
530 ecore_con_event_server_error(arg->svr, ares_strerror(status));
534 ERR("Unknown status returned by c-ares: %i assuming error", status);
535 ecore_con_event_server_error(arg->svr, ares_strerror(status));
542 ERR("Not enough memory");
547 ecore_con_server_infos_del(arg->data, arg);
548 arg->done_cb(arg->data, NULL);
554 _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
556 int timeouts __UNUSED__,
564 strcpy(arg->result->ip, node);
566 *arg->result->ip = '\0';
569 strcpy(arg->result->service, service);
571 *arg->result->service = '\0';
573 if (arg->data) arg->done_cb(arg->data, arg->result);
579 case ARES_EDESTRUCTION:
581 ecore_con_event_server_error(arg->svr, ares_strerror(status));
582 if (arg->data) arg->done_cb(arg->data, NULL);
586 free(arg->result->info.ai_addr);
588 if (arg->data) ecore_con_server_infos_del(arg->data, arg);