From: Carsten Haitzler (Rasterman) Date: Wed, 20 Dec 2017 12:10:53 +0000 (+0900) Subject: ecore_con: bug workaround SO_REUSEADDR and EADDRINUSE from bind (fix) X-Git-Tag: submit/sandbox/upgrade/efl120/20180319.053334~555 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=eab194a34fb3ba38228c9fc65a98b58bb39cf32a;p=platform%2Fupstream%2Fefl.git 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 --- diff --git a/src/lib/ecore_con/efl_net_server_unix.c b/src/lib/ecore_con/efl_net_server_unix.c index b1a1d2d..65f2b25 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);