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
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;
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;
}
}
while (pd->unlink_before_bind);
+ if (fd == INVALID_SOCKET) goto error;
efl_loop_fd_set(o, fd);
r = listen(fd, 0);