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;
46 static ares_channel info_channel;
47 static int info_init = 0;
48 static Eina_List *info_fds = NULL;
49 static int active = 0;
50 static Ecore_Timer *tm = NULL;
51 static fd_set info_readers, info_writers;
53 static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg, int status, int timeouts, char *node, char *service);
54 static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, int status, int timeouts, struct hostent *hostent);
55 static int _ecore_con_info_cares_fd_cb(void *data, Ecore_Fd_Handler *fd_handler);
56 static int _ecore_con_info_cares_timeout_cb(void *data);
57 static void _ecore_con_info_cares_clean(void);
60 ecore_con_info_init(void)
64 if (ares_library_init(ARES_LIB_INIT_ALL) != 0)
66 if (ares_init(&info_channel) != ARES_SUCCESS)
68 ares_library_cleanup();
78 ecore_con_info_shutdown(void)
83 /* Cancel all ongoing request */
84 ares_cancel(info_channel);
85 ares_destroy(info_channel);
87 /* Destroy FD handler here. */
89 ares_library_cleanup();
95 ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
96 Ecore_Con_Info_Cb done_cb,
99 struct addrinfo hints;
101 memset(&hints, 0, sizeof(struct addrinfo));
102 hints.ai_family = AF_UNSPEC;
103 hints.ai_socktype = SOCK_STREAM;
104 hints.ai_flags = AI_CANONNAME;
105 hints.ai_protocol = IPPROTO_TCP;
106 hints.ai_canonname = NULL;
107 hints.ai_next = NULL;
108 hints.ai_addr = NULL;
110 return ecore_con_info_get(svr, done_cb, data, &hints);
114 ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
115 Ecore_Con_Info_Cb done_cb,
118 struct addrinfo hints;
120 memset(&hints, 0, sizeof(struct addrinfo));
121 hints.ai_family = AF_UNSPEC;
122 hints.ai_socktype = SOCK_STREAM;
123 hints.ai_flags = AI_PASSIVE;
124 hints.ai_protocol = IPPROTO_TCP;
125 hints.ai_canonname = NULL;
126 hints.ai_next = NULL;
127 hints.ai_addr = NULL;
129 return ecore_con_info_get(svr, done_cb, data, &hints);
133 ecore_con_info_udp_connect(Ecore_Con_Server *svr,
134 Ecore_Con_Info_Cb done_cb,
137 struct addrinfo hints;
139 memset(&hints, 0, sizeof(struct addrinfo));
140 hints.ai_family = AF_UNSPEC;
141 hints.ai_socktype = SOCK_DGRAM;
142 hints.ai_flags = AI_CANONNAME;
143 hints.ai_protocol = IPPROTO_UDP;
144 hints.ai_canonname = NULL;
145 hints.ai_next = NULL;
146 hints.ai_addr = NULL;
148 return ecore_con_info_get(svr, done_cb, data, &hints);
152 ecore_con_info_udp_listen(Ecore_Con_Server *svr,
153 Ecore_Con_Info_Cb done_cb,
156 struct addrinfo hints;
158 memset(&hints, 0, sizeof(struct addrinfo));
159 hints.ai_family = AF_UNSPEC;
160 hints.ai_socktype = SOCK_DGRAM;
161 hints.ai_flags = AI_PASSIVE;
162 hints.ai_protocol = IPPROTO_UDP;
163 hints.ai_canonname = NULL;
164 hints.ai_next = NULL;
165 hints.ai_addr = NULL;
167 return ecore_con_info_get(svr, done_cb, data, &hints);
171 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
172 Ecore_Con_Info_Cb done_cb,
175 struct addrinfo hints;
177 memset(&hints, 0, sizeof(struct addrinfo));
178 hints.ai_family = AF_UNSPEC;
179 hints.ai_socktype = SOCK_DGRAM;
181 hints.ai_protocol = IPPROTO_UDP;
182 hints.ai_canonname = NULL;
183 hints.ai_next = NULL;
184 hints.ai_addr = NULL;
186 return ecore_con_info_get(svr, done_cb, data, &hints);
190 ecore_con_info_get(Ecore_Con_Server *svr,
191 Ecore_Con_Info_Cb done_cb,
193 struct addrinfo *hints)
195 Ecore_Con_CAres *cares;
196 int ai_family = AF_UNSPEC;
198 cares = calloc(1, sizeof (Ecore_Con_CAres));
199 if (!cares) return 0;
202 cares->done_cb = done_cb;
207 ai_family = hints->ai_family;
208 memcpy(&cares->hints, hints, sizeof (struct addrinfo));
211 if (inet_pton(AF_INET, svr->name, &cares->addr.v4) == 1)
213 cares->byaddr = EINA_TRUE;
214 ares_gethostbyaddr(info_channel, &cares->addr.v4, sizeof (cares->addr.v4), AF_INET, (ares_host_callback) _ecore_con_info_ares_host_cb, cares);
216 else if (inet_pton(AF_INET6, svr->name, &cares->addr.v6) == 1)
218 cares->byaddr = EINA_TRUE;
219 ares_gethostbyaddr(info_channel, &cares->addr.v6, sizeof (cares->addr.v6), AF_INET6, (ares_host_callback) _ecore_con_info_ares_host_cb, cares);
223 cares->byaddr = EINA_FALSE;
224 ares_gethostbyname(info_channel, svr->name, ai_family, (ares_host_callback) _ecore_con_info_ares_host_cb, cares);
227 _ecore_con_info_cares_clean();
233 _ecore_con_info_fds_search(const Ecore_Con_FD *fd1, const Ecore_Con_FD *fd2)
235 return fd1->fd - fd2->fd;
239 _ecore_con_info_fds_lookup(int fd)
242 Ecore_Con_FD *search;
246 search = eina_list_search_unsorted(info_fds, (Eina_Compare_Cb) _ecore_con_info_fds_search, &fdl);
250 search->active = active;
257 _ecore_con_info_cares_clean(void)
259 fd_set readers, writers;
260 Eina_List *l, *l_next;
267 nfds = ares_fds(info_channel, &readers, &writers);
270 for (i = 0; i < nfds; ++i)
274 if (FD_ISSET(i, &readers)) flags |= ECORE_FD_READ;
275 if (FD_ISSET(i, &writers)) flags |= ECORE_FD_WRITE;
279 if (!_ecore_con_info_fds_lookup(i))
281 ecf = malloc(sizeof (Ecore_Con_FD));
285 ecf->active = active;
286 ecf->handler = ecore_main_fd_handler_add(i, ECORE_FD_WRITE | ECORE_FD_READ,
287 _ecore_con_info_cares_fd_cb,
289 info_fds = eina_list_append(info_fds, ecf);
295 info_readers = readers;
296 info_writers = writers;
298 EINA_LIST_FOREACH_SAFE(info_fds, l, l_next, ecf)
300 if (ecf->active != active)
302 ecore_main_fd_handler_del(ecf->handler);
304 info_fds = eina_list_remove_list(info_fds, l);
310 if (tm) ecore_timer_del(tm);
317 ares_timeout(info_channel, NULL, &tv);
320 ecore_timer_delay(tm, tv.tv_sec);
322 tm = ecore_timer_add((double) tv.tv_sec, _ecore_con_info_cares_timeout_cb, NULL);
327 _ecore_con_info_cares_timeout_cb(void *data)
329 ares_process(info_channel, &info_readers, &info_writers);
330 _ecore_con_info_cares_clean();
336 _ecore_con_info_cares_fd_cb(void *data, Ecore_Fd_Handler *fd_handler)
338 ares_process(info_channel, &info_readers, &info_writers);
339 _ecore_con_info_cares_clean();
345 _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, int status, int timeouts, struct hostent *hostent)
347 struct sockaddr *addr;
351 /* Found something ? */
355 if (hostent->h_addr_list[0] == NULL)
357 fprintf(stderr, "No IP found\n");
361 switch (hostent->h_addrtype)
365 struct sockaddr_in *addri;
367 addrlen = sizeof (struct sockaddr_in);
368 addri = malloc(addrlen);
372 fprintf(stderr, "Not enough memory\n");
376 addri->sin_family = AF_INET;
377 addri->sin_port = htons(arg->svr->port);
379 memcpy(&addri->sin_addr.s_addr, arg->byaddr ? &arg->addr.v4 : (struct in_addr*)hostent->h_addr_list[0], sizeof (struct in_addr));
381 addr = (struct sockaddr*) addri;
386 struct sockaddr_in6 *addri6;
388 addrlen = sizeof (struct sockaddr_in6);
389 addri6 = malloc(addrlen);
393 fprintf(stderr, "Not enough memory\n");
397 addri6->sin6_family = AF_INET6;
398 addri6->sin6_port = htons(arg->svr->port);
399 addri6->sin6_flowinfo = 0;
400 addri6->sin6_scope_id = 0;
402 memcpy(&addri6->sin6_addr.s6_addr, arg->byaddr ? &arg->addr.v6 : (struct in6_addr*)hostent->h_addr_list[0], sizeof (struct in6_addr));
404 addr = (struct sockaddr*) addri6;
408 fprintf(stderr, "Unknown addrtype %i\n", hostent->h_addrtype);
413 length = strlen(hostent->h_name) + 1;
415 arg->result = malloc(sizeof (Ecore_Con_Info) + length);
418 fprintf(stderr, "Not enough memory\n");
423 /* FIXME: What to do when hint is not set ? */
424 arg->result->info.ai_flags = arg->hints.ai_flags;
425 arg->result->info.ai_socktype = arg->hints.ai_socktype;
426 arg->result->info.ai_protocol = arg->hints.ai_protocol;
428 arg->result->info.ai_family = hostent->h_addrtype;
429 arg->result->info.ai_addrlen = addrlen;
430 arg->result->info.ai_addr = addr;
431 arg->result->info.ai_canonname = (char*) (arg->result + 1);
433 strcpy(arg->result->info.ai_canonname, hostent->h_name);
435 arg->result->info.ai_next = NULL;
437 ares_getnameinfo(info_channel, addr, addrlen,
438 ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST | ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
439 (ares_nameinfo_callback) _ecore_con_info_ares_nameinfo, arg);
441 case ARES_ENOTIMP: /* unknown family */
442 case ARES_EBADNAME: /* not a valid internet address */
443 case ARES_ENOTFOUND: /* address notfound */
444 case ARES_ENOMEM: /* not enough memory */
445 case ARES_EDESTRUCTION: /* request canceled, shuting down */
448 fprintf(stderr, "Unknown status returned by c-ares: %i assuming error\n", status);
455 arg->done_cb(arg->data, NULL);
460 _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg, int status, int timeouts, char *node, char *service)
465 if (node) strcpy(arg->result->ip, node);
466 else *arg->result->ip = '\0';
467 if (service) strcpy(arg->result->service, service);
468 else *arg->result->service = '\0';
470 arg->done_cb(arg->data, arg->result);
475 case ARES_EDESTRUCTION:
477 arg->done_cb(arg->data, NULL);
481 free(arg->result->info.ai_addr);