ecore-con - simplify down to a single libc resolver

Summary:
this removes the cares/ares based resolver and the compiled-in dns.c
resolver, modified the getaddrinfo based resolver to use threads not
forking (almost halving its size) and now makes that the only resolver
we have. getaddrinfo handles ipv6 and ipv4 (according to docs). this
simplifies code paths, drops code size of the efl tree by about 11k
lines of code, makes it easier to test and more robust to future
changes with ip resolving as it now just relies on libc. we won't have
coverity complaints on dns.c imported code anymore to fix and don't
have tokeep up with bugfixes/security from the upstream imported code.
this means we use a single resolver on all platforms (windows, mac,
linux) as opposed to before where cares was used for windows, and
dns.c on linux/mac. oh and the forking original was broken since our
move to eo too. so it couldnt even compile if enabled, letalone work.

so fix bug with missing /etc/resolv.conf that dns.c couldn't cope
with, fix testability, fix maintainability and reduce efl codebase size.

this fixes T3668

@fix
@improve

Subscribers: cedric, seoz, jpeg

Maniphest Tasks: T3668

Differential Revision: https://phab.enlightenment.org/D3971
This commit is contained in:
Carsten Haitzler 2016-05-22 17:03:26 +09:00
parent 6e23780bb1
commit 1eba9d9de0
7 changed files with 135 additions and 11186 deletions

View File

@ -1732,6 +1732,7 @@ AC_CHECK_HEADERS([sys/socket.h])
AC_CHECK_HEADERS([ \
arpa/inet.h \
arpa/nameser.h \
langinfo.h \
features.h \
netinet/in.h \
@ -2878,17 +2879,12 @@ want_ecore_con_local_sockets="yes"
want_ecore_con_abstract_sockets="yes"
if test "${have_win32}" = "yes"; then
want_cares="yes"
want_ecore_con_abstract_sockets="no"
elif test "${have_darwin}" = "yes"; then
want_cares="no"
want_ecore_con_abstract_sockets="yes"
elif test "${have_ps3}" = "yes"; then
want_cares="no"
want_ecore_con_local_sockets="no"
want_ecore_con_abstract_sockets="no"
else
want_cares="no"
fi
AC_DEFINE_IF([HAVE_LOCAL_SOCKETS],
@ -2914,24 +2910,10 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [emile])
EFL_ADD_LIBS([ECORE_CON], [-lm])
EFL_OPTIONAL_DEPEND_PKG([ECORE_CON], [${want_cares}],
[CARES], [libcares >= 1.6.1])
AM_CONDITIONAL([HAVE_CARES], [test "x${have_cares}" = "xyes"])
if test "x$have_cares" = "xyes" ; then
ecore_con_resolver="cares"
elif test "x$ac_cv_prog_cc_c99" != "xno" ; then
ecore_con_resolver="dns.c"
else
ecore_con_resolver="fork"
fi
EFL_OPTIONAL_DEPEND_PKG([ECORE_CON], [${want_systemd}], [SYSTEMD], [libsystemd])
EFL_ADD_FEATURE([ECORE_CON], [cares])
EFL_ADD_FEATURE([ECORE_CON], [local-sockets], [${want_ecore_con_local_sockets}])
EFL_ADD_FEATURE([ECORE_CON], [abstract-sockets], [${want_ecore_con_abstract_sockets}])
EFL_ADD_FEATURE([ECORE_CON], [resolver], [${ecore_con_resolver}])
EFL_ADD_FEATURE([ECORE_CON], [systemd-daemon], [${want_systemd}])
EFL_EVAL_PKGS([ECORE_CON])

View File

@ -51,7 +51,8 @@ lib/ecore_con/ecore_con_url_curl.c \
lib/ecore_con/ecore_con_url_curl.h \
static_libs/http-parser/http_parser.c \
static_libs/http-parser/http_parser.h \
lib/ecore_con/ecore_con_private.h
lib/ecore_con/ecore_con_private.h \
lib/ecore_con/ecore_con_info.c
EXTRA_DIST += lib/ecore_con/ecore_con_legacy.c
@ -61,19 +62,6 @@ else
lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local.c
endif
if HAVE_CARES
lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_ares.c
else
if HAVE_IPV6
lib_ecore_con_libecore_con_la_SOURCES += \
lib/ecore_con/ecore_con_dns.c \
static_libs/dns/dns.c \
static_libs/dns/dns.h
else
lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_info.c
endif
endif
lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CON_CFLAGS@
lib_ecore_con_libecore_con_la_LIBADD = @ECORE_CON_LIBS@ @EVIL_LIBS@
lib_ecore_con_libecore_con_la_DEPENDENCIES = @ECORE_CON_INTERNAL_LIBS@
@ -81,10 +69,6 @@ lib_ecore_con_libecore_con_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
lib_ecore_con_libecore_con_la_CPPFLAGS += -I$(top_srcdir)/src/static_libs/http-parser
if HAVE_IPV6
lib_ecore_con_libecore_con_la_CPPFLAGS += -I$(top_srcdir)/src/static_libs/dns/
endif
EXTRA_DIST += \
tests/ecore_con/server.key \
tests/ecore_con/server.pem \

View File

@ -1,635 +0,0 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/*
* This version of ecore_con_info use c-ares to provide asynchronous dns lookup.
*
* Note: It doesn't fork nor does it use libc getaddrinfo.
* http://c-ares.haxx.se/docs.html
*/
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#include <ares.h>
#include "Ecore.h"
#include "Ecore_Con.h"
#include "ecore_con_private.h"
typedef struct _Ecore_Con_FD Ecore_Con_FD;
typedef struct _Ecore_Con_CAres Ecore_Con_CAres;
struct _Ecore_Con_FD
{
Ecore_Fd_Handler *handler;
Ecore_Timer *timer;
int fd;
};
struct _Ecore_Con_CAres
{
Ecore_Con_Server *svr;
Ecore_Con_Info_Cb done_cb;
void *data;
struct addrinfo hints;
Ecore_Con_Info *result;
union
{
struct in_addr v4;
#ifdef HAVE_IPV6
struct in6_addr v6;
#endif
} addr;
Eina_Bool byaddr : 1;
Eina_Bool isv6 : 1;
};
static ares_channel info_channel;
static int info_init = 0;
static Eina_List *info_fds = NULL;
static void _ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
int status,
int timeouts,
char *node,
char *service);
static void _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
int status,
int timeouts,
struct hostent *hostent);
static Eina_Bool _ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
Ecore_Fd_Handler *fd_handler);
static Eina_Bool _ecore_con_info_cares_timeout_cb(void *data);
static void
_ecore_con_info_cares_state_cb(void *data,
ares_socket_t fd,
int readable,
int writable);
static int
_ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
const Ecore_Con_FD *fd2);
int
ecore_con_info_init(void)
{
struct ares_options opts;
if (!info_init)
{
if (ares_library_init(ARES_LIB_INIT_ALL))
return 0;
opts.lookups = "fb"; /* hosts file then dns */
opts.sock_state_cb = _ecore_con_info_cares_state_cb;
if (ares_init_options(&info_channel, &opts,
ARES_OPT_LOOKUPS | ARES_OPT_SOCK_STATE_CB) != ARES_SUCCESS)
{
ares_library_cleanup();
return 0;
}
}
info_init++;
return info_init;
}
int
ecore_con_info_shutdown(void)
{
info_init--;
if (info_init == 0)
{
/* Cancel all ongoing request */
ares_cancel(info_channel);
ares_destroy(info_channel);
/* Shutdown ares */
ares_library_cleanup();
}
return info_init;
}
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;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
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;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
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;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
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;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
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_flags = 0;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
return ecore_con_info_get(svr, done_cb, data, &hints);
}
static Eina_Bool
_ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
int addrtype,
const char *name,
struct sockaddr *addr,
int addrlen)
{
int length = 0;
if (name)
length = strlen(name) + 1;
else
length = 1;
arg->result = malloc(sizeof(Ecore_Con_Info) + length);
if (!arg->result)
return EINA_FALSE;
/* FIXME: What to do when hint is not set ? */
arg->result->info.ai_flags = arg->hints.ai_flags;
arg->result->info.ai_socktype = arg->hints.ai_socktype;
arg->result->info.ai_protocol = arg->hints.ai_protocol;
arg->result->info.ai_family = addrtype;
arg->result->info.ai_addrlen = addrlen;
arg->result->info.ai_addr = addr;
arg->result->info.ai_canonname = (char *)(arg->result + 1);
if (!name)
*arg->result->info.ai_canonname = '\0';
else
strcpy(arg->result->info.ai_canonname, name);
arg->result->info.ai_next = NULL;
ares_getnameinfo(
info_channel, addr, addrlen,
ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST |
ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
(ares_nameinfo_callback)_ecore_con_info_ares_nameinfo, arg);
return EINA_TRUE;
}
EAPI int
ecore_con_info_get(Ecore_Con_Server *obj,
Ecore_Con_Info_Cb done_cb,
void *data,
struct addrinfo *hints)
{
Efl_Network_Server_Data *svr = eo_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS);
Ecore_Con_CAres *cares;
#ifdef HAVE_IPV6
int ai_family = AF_INET6;
#else
int ai_family = AF_INET;
#endif
cares = calloc(1, sizeof(Ecore_Con_CAres));
if (!cares)
return 0;
cares->svr = obj;
cares->done_cb = done_cb;
cares->data = data;
if (hints)
{
ai_family = hints->ai_family;
memcpy(&cares->hints, hints, sizeof(struct addrinfo));
}
if (inet_pton(AF_INET, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v4) == 1)
{
cares->byaddr = EINA_TRUE;
cares->isv6 = EINA_FALSE;
ares_gethostbyaddr(info_channel, &cares->addr.v4,
sizeof(cares->addr.v4),
AF_INET,
(ares_host_callback)_ecore_con_info_ares_host_cb,
cares);
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v6) == 1)
{
cares->byaddr = EINA_TRUE;
cares->isv6 = EINA_TRUE;
ares_gethostbyaddr(info_channel, &cares->addr.v6,
sizeof(cares->addr.v6),
AF_INET6,
(ares_host_callback)_ecore_con_info_ares_host_cb,
cares);
}
#endif
else
{
cares->byaddr = EINA_FALSE;
ares_gethostbyname(info_channel, svr->ecs ? svr->ecs->ip : svr->name, ai_family,
(ares_host_callback)_ecore_con_info_ares_host_cb,
cares);
}
svr->infos = eina_list_append(svr->infos, cares);
return 1;
}
void
ecore_con_info_data_clear(void *info)
{
Ecore_Con_CAres *cares = info;
if (cares) cares->data = NULL;
}
static Eina_Bool
_ecore_con_info_cares_timeout_cb(void *data EINA_UNUSED)
{
ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_ecore_con_info_cares_fd_cb(Ecore_Con_FD *ecf,
Ecore_Fd_Handler *fd_handler)
{
ares_socket_t read_fd, write_fd;
read_fd = write_fd = ARES_SOCKET_BAD;
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
read_fd = ecf->fd;
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
write_fd = ecf->fd;
ares_process_fd(info_channel, read_fd, write_fd);
return ECORE_CALLBACK_RENEW;
}
static int
_ecore_con_info_fds_search(const Ecore_Con_FD *fd1,
const Ecore_Con_FD *fd2)
{
return fd1->fd - fd2->fd;
}
static void
_ecore_con_info_cares_state_cb(void *data EINA_UNUSED,
ares_socket_t fd,
int readable,
int writable)
{
int flags = 0;
Ecore_Con_FD *search = NULL, *ecf = NULL;
search = eina_list_search_unsorted(info_fds,
(Eina_Compare_Cb)_ecore_con_info_fds_search, &ecf);
if (!(readable | writable))
{
ares_process_fd(info_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
if (search)
{
info_fds = eina_list_remove(info_fds, search);
ecore_timer_del(search->timer);
ecore_main_fd_handler_del(search->handler);
free(search);
}
return;
}
if (!search)
{
search = malloc(sizeof(Ecore_Con_FD));
EINA_SAFETY_ON_NULL_RETURN(search);
search->fd = fd;
search->handler = ecore_main_fd_handler_add(fd, ECORE_FD_WRITE | ECORE_FD_READ,
(Ecore_Fd_Cb)_ecore_con_info_cares_fd_cb, search, NULL, NULL);
/* c-ares default timeout is 5 seconds */
search->timer = ecore_timer_add(5, _ecore_con_info_cares_timeout_cb, NULL);
info_fds = eina_list_append(info_fds, search);
}
if (readable) flags |= ECORE_FD_READ;
if (writable) flags |= ECORE_FD_WRITE;
ecore_main_fd_handler_active_set(search->handler, flags);
}
static void
_ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg,
int status,
int timeouts EINA_UNUSED,
struct hostent *hostent)
{
struct sockaddr *addr;
Efl_Network_Server_Data *svr;
int addrlen;
svr = eo_data_scope_get(arg->svr, EFL_NETWORK_SERVER_CLASS);
/* Found something ? */
switch (status)
{
case ARES_SUCCESS:
if (!hostent->h_addr_list[0])
{
ERR("No IP found");
goto on_error;
}
switch (hostent->h_addrtype)
{
case AF_INET:
{
struct sockaddr_in *addri;
addrlen = sizeof(struct sockaddr_in);
addri = malloc(addrlen);
if (!addri)
goto on_mem_error;
addri->sin_family = AF_INET;
addri->sin_port = htons(svr->ecs ? svr->ecs->port : svr->port);
memcpy(&addri->sin_addr.s_addr,
hostent->h_addr_list[0], sizeof(struct in_addr));
addr = (struct sockaddr *)addri;
break;
}
#ifdef HAVE_IPV6
case AF_INET6:
{
struct sockaddr_in6 *addri6;
addrlen = sizeof(struct sockaddr_in6);
addri6 = malloc(addrlen);
if (!addri6)
goto on_mem_error;
addri6->sin6_family = AF_INET6;
addri6->sin6_port = htons(svr->ecs ? svr->ecs->port : svr->port);
addri6->sin6_flowinfo = 0;
addri6->sin6_scope_id = 0;
memcpy(&addri6->sin6_addr.s6_addr,
hostent->h_addr_list[0], sizeof(struct in6_addr));
addr = (struct sockaddr *)addri6;
break;
}
#endif
default:
ERR("Unknown addrtype %i", hostent->h_addrtype);
goto on_error;
}
if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype,
hostent->h_name,
addr, addrlen))
goto on_error;
break;
case ARES_ENOTFOUND: /* address notfound */
if (arg->byaddr)
{
#ifdef HAVE_IPV6
/* This happen when host doesn't have a reverse. */
if (arg->isv6)
{
struct sockaddr_in6 *addri6;
addrlen = sizeof(struct sockaddr_in6);
addri6 = malloc(addrlen);
if (!addri6)
goto on_mem_error;
addri6->sin6_family = AF_INET6;
addri6->sin6_port = htons(svr->ecs ? svr->ecs->port : svr->port);
addri6->sin6_flowinfo = 0;
addri6->sin6_scope_id = 0;
memcpy(&addri6->sin6_addr.s6_addr,
&arg->addr.v6, sizeof(struct in6_addr));
addr = (struct sockaddr *)addri6;
}
else
#endif
{
struct sockaddr_in *addri;
addrlen = sizeof(struct sockaddr_in);
addri = malloc(addrlen);
if (!addri)
goto on_mem_error;
addri->sin_family = AF_INET;
addri->sin_port = htons(svr->ecs ? svr->ecs->port : svr->port);
memcpy(&addri->sin_addr.s_addr,
&arg->addr.v4, sizeof(struct in_addr));
addr = (struct sockaddr *)addri;
}
if (!_ecore_con_info_ares_getnameinfo(arg,
#ifdef HAVE_IPV6
arg->isv6 ? AF_INET6 :
#endif
AF_INET,
NULL, addr,
addrlen))
goto on_error;
break;
}
case ARES_ENOTIMP: /* unknown family */
case ARES_EBADNAME: /* not a valid internet address */
case ARES_ENOMEM: /* not enough memory */
case ARES_EDESTRUCTION: /* request canceled, shuting down */
case ARES_ENODATA: /* no data returned */
case ARES_ECONNREFUSED: /* connection refused */
case ARES_ETIMEOUT: /* connection timed out */
ecore_con_event_server_error(arg->svr, ares_strerror(status));
goto on_error;
default:
ERR("Unknown status returned by c-ares: %i assuming error", status);
ecore_con_event_server_error(arg->svr, ares_strerror(status));
goto on_error;
}
return;
on_mem_error:
ERR("Not enough memory");
on_error:
if (arg->data)
{
ecore_con_server_infos_del(arg->data, arg);
arg->done_cb(arg->data, NULL);
}
free(arg);
}
static void
_ecore_con_info_ares_nameinfo(Ecore_Con_CAres *arg,
int status,
int timeouts EINA_UNUSED,
char *node,
char *service)
{
switch (status)
{
case ARES_SUCCESS:
if (node)
strcpy(arg->result->ip, node);
else
*arg->result->ip = '\0';
if (service)
strcpy(arg->result->service, service);
else
*arg->result->service = '\0';
if (arg->data) arg->done_cb(arg->data, arg->result);
break;
case ARES_ENOTIMP:
case ARES_ENOTFOUND:
case ARES_ENOMEM:
case ARES_EDESTRUCTION:
case ARES_EBADFLAGS:
ecore_con_event_server_error(arg->svr, ares_strerror(status));
if (arg->data) arg->done_cb(arg->data, NULL);
break;
}
free(arg->result->info.ai_addr);
free(arg->result);
if (arg->data) ecore_con_server_infos_del(arg->data, arg);
free(arg);
}

View File

@ -1,351 +0,0 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/*
* This version of ecore_con_info uses dns.c to provide asynchronous dns lookup.
*
* dns.c is written by William Ahern:
* http://25thandclement.com/~william/projects/dns.c.html
*/
#include <string.h>
#include <sys/types.h>
#include <errno.h> /* for EAGAIN */
#include <netinet/in.h>
#include <arpa/inet.h>
#include "dns.h"
#include "Ecore.h"
#include "Ecore_Con.h"
#include "ecore_con_private.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 _Ecore_Con_DNS Ecore_Con_DNS;
struct _Ecore_Con_DNS
{
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;
Ecore_Timer *timer;
};
static int _ecore_con_dns_init = 0;
static dns_resolv_conf *resconf = NULL;
static dns_hosts *hosts = NULL;
static void
_ecore_con_dns_free(Ecore_Con_DNS *dns)
{
if (dns->timer) ecore_timer_del(dns->timer);
if (dns->fdh) ecore_main_fd_handler_del(dns->fdh);
if (dns->ai) dns_ai_close(dns->ai);
dns_res_close(dns_res_mortal(dns->resolv));
free(dns);
}
static void
_ecore_con_dns_del(Ecore_Con_DNS *dns)
{
if (dns->svr)
{
Efl_Network_Server_Data *svr;
svr = eo_data_scope_get(dns->svr, EFL_NETWORK_CLIENT_CLASS);
if ((svr) && (svr->infos))
svr->infos = eina_list_remove(svr->infos, dns);
}
_ecore_con_dns_free(dns);
}
static Eina_Bool
_dns_addrinfo_get(Ecore_Con_DNS *dns, const char *addr, int port)
{
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;
}
static int
_ecore_con_dns_check(Ecore_Con_DNS *dns)
{
struct addrinfo *ent = NULL;
int error = 0;
error = dns_ai_nextent(&ent, dns->ai);
switch (error)
{
case 0:
break;
case EAGAIN:
return 1;
default:
DBG("resolve failed: %s", dns_strerror(error));
goto error;
}
{
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_del(dns);
}
return 0;
error:
dns->done_cb(dns->data, NULL);
_ecore_con_dns_del(dns);
return -1;
}
static Eina_Bool
_dns_fd_cb(Ecore_Con_DNS *dns, Ecore_Fd_Handler *fdh EINA_UNUSED)
{
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))
{
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
ecore_main_fd_handler_active_set(dns->fdh, dns_ai_events(dns->ai));
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_dns_timer_cb(Ecore_Con_DNS *dns)
{
dns->done_cb(dns->data, NULL);
_ecore_con_dns_del(dns);
return EINA_FALSE;
}
int
ecore_con_info_init(void)
{
int err;
if (_ecore_con_dns_init) return ++_ecore_con_dns_init;
resconf = dns_resconf_local(&err);
if (!resconf)
{
ERR("resconf_open: %s", dns_strerror(err));
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;
}
int
ecore_con_info_shutdown(void)
{
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;
}
void
ecore_con_info_data_clear(void *info)
{
if (info)
_ecore_con_dns_free(info);
}
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 *obj,
Ecore_Con_Info_Cb done_cb,
void *data,
struct addrinfo *hints)
{
Efl_Network_Server_Data *svr = eo_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS);
Ecore_Con_DNS *dns;
int error = 0;
if (!svr)
return 0;
dns = calloc(1, sizeof(Ecore_Con_DNS));
if (!dns) return 0;
dns->svr = obj;
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, svr->ecs ? svr->ecs->port : 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;
}

View File

@ -23,14 +23,21 @@
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef __OpenBSD__
# include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
@ -48,21 +55,20 @@ struct _CB_Data
EINA_INLIST;
Ecore_Con_Info_Cb cb_done;
void *data;
Ecore_Fd_Handler *fdh;
pid_t pid;
Ecore_Event_Handler *handler;
int fd2;
Ecore_Thread *thread;
struct addrinfo hints;
Ecore_Con_Info *result;
int error;
char service[NI_MAXSERV];
char name[NI_MAXHOST];
};
static void _ecore_con_info_readdata(CB_Data *cbdata);
static void _ecore_con_info_slave_free(CB_Data *cbdata);
static Eina_Bool _ecore_con_info_data_handler(void *data,
Ecore_Fd_Handler *fd_handler);
static Eina_Bool _ecore_con_info_exit_handler(void *data,
int type EINA_UNUSED,
void *event);
static void _ecore_con_info_slave_free (CB_Data *cbdata);
static void _ecore_con_info_slave_result(void *data, Ecore_Thread *th);
static void _ecore_con_info_slave_cancel(void *data, Ecore_Thread *th);
static void _ecore_con_info_slave_lookup(void *data, Ecore_Thread *th);
static int info_init = 0;
static int info_init = 0;
static CB_Data *info_slaves = NULL;
int
@ -77,28 +83,38 @@ ecore_con_info_shutdown(void)
{
info_init--;
if (info_init == 0)
while (info_slaves)
_ecore_con_info_slave_free(info_slaves);
{
while (info_slaves)
{
CB_Data *cbdata;
cbdata = info_slaves;
info_slaves = (CB_Data *)eina_inlist_remove
(EINA_INLIST_GET(info_slaves), EINA_INLIST_GET(info_slaves));
ecore_thread_cancel(cbdata->thread);
}
}
return info_init;
}
static void
_hints_fill(struct addrinfo *hints, int flags, int proto)
{
memset(hints, 0, sizeof(struct addrinfo));
hints->ai_family = AF_UNSPEC;
hints->ai_flags = flags;
if (proto == IPPROTO_TCP) hints->ai_socktype = SOCK_STREAM;
else hints->ai_socktype = SOCK_DGRAM;
hints->ai_protocol = proto;
}
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));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
_hints_fill(&hints, AI_CANONNAME, IPPROTO_TCP);
return ecore_con_info_get(svr, done_cb, data, &hints);
}
@ -108,16 +124,7 @@ ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
void *data)
{
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
_hints_fill(&hints, AI_PASSIVE, IPPROTO_TCP);
return ecore_con_info_get(svr, done_cb, data, &hints);
}
@ -127,16 +134,7 @@ ecore_con_info_udp_connect(Ecore_Con_Server *svr,
void *data)
{
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_CANONNAME;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
_hints_fill(&hints, AI_CANONNAME, IPPROTO_UDP);
return ecore_con_info_get(svr, done_cb, data, &hints);
}
@ -146,16 +144,7 @@ ecore_con_info_udp_listen(Ecore_Con_Server *svr,
void *data)
{
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
_hints_fill(&hints, AI_PASSIVE, IPPROTO_UDP);
return ecore_con_info_get(svr, done_cb, data, &hints);
}
@ -165,151 +154,44 @@ ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
void *data)
{
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
hints.ai_addr = NULL;
_hints_fill(&hints, 0, IPPROTO_UDP);
return ecore_con_info_get(svr, done_cb, data, &hints);
}
static void
_ecore_con_fd_close_on_exec(int fd)
{
#ifdef HAVE_FCNTL
int flags;
flags = fcntl(fd, F_GETFD);
if (flags == -1) return;
flags |= FD_CLOEXEC;
if (fcntl(fd, F_SETFD, flags) == -1) return;
#else
(void)fd;
#endif
}
EAPI int
ecore_con_info_get(Ecore_Con_Server *svr,
ecore_con_info_get(Ecore_Con_Server *obj,
Ecore_Con_Info_Cb done_cb,
void *data,
struct addrinfo *hints)
{
Efl_Network_Server_Data *svr = eo_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS);
CB_Data *cbdata;
int fd[2];
if (pipe(fd) < 0)
{
ecore_con_event_server_error(svr, strerror(errno));
return 0;
}
_ecore_con_fd_close_on_exec(fd[0]);
_ecore_con_fd_close_on_exec(fd[1]);
if (!svr) return 0;
cbdata = calloc(1, sizeof(CB_Data));
if (!cbdata)
{
close(fd[0]);
close(fd[1]);
ecore_con_event_server_error(obj, "Memory allocation failure");
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_info_data_handler,
cbdata,
NULL, NULL)))
cbdata->hints = *hints;
cbdata->thread = ecore_thread_run(_ecore_con_info_slave_lookup,
_ecore_con_info_slave_result,
_ecore_con_info_slave_cancel,
cbdata);
if (!cbdata->thread)
{
ecore_con_event_server_error(svr, "Memory allocation failure");
free(cbdata);
close(fd[0]);
close(fd[1]);
ecore_con_event_server_error(obj, "Memory allocation failure");
return 0;
}
if ((cbdata->pid = fork()) == 0)
{
Ecore_Con_Info *container;
struct addrinfo *result = NULL;
char service[NI_MAXSERV] = {0};
char hbuf[NI_MAXHOST] = {0};
char sbuf[NI_MAXSERV] = {0};
unsigned char *tosend = NULL;
int tosend_len;
int canonname_len = 0;
eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, service);
/* CHILD */
if (!getaddrinfo(svr->ecs ? svr->ecs->ip : svr->name, service, hints, &result) && result)
{
if (result->ai_canonname)
canonname_len = strlen(result->ai_canonname) + 1;
tosend_len = sizeof(Ecore_Con_Info) + result->ai_addrlen +
canonname_len;
tosend = alloca(tosend_len);
memset(tosend, 0, tosend_len);
container = (Ecore_Con_Info *)tosend;
container->size = tosend_len;
memcpy(&container->info,
result,
sizeof(struct addrinfo));
memcpy(tosend + sizeof(Ecore_Con_Info),
result->ai_addr,
result->ai_addrlen);
if (result->ai_canonname) /* FIXME: else... */
memcpy(tosend + sizeof(Ecore_Con_Info) + result->ai_addrlen,
result->ai_canonname,
canonname_len);
if (!getnameinfo(result->ai_addr, result->ai_addrlen,
hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV))
{
memcpy(container->ip, hbuf, sizeof(container->ip));
memcpy(container->service, sbuf, sizeof(container->service));
}
if (write(fd[1], tosend, tosend_len) < 0) perror("write");
}
if (result)
freeaddrinfo(result);
if (write(fd[1], "", 1) < 0) perror("write");
close(fd[1]);
#if defined(__USE_ISOC99) && !defined(__UCLIBC__)
_Exit(0);
#else
_exit(0);
#endif
}
/* PARENT */
cbdata->handler =
ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler,
cbdata);
close(fd[1]);
if (!cbdata->handler)
{
ecore_main_fd_handler_del(cbdata->fdh);
free(cbdata);
close(fd[0]);
return 0;
}
info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(
info_slaves),
eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, cbdata->service);
strncpy(cbdata->name, svr->ecs ? svr->ecs->ip : svr->name, NI_MAXHOST - 1);
cbdata->name[NI_MAXHOST - 1] = 0;
info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(info_slaves),
EINA_INLIST_GET(cbdata));
svr->infos = eina_list_append(svr->infos, cbdata);
return 1;
@ -322,128 +204,93 @@ ecore_con_info_data_clear(void *info)
cbdata->data = NULL;
}
static void
_ecore_con_info_readdata(CB_Data *cbdata)
{
Ecore_Con_Info container;
Ecore_Con_Info *recv_info;
unsigned char *torecv;
int torecv_len;
ssize_t size;
size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container,
sizeof(Ecore_Con_Info));
if (size == sizeof(Ecore_Con_Info))
{
torecv_len = container.size;
torecv = malloc(torecv_len);
memcpy(torecv, &container, sizeof(Ecore_Con_Info));
size = read(ecore_main_fd_handler_fd_get(cbdata->fdh),
torecv + sizeof(Ecore_Con_Info),
torecv_len - sizeof(Ecore_Con_Info));
if ((size > 0) &&
((size_t)size == torecv_len - sizeof(Ecore_Con_Info)))
{
recv_info = (Ecore_Con_Info *)torecv;
recv_info->info.ai_addr =
(struct sockaddr *)(torecv + sizeof(Ecore_Con_Info));
if ((size_t)torecv_len !=
(sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen))
recv_info->info.ai_canonname = (char *)
(torecv + sizeof(Ecore_Con_Info) + recv_info->info.ai_addrlen);
else
recv_info->info.ai_canonname = NULL;
recv_info->info.ai_next = NULL;
if (cbdata->data)
{
cbdata->cb_done(cbdata->data, recv_info);
ecore_con_server_infos_del(cbdata->data, cbdata);
}
free(torecv);
}
else
{
if (cbdata->data)
{
cbdata->cb_done(cbdata->data, NULL);
ecore_con_server_infos_del(cbdata->data, cbdata);
}
}
}
else
{
if (cbdata->data)
{
ecore_con_event_server_error(cbdata->data, strerror(errno));
cbdata->cb_done(cbdata->data, NULL);
ecore_con_server_infos_del(cbdata->data, cbdata);
}
}
cbdata->cb_done = NULL;
}
static void
_ecore_con_info_slave_free(CB_Data *cbdata)
{
info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves),
EINA_INLIST_GET(cbdata));
ecore_main_fd_handler_del(cbdata->fdh);
ecore_event_handler_del(cbdata->handler);
close(ecore_main_fd_handler_fd_get(cbdata->fdh));
if (cbdata->result) free(cbdata->result);
cbdata->result = NULL;
if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
cbdata->data = NULL;
free(cbdata);
}
static Eina_Bool
_ecore_con_info_data_handler(void *data,
Ecore_Fd_Handler *fd_handler)
static void
_ecore_con_info_slave_result(void *data, Ecore_Thread *th EINA_UNUSED)
{
CB_Data *cbdata;
CB_Data *cbdata = data;
cbdata = data;
if (cbdata->cb_done)
if (cbdata->result) // lookup ok
{
if (ecore_main_fd_handler_active_get(fd_handler,
ECORE_FD_READ))
_ecore_con_info_readdata(cbdata);
else
if (cbdata->data) cbdata->cb_done(cbdata->data, cbdata->result);
}
else // an error occured
{
if (cbdata->data)
{
if (cbdata->data)
{
cbdata->cb_done(cbdata->data, NULL);
cbdata->cb_done = NULL;
ecore_con_server_infos_del(cbdata->data, cbdata);
}
char *str = strerror(cbdata->error);
ecore_con_event_server_error(cbdata->data, str);
cbdata->cb_done(cbdata->data, NULL);
}
}
if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata);
cbdata->data = NULL;
_ecore_con_info_slave_free(cbdata);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_ecore_con_info_exit_handler(void *data,
int type EINA_UNUSED,
void *event)
static void
_ecore_con_info_slave_cancel(void *data, Ecore_Thread *th EINA_UNUSED)
{
CB_Data *cbdata;
Ecore_Exe_Event_Del *ev;
ev = event;
cbdata = data;
if (cbdata->pid != ev->pid)
return ECORE_CALLBACK_RENEW;
return ECORE_CALLBACK_CANCEL; /* FIXME: Woot ??? */
CB_Data *cbdata = data;
_ecore_con_info_slave_free(cbdata);
return ECORE_CALLBACK_CANCEL;
}
static void
_ecore_con_info_slave_lookup(void *data, Ecore_Thread *th EINA_UNUSED)
{
CB_Data *cbdata = data;
struct addrinfo *result = NULL;
// do lookup, fill cbdata
if ((!getaddrinfo(cbdata->name, cbdata->service, &(cbdata->hints), &result))
&& (result))
{
Ecore_Con_Info *info;
unsigned int canonname_size = 0, size;
if (result->ai_canonname)
canonname_size = strlen(result->ai_canonname) + 1;
size = sizeof(Ecore_Con_Info) + result->ai_addrlen + canonname_size;
info = calloc(1, size);
if (info)
{
char hbuf[NI_MAXHOST] = { 0 }, sbuf[NI_MAXSERV] = { 0 }, *p;
info->size = size;
memcpy(&(info->info), result, sizeof(struct addrinfo));
p = ((char *)info) + sizeof(Ecore_Con_Info);
memcpy(p, result->ai_addr, result->ai_addrlen);
info->info.ai_addr = (struct sockaddr *)p;
if (result->ai_canonname)
{
p = ((char *)info) + sizeof(Ecore_Con_Info) + result->ai_addrlen;
memcpy(p, result->ai_canonname, canonname_size);
info->info.ai_canonname = p;
}
// we don't care about multiple entries - take first one then
info->info.ai_next = NULL;
if (!getnameinfo(result->ai_addr, result->ai_addrlen,
hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
NI_NUMERICHOST | NI_NUMERICSERV))
{
memcpy(info->ip, hbuf, sizeof(info->ip));
memcpy(info->service, sbuf, sizeof(info->service));
}
cbdata->result = info;
}
if (!cbdata->result) free(info);
}
if (!cbdata->result) cbdata->error = errno;
if (result) freeaddrinfo(result);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff