forked from enlightenment/efl
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:
parent
6e23780bb1
commit
1eba9d9de0
20
configure.ac
20
configure.ac
|
@ -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])
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue