X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Flib%2Fecore_con%2Fecore_con_dns.c;h=3671576ce1e14c20d1efcb6485705b4432a4f2dd;hb=1771a7c6b8fef4deabd25e31c5843d774b357de1;hp=e9c64deb48b6f936f3d9042960b6a78febe5cd4f;hpb=e6226e1771be5405fe7dc7f58974c72abd1d91a0;p=profile%2Fivi%2Fecore.git diff --git a/src/lib/ecore_con/ecore_con_dns.c b/src/lib/ecore_con/ecore_con_dns.c index e9c64de..3671576 100644 --- a/src/lib/ecore_con/ecore_con_dns.c +++ b/src/lib/ecore_con/ecore_con_dns.c @@ -1,210 +1,344 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* - * Simple dns lookup - * - * http://www.faqs.org/rfcs/rfc1035.html - * man resolv.conf - * - * And a sneakpeek at ares, ftp://athena-dist.mit.edu/pub/ATHENA/ares/ - */ -/* - * TODO - * * Check env LOCALDOMAIN to override search - * * Check env RES_OPTIONS to override options + * This version of ecore_con_info uses dns.c to provide asynchronous dns lookup. * - * * Read /etc/host.conf - * * host.conf env - * RESOLV_HOST_CONF, RESOLV_SERV_ORDER - * * Check /etc/hosts - * - * * Caching - * We should store all names returned when CNAME, might have different ttl. - * Check against search and hostname when querying cache? - * * Remember all querys and delete them on shutdown - * - * * Need more buffer overflow checks. + * dns.c is written by William Ahern: + * http://25thandclement.com/~william/projects/dns.c.html */ -#include "ecore_private.h" + +#include +#include + +#ifdef HAVE_ERRNO_H +# include /* for EAGAIN */ +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#ifdef HAVE_ERRNO_H +# include +#endif + +#include "dns.h" + #include "Ecore.h" +#include "Ecore_Con.h" #include "ecore_con_private.h" -#include -#include -#include -#include -#include -#include +typedef struct dns_addrinfo dns_addrinfo; +typedef struct dns_resolv_conf dns_resolv_conf; +typedef struct dns_resolver dns_resolver; +typedef struct dns_hosts dns_hosts; -typedef struct _CB_Data CB_Data; +typedef struct _Ecore_Con_DNS Ecore_Con_DNS; -struct _CB_Data +struct _Ecore_Con_DNS { - Ecore_List2 __list_data; - void (*cb_done) (void *data, struct hostent *hostent); - void *data; + Ecore_Con_Server *svr; + Ecore_Con_Info_Cb done_cb; + void *data; + dns_addrinfo *ai; + dns_resolver *resolv; + struct addrinfo hints; Ecore_Fd_Handler *fdh; - pid_t pid; - Ecore_Event_Handler *handler; - int fd2; + Ecore_Timer *timer; }; -static void _ecore_con_dns_readdata(CB_Data *cbdata); -static void _ecore_con_dns_slave_free(CB_Data *cbdata); -static int _ecore_con_dns_data_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_con_dns_exit_handler(void *data, int type __UNUSED__, void *event); +static int _ecore_con_dns_init = 0; +static dns_resolv_conf *resconf = NULL; +static dns_hosts *hosts = NULL; -static int dns_init = 0; -static Ecore_List2 *dns_slaves = NULL; - -int -ecore_con_dns_init(void) +static void +_ecore_con_dns_free(Ecore_Con_DNS *dns) { - dns_init++; - return dns_init; + if (dns->svr->infos) dns->svr->infos = eina_list_remove(dns->svr->infos, dns); + if (dns->timer) ecore_timer_del(dns->timer); + if (dns->fdh) ecore_main_fd_handler_del(dns->fdh); + dns_res_close(dns_res_mortal(dns->resolv)); + free(dns); } -int -ecore_con_dns_shutdown(void) +static Eina_Bool +_dns_addrinfo_get(Ecore_Con_DNS *dns, const char *addr, int port) { - dns_init--; - if (dns_init == 0) - { - while (dns_slaves) _ecore_con_dns_slave_free((CB_Data *)dns_slaves); - } - return dns_init; + int error = 0; + char service[NI_MAXSERV]; + + snprintf(service, sizeof(service), "%d", port); + dns->ai = dns_ai_open(addr, service, DNS_T_A, (const struct addrinfo *)&dns->hints, dns->resolv, &error); + return error; } -int -ecore_con_dns_lookup(const char *name, - void (*done_cb) (void *data, struct hostent *hostent), - void *data) +static int +_ecore_con_dns_check(Ecore_Con_DNS *dns) { - CB_Data *cbdata; - int fd[2]; - - if (pipe(fd) < 0) return 0; - cbdata = calloc(1, sizeof(CB_Data)); - if (!cbdata) - { - close(fd[0]); - close(fd[1]); - return 0; - } - cbdata->cb_done = done_cb; - cbdata->data = data; - cbdata->fd2 = fd[1]; - if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ, - _ecore_con_dns_data_handler, - cbdata, - NULL, NULL))) - { - free(cbdata); - close(fd[0]); - close(fd[1]); - return 0; - } - - if ((cbdata->pid = fork()) == 0) - { - struct hostent *he; - - /* CHILD */ - he = gethostbyname(name); - if (he) - { - struct in_addr addr; - - memcpy((struct in_addr *)&addr, he->h_addr, - sizeof(struct in_addr)); - write(fd[1], &(addr.s_addr), sizeof(in_addr_t)); - } - close(fd[1]); -# ifdef __USE_ISOC99 - _Exit(0); -# else - _exit(0); -# endif - } - /* PARENT */ - cbdata->handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_dns_exit_handler, cbdata); - if (!cbdata->handler) + struct addrinfo *ent = NULL; + int error = 0; + + error = dns_ai_nextent(&ent, dns->ai); + + switch (error) { - ecore_main_fd_handler_del(cbdata->fdh); - free(cbdata); - close(fd[0]); - close(fd[1]); - return 0; + case 0: + break; + case EAGAIN: + return 1; + default: + ERR("resolve failed: %s", dns_strerror(error)); + goto error; } - dns_slaves = _ecore_list2_append(dns_slaves, cbdata); - return 1; + + { + Ecore_Con_Info result = {0, .ip = {0}, .service = {0}}; +#if 0 + char pretty[512]; + dns_ai_print(pretty, sizeof(pretty), ent, dns->ai); + printf("%s\n", pretty); +#endif + result.size = 0; + dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), result.ip, sizeof(result.ip)); + snprintf(result.service, sizeof(result.service), "%u", ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr))); + memcpy(&result.info, ent, sizeof(result.info)); + if (dns->fdh) ecore_main_fd_handler_del(dns->fdh); + dns->fdh = NULL; + dns->done_cb(dns->data, &result); + free(ent); + _ecore_con_dns_free(dns); + } + + return 0; +error: + dns->done_cb(dns->data, NULL); + _ecore_con_dns_free(dns); + return -1; } -static void -_ecore_con_dns_readdata(CB_Data *cbdata) +static Eina_Bool +_dns_fd_cb(Ecore_Con_DNS *dns, Ecore_Fd_Handler *fdh __UNUSED__) { - struct hostent he; - struct in_addr addr; - char *addr2; - ssize_t size; - - size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &(addr.s_addr), - sizeof(in_addr_t)); - if (size == sizeof(in_addr_t)) + if (_ecore_con_dns_check(dns) != 1) return ECORE_CALLBACK_RENEW; + if (ecore_main_fd_handler_fd_get(dns->fdh) != dns_ai_pollfd(dns->ai)) { - addr2 = (char *)&addr; - he.h_addrtype = AF_INET; - he.h_length = sizeof(in_addr_t); - he.h_addr_list = &addr2; - cbdata->cb_done(cbdata->data, &he); + ecore_main_fd_handler_del(dns->fdh); + dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL); } else - cbdata->cb_done(cbdata->data, NULL); - cbdata->cb_done = NULL; + ecore_main_fd_handler_active_set(dns->fdh, dns_ai_events(dns->ai)); + return ECORE_CALLBACK_RENEW; } -static void -_ecore_con_dns_slave_free(CB_Data *cbdata) +static Eina_Bool +_dns_timer_cb(Ecore_Con_DNS *dns) { - dns_slaves = _ecore_list2_remove(dns_slaves, cbdata); - close(ecore_main_fd_handler_fd_get(cbdata->fdh)); - close(cbdata->fd2); - ecore_main_fd_handler_del(cbdata->fdh); - ecore_event_handler_del(cbdata->handler); - free(cbdata); + dns->done_cb(dns->data, NULL); + _ecore_con_dns_free(dns); + dns->timer = NULL; + return EINA_FALSE; } -static int -_ecore_con_dns_data_handler(void *data, Ecore_Fd_Handler *fd_handler) +int +ecore_con_info_init(void) { - CB_Data *cbdata; + int err; + if (_ecore_con_dns_init) return ++_ecore_con_dns_init; - cbdata = data; - if (cbdata->cb_done) + resconf = dns_resconf_local(&err); + if (!resconf) { - if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) - _ecore_con_dns_readdata(cbdata); - else - { - cbdata->cb_done(cbdata->data, NULL); - cbdata->cb_done = NULL; - } + ERR("resconf_open: %s", dns_strerror(err)); + return 0; } - _ecore_con_dns_slave_free(cbdata); - return 0; + hosts = dns_hosts_local(&err); + if (!hosts) + { + ERR("hosts_open: %s", dns_strerror(err)); + dns_resconf_close(resconf); + resconf = NULL; + return 0; + } + /* this is super slow don't do it */ + //resconf->options.recurse = 1; + return ++_ecore_con_dns_init; } -static int -_ecore_con_dns_exit_handler(void *data, int type __UNUSED__, void *event) +int +ecore_con_info_shutdown(void) { - CB_Data *cbdata; - Ecore_Exe_Event_Del *ev; - - ev = event; - cbdata = data; - if (cbdata->pid != ev->pid) return 1; + if (!_ecore_con_dns_init) return 0; + if (--_ecore_con_dns_init) return _ecore_con_dns_init; + dns_resconf_close(resconf); + resconf = NULL; + dns_hosts_close(hosts); + hosts = NULL; return 0; - _ecore_con_dns_slave_free(cbdata); +} + +void +ecore_con_info_data_clear(void *info) +{ + Ecore_Con_DNS *dns = info; + if (dns) dns->data = NULL; +} + +int +ecore_con_info_tcp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_TCP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_tcp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_TCP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_connect(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = IPPROTO_UDP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_udp_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_UDP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +int +ecore_con_info_mcast_listen(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data) +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); +#ifdef HAVE_IPV6 + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + return ecore_con_info_get(svr, done_cb, data, &hints); +} + +EAPI int +ecore_con_info_get(Ecore_Con_Server *svr, + Ecore_Con_Info_Cb done_cb, + void *data, + struct addrinfo *hints) +{ + Ecore_Con_DNS *dns; + int error = 0; + + dns = calloc(1, sizeof(Ecore_Con_DNS)); + if (!dns) return 0; + + dns->svr = svr; + dns->done_cb = done_cb; + dns->data = data; + + if (hints) + memcpy(&dns->hints, hints, sizeof(struct addrinfo)); + + if (!(dns->resolv = dns_res_open(resconf, hosts, dns_hints_mortal(dns_hints_local(resconf, &error)), NULL, dns_opts(), &error))) + { + ERR("res_open: %s", dns_strerror(error)); + goto reserr; + + } + + error = _dns_addrinfo_get(dns, svr->ecs ? svr->ecs->ip : svr->name, dns->svr->ecs ? dns->svr->ecs->port : dns->svr->port); + if (error && (error != EAGAIN)) + { + ERR("resolver: %s", dns_strerror(error)); + goto seterr; + } + + switch (_ecore_con_dns_check(dns)) + { + case 0: + break; + case 1: + dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL); + svr->infos = eina_list_append(svr->infos, dns); + dns->timer = ecore_timer_add(5.0, (Ecore_Task_Cb)_dns_timer_cb, dns); + break; + default: + return 0; + } + + return 1; +seterr: + if (dns->resolv) dns_res_close(dns_res_mortal(dns->resolv)); +reserr: + free(dns); return 0; } +