raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=b22b2ded1d72e63f7e3c3be425e973e6d8d3fb6c

commit b22b2ded1d72e63f7e3c3be425e973e6d8d3fb6c
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
Date:   Wed Dec 20 21:10:53 2017 +0900

    ecore_con: bug workaround SO_REUSEADDR and EADDRINUSE from bind (fix)
    
    what i'm seeing is this with local unix sockets:
    
    1. server process not cleanly shut down (kill -9 for example).
    2. run server process again and bind fails due to EADDRINUSE
    3. we ARE doing setsockopt() with SO_REUSEADDR set to 1 ...
    
    this just makes no sense because setsockopt() SHOULD allow use to
    re-use... the previous efreetd process for example is gone. no such
    process, yet socket is not re-usable. this should just not happen due
    to SO_REUSEADDR, but it does. this has nasty consequences like efreetd
    maybe never running because of stale sockets. this should never have
    happened, but it does. odd. so a hacky workaround:
    
    1. try bind.
    2. if bind fails with EADDRINUSE and its a socket path AND
    pd->unlink_before_bind is NOT set... then try a connect to the socket.
    3. if connect succeeds then fail as normal (close socket and error on
    bind'ing)
       if connect fails then we have a stale socket, so unlink it
    forcibly. create the socket again and try bind again.
    
    hacky but... fixes the core issue.
    
    @fix
---
 src/lib/ecore_con/efl_net_server_unix.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/lib/ecore_con/efl_net_server_unix.c 
b/src/lib/ecore_con/efl_net_server_unix.c
index b1a1d2d158..65f2b255e1 100644
--- a/src/lib/ecore_con/efl_net_server_unix.c
+++ b/src/lib/ecore_con/efl_net_server_unix.c
@@ -50,7 +50,7 @@ _efl_net_server_unix_bind(Eo *o, Efl_Net_Server_Unix_Data *pd)
    const char *address = efl_net_server_address_get(o);
    struct sockaddr_un addr = { .sun_family = AF_UNIX };
    socklen_t addrlen;
-   SOCKET fd;
+   SOCKET fd = INVALID_SOCKET;
    Eina_Error err = 0;
    int r;
 
@@ -108,6 +108,17 @@ _efl_net_server_unix_bind(Eo *o, Efl_Net_Server_Unix_Data 
*pd)
              if ((err == EADDRINUSE) && (pd->unlink_before_bind) && 
(addr.sun_path[0] != '\0'))
                {
                   closesocket(fd);
+                  fd = INVALID_SOCKET;
+                  err = 0;
+                  continue;
+               }
+             if ((err == EADDRINUSE) && (addr.sun_path[0] != '\0') &&
+                 (connect(fd, (struct sockaddr *)&addr, addrlen) != 0))
+               {
+                  DBG("bind(" SOCKET_FMT ", %s): failed with EADDRINUSE but 
connect also failed, so unlink socket file and try again", fd, address);
+                  closesocket(fd);
+                  unlink(addr.sun_path);
+                  fd = INVALID_SOCKET;
                   err = 0;
                   continue;
                }
@@ -118,6 +129,7 @@ _efl_net_server_unix_bind(Eo *o, Efl_Net_Server_Unix_Data 
*pd)
      }
    while (pd->unlink_before_bind);
 
+   if (fd == INVALID_SOCKET) goto error;
    efl_loop_fd_set(o, fd);
 
    r = listen(fd, 0);

-- 


Reply via email to