+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#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 <string.h>
+#include <sys/types.h>
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h> /* for EAGAIN */
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+#include "dns.h"
+
#include "Ecore.h"
+#include "Ecore_Con.h"
#include "ecore_con_private.h"
-#include <ctype.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <netdb.h>
+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;
}
+