efl_net: optimize serving of IP addresses.

If we can parse the IP using inet_pton() and the port, there is no
reason to call getaddrinfo() in a thread.

This is required since ecore_con_suite (for ecore_con-over-efl_net) will
assume the server is running as soon as it's created.
This commit is contained in:
Gustavo Sverzut Barbieri 2016-12-09 11:42:17 -02:00
parent 83cbcf7cb5
commit afdbe897a0
4 changed files with 115 additions and 57 deletions

View File

@ -3085,6 +3085,69 @@ efl_net_unix_fmt(char *buf, size_t buflen, SOCKET fd, const struct sockaddr_un *
}
#endif
/* The reverse of efl_net_ip_port_fmt().
*
* If was parsed, then returns EINA_TRUE, otherwise use getaddrinfo()
* or efl_net_ip_resolve_async_new().
*/
Eina_Bool
efl_net_ip_port_parse(const char *address, struct sockaddr_storage *storage)
{
char *str;
const char *host, *port;
Eina_Bool ret;
str = strdup(address);
EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
if (!efl_net_ip_port_split(str, &host, &port))
{
ERR("invalid IP:PORT address: %s", address);
ret = EINA_FALSE;
}
else
ret = efl_net_ip_port_parse_split(host, port, storage);
free(str);
return ret;
}
Eina_Bool
efl_net_ip_port_parse_split(const char *host, const char *port, struct sockaddr_storage *storage)
{
int x;
char *endptr;
unsigned long p;
if (!port) port = "0";
if (strchr(host, ':')) storage->ss_family = AF_INET6;
else storage->ss_family = AF_INET;
errno = 0;
p = strtoul(port, &endptr, 10);
if ((errno) || (endptr == port) || (*endptr != '\0')) return EINA_FALSE;
else if (p > UINT16_MAX)
{
ERR("invalid port number %lu (out of range)", p);
return EINA_FALSE;
}
if (storage->ss_family == AF_INET6)
{
struct sockaddr_in6 *a = (struct sockaddr_in6 *)storage;
a->sin6_port = htons(p);
x = inet_pton(AF_INET6, host, &a->sin6_addr);
}
else
{
struct sockaddr_in *a = (struct sockaddr_in *)storage;
a->sin_port = htons(p);
x = inet_pton(AF_INET, host, &a->sin_addr);
}
return x == 1;
}
Eina_Bool
efl_net_ip_port_fmt(char *buf, size_t buflen, const struct sockaddr *addr)
{
@ -3262,62 +3325,20 @@ efl_net_ip_socket_activate_check(const char *address, int family, int type, Eina
}
if (!port) port = "0";
if ((family == AF_UNSPEC) && (strchr(host, ':'))) family = AF_INET6;
if (family == AF_INET6)
if (efl_net_ip_port_parse_split(host, port, &want_addr))
{
struct sockaddr_in6 *a = (struct sockaddr_in6 *)&want_addr;
x = inet_pton(AF_INET6, host, &a->sin6_addr);
}
else
{
struct sockaddr_in *a = (struct sockaddr_in *)&want_addr;
x = inet_pton(AF_INET, host, &a->sin_addr);
}
/* FAST PATH: numbers were provided */
if (x == 1)
{
char *endptr;
unsigned long p;
Eina_Bool matches;
want_addr.ss_family = family;
if (want_addr.ss_family != sock_addr.ss_family)
{
ERR("socket " SOCKET_FMT " family=%d differs from wanted %d", fd, sock_addr.ss_family, want_addr.ss_family);
free(str);
return EINVAL;
}
errno = 0;
p = strtoul(port, &endptr, 10);
if ((errno) || (endptr == port) || (*endptr != '\0'))
{
ERR("invalid port number '%s'", port);
free(str);
return EINVAL;
}
else if (p > UINT16_MAX)
{
ERR("invalid port number %lu (out of range)", p);
free(str);
return ERANGE;
}
if (family == AF_INET6)
{
struct sockaddr_in6 *a = (struct sockaddr_in6 *)&want_addr;
a->sin6_port = htons(p);
matches = memcmp(a, &sock_addr, sizeof(*a)) == 0;
}
else if (want_addr.ss_family == AF_INET6)
matches = memcmp(&want_addr, &sock_addr, sizeof(struct sockaddr_in6)) == 0;
else
{
struct sockaddr_in *a = (struct sockaddr_in *)&want_addr;
x = inet_pton(AF_INET, host, &a->sin_addr);
a->sin_port = htons(p);
matches = memcmp(a, &sock_addr, sizeof(*a)) == 0;
}
matches = memcmp(&want_addr, &sock_addr, sizeof(struct sockaddr_in)) == 0;
if (!matches)
{

View File

@ -447,6 +447,8 @@ void _efl_net_socket_udp_init(Eo *o, const struct sockaddr *addr, socklen_t addr
#ifndef _WIN32
Eina_Bool efl_net_unix_fmt(char *buf, size_t buflen, SOCKET fd, const struct sockaddr_un *addr, socklen_t addrlen);
#endif
Eina_Bool efl_net_ip_port_parse(const char *address, struct sockaddr_storage *storage);
Eina_Bool efl_net_ip_port_parse_split(const char *host, const char *port, struct sockaddr_storage *storage);
Eina_Bool efl_net_ip_port_fmt(char *buf, size_t buflen, const struct sockaddr *addr);
#ifdef HAVE_SYSTEMD

View File

@ -223,6 +223,8 @@ _efl_net_server_tcp_efl_net_server_serve(Eo *o, Efl_Net_Server_Tcp_Data *pd, con
.ai_family = AF_UNSPEC,
.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED,
};
struct sockaddr_storage ss;
Eina_Error err;
EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
@ -233,13 +235,28 @@ _efl_net_server_tcp_efl_net_server_serve(Eo *o, Efl_Net_Server_Tcp_Data *pd, con
return EINVAL;
}
if (!port) port = "0";
if (strchr(host, ':')) hints.ai_family = AF_INET6;
pd->resolver = efl_net_ip_resolve_async_new(host, port, &hints,
_efl_net_server_tcp_resolved, o);
free(str);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->resolver, EINVAL);
return 0;
if (efl_net_ip_port_parse_split(host, port, &ss))
{
struct addrinfo ai = hints;
ai.ai_family = ss.ss_family;
ai.ai_addr = (struct sockaddr *)&ss;
ai.ai_addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
err = _efl_net_server_tcp_resolved_bind(o, pd, &ai);
free(str);
}
else
{
pd->resolver = efl_net_ip_resolve_async_new(host, port, &hints,
_efl_net_server_tcp_resolved, o);
free(str);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->resolver, EINVAL);
err = 0;
}
return err;
}
static void

View File

@ -259,6 +259,8 @@ _efl_net_server_udp_efl_net_server_serve(Eo *o, Efl_Net_Server_Udp_Data *pd, con
.ai_family = AF_UNSPEC,
.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED,
};
struct sockaddr_storage ss;
Eina_Error err;
EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
@ -271,11 +273,27 @@ _efl_net_server_udp_efl_net_server_serve(Eo *o, Efl_Net_Server_Udp_Data *pd, con
if (!port) port = "0";
if (strchr(host, ':')) hints.ai_family = AF_INET6;
pd->resolver = efl_net_ip_resolve_async_new(host, port, &hints,
_efl_net_server_udp_resolved, o);
free(str);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->resolver, EINVAL);
return 0;
if (efl_net_ip_port_parse_split(host, port, &ss))
{
struct addrinfo ai = hints;
ai.ai_family = ss.ss_family;
ai.ai_addr = (struct sockaddr *)&ss;
ai.ai_addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
err = _efl_net_server_udp_resolved_bind(o, pd, &ai);
free(str);
}
else
{
pd->resolver = efl_net_ip_resolve_async_new(host, port, &hints,
_efl_net_server_udp_resolved, o);
free(str);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->resolver, EINVAL);
err = 0;
}
return err;
}
static void