From e3ee477140bb760dfffc8e32c0a3e9a961664c3d Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Wed, 24 Aug 2016 12:34:59 -0300 Subject: [PATCH] efl_net: better handling for SOCK_CLOEXEC. On systems where SOCK_CLOEXEC is supported, give it to socket() and if accept4() is supported, then use it as well. Otherwise revert to fcntl(). --- src/lib/ecore_con/ecore_con.c | 29 +++++++++++++++++ src/lib/ecore_con/ecore_con_private.h | 2 ++ src/lib/ecore_con/efl_net_dialer_tcp.c | 11 +++---- src/lib/ecore_con/efl_net_server_fd.c | 43 +++++++++++++++++--------- src/lib/ecore_con/efl_net_server_tcp.c | 12 +++---- 5 files changed, 69 insertions(+), 28 deletions(-) diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c index e040a71a75..8340c3d463 100644 --- a/src/lib/ecore_con/ecore_con.c +++ b/src/lib/ecore_con/ecore_con.c @@ -3036,3 +3036,32 @@ efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr) return EINA_TRUE; } + +int +efl_net_socket4(int domain, int type, int protocol, Eina_Bool close_on_exec) +{ + int fd; + +#ifdef SOCK_CLOEXEC + if (close_on_exec) type |= SOCK_CLOEXEC; +#endif + + fd = socket(domain, type, protocol); + if (fd < 0) return fd; + +#ifndef SOCK_CLOEXEC + if (close_on_exec) + { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) + { + int errno_bkp = errno; + ERR("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", fd, strerror(errno)); + close(fd); + errno = errno_bkp; + return -1; + } + } +#endif + + return fd; +} diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h index 089f864ca5..e2fab7a506 100644 --- a/src/lib/ecore_con/ecore_con_private.h +++ b/src/lib/ecore_con/ecore_con_private.h @@ -375,4 +375,6 @@ void ecore_con_mempool_shutdown(void); Eina_Bool efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr); +int efl_net_socket4(int domain, int type, int protocol, Eina_Bool close_on_exec); + #endif diff --git a/src/lib/ecore_con/efl_net_dialer_tcp.c b/src/lib/ecore_con/efl_net_dialer_tcp.c index b835d93f02..88f78fe971 100644 --- a/src/lib/ecore_con/efl_net_dialer_tcp.c +++ b/src/lib/ecore_con/efl_net_dialer_tcp.c @@ -51,7 +51,7 @@ _efl_net_dialer_tcp_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Tcp_Data *pd EINA_ { struct sockaddr_storage addr = {}; char *str, *host, *port; - int r, fd, extra_flags = 0; + int r, fd; socklen_t addrlen; char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")]; @@ -118,14 +118,11 @@ _efl_net_dialer_tcp_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Tcp_Data *pd EINA_ efl_event_callback_call(o, EFL_NET_DIALER_EVENT_RESOLVED, NULL); } - if (efl_net_socket_fd_close_on_exec_get(o)) - extra_flags |= SOCK_CLOEXEC; - - fd = socket(addr.ss_family, SOCK_STREAM | extra_flags, IPPROTO_TCP); + fd = efl_net_socket4(addr.ss_family, SOCK_STREAM, IPPROTO_TCP, efl_net_socket_fd_close_on_exec_get(o)); if (fd < 0) { - ERR("socket(%d, SOCK_STREAM | %#x, IPPROTO_TCP): %s", - addr.ss_family, extra_flags, strerror(errno)); + ERR("socket(%d, SOCK_STREAM, IPPROTO_TCP): %s", + addr.ss_family, strerror(errno)); return errno; } diff --git a/src/lib/ecore_con/efl_net_server_fd.c b/src/lib/ecore_con/efl_net_server_fd.c index 06af641fb7..0365669dc1 100644 --- a/src/lib/ecore_con/efl_net_server_fd.c +++ b/src/lib/ecore_con/efl_net_server_fd.c @@ -32,6 +32,32 @@ typedef struct _Efl_Net_Server_Fd_Data Eina_Bool reuse_port; } Efl_Net_Server_Fd_Data; +static int +efl_net_accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, Eina_Bool close_on_exec) +{ +#ifdef HAVE_ACCEPT4 + int flags = 0; + if (close_on_exec) flags |= SOCK_CLOEXEC; + return accept4(fd, addr, addrlen, flags); +#else + int client = accept(fd, addr, addrlen); + if (client < 0) return client; + + if (close_on_exec) + { + if (fcntl(client, F_SETFD, FD_CLOEXEC) < 0) + { + int errno_bkp = errno; + ERR("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", client, strerror(errno)); + close(client); + errno = errno_bkp; + return -1; + } + } + return client; +#endif +} + static void _efl_net_server_fd_event_read(void *data EINA_UNUSED, const Eo_Event *event) { @@ -39,7 +65,7 @@ _efl_net_server_fd_event_read(void *data EINA_UNUSED, const Eo_Event *event) unsigned int count, limit; Eina_Bool reject_excess, do_reject = EINA_FALSE; struct sockaddr_storage addr; - int client, fd, flags = 0; + int client, fd; socklen_t addrlen; count = efl_net_server_clients_count_get(o); @@ -57,15 +83,9 @@ _efl_net_server_fd_event_read(void *data EINA_UNUSED, const Eo_Event *event) fd = efl_loop_fd_get(o); - if (efl_net_server_fd_close_on_exec_get(o)) - flags |= SOCK_CLOEXEC; - addrlen = sizeof(addr); -#ifdef HAVE_ACCEPT4 - client = accept4(fd, (struct sockaddr *)&addr, &addrlen, flags); -#else - client = accept(fd, (struct sockaddr *)&addr, &addrlen); -#endif + client = efl_net_accept4(fd, (struct sockaddr *)&addr, &addrlen, + efl_net_server_fd_close_on_exec_get(o)); if (client < 0) { Eina_Error err = errno; @@ -74,11 +94,6 @@ _efl_net_server_fd_event_read(void *data EINA_UNUSED, const Eo_Event *event) return; } -#ifndef HAVE_ACCEPT4 - if (fcntl(fd, F_SETFD, flags) < 0) - ERR("fcntl(%d, F_SETFD, %#x): %s", fd, flags, strerror(errno)); -#endif - if (do_reject) efl_net_server_fd_client_reject(o, client); else diff --git a/src/lib/ecore_con/efl_net_server_tcp.c b/src/lib/ecore_con/efl_net_server_tcp.c index 25bfb01aef..b904cbba84 100644 --- a/src/lib/ecore_con/efl_net_server_tcp.c +++ b/src/lib/ecore_con/efl_net_server_tcp.c @@ -34,7 +34,7 @@ _efl_net_server_tcp_efl_net_server_serve(Eo *o, void *pd EINA_UNUSED, const char { struct sockaddr_storage addr = {}; char *str, *host, *port; - int r, fd, extra_flags = 0; + int r, fd; socklen_t addrlen; char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")]; Eina_Error err = 0; @@ -97,15 +97,13 @@ _efl_net_server_tcp_efl_net_server_serve(Eo *o, void *pd EINA_UNUSED, const char if (efl_net_ip_port_fmt(buf, sizeof(buf), (struct sockaddr *)&addr)) efl_net_server_address_set(o, buf); - if (efl_net_server_fd_close_on_exec_get(o)) - extra_flags |= SOCK_CLOEXEC; - - fd = socket(addr.ss_family, SOCK_STREAM | extra_flags, IPPROTO_TCP); + fd = efl_net_socket4(addr.ss_family, SOCK_STREAM, IPPROTO_TCP, + efl_net_server_fd_close_on_exec_get(o)); if (fd < 0) { err = errno; - ERR("socket(%d, SOCK_STREAM | %#x, IPPROTO_TCP): %s", - addr.ss_family, extra_flags, strerror(errno)); + ERR("socket(%d, SOCK_STREAM, IPPROTO_TCP): %s", + addr.ss_family, strerror(errno)); goto error_socket; }