From afdbe897a0cc46a3ae945110e83323d40c1ecc8e Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Fri, 9 Dec 2016 11:42:17 -0200 Subject: [PATCH] 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. --- src/lib/ecore_con/ecore_con.c | 113 +++++++++++++++---------- src/lib/ecore_con/ecore_con_private.h | 2 + src/lib/ecore_con/efl_net_server_tcp.c | 29 +++++-- src/lib/ecore_con/efl_net_server_udp.c | 28 ++++-- 4 files changed, 115 insertions(+), 57 deletions(-) diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c index 7b613715cc..84f639d85f 100644 --- a/src/lib/ecore_con/ecore_con.c +++ b/src/lib/ecore_con/ecore_con.c @@ -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) { diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h index bf70f64292..9db016b003 100644 --- a/src/lib/ecore_con/ecore_con_private.h +++ b/src/lib/ecore_con/ecore_con_private.h @@ -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 diff --git a/src/lib/ecore_con/efl_net_server_tcp.c b/src/lib/ecore_con/efl_net_server_tcp.c index bdb081233e..93d502416c 100644 --- a/src/lib/ecore_con/efl_net_server_tcp.c +++ b/src/lib/ecore_con/efl_net_server_tcp.c @@ -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 diff --git a/src/lib/ecore_con/efl_net_server_udp.c b/src/lib/ecore_con/efl_net_server_udp.c index 4b297939ae..27928e02cd 100644 --- a/src/lib/ecore_con/efl_net_server_udp.c +++ b/src/lib/ecore_con/efl_net_server_udp.c @@ -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