|
@@ -13432,8 +13432,14 @@ inline bool Server::listen_internal() {
|
|
|
} else if (errno == EINTR || errno == EAGAIN) {
|
|
} else if (errno == EINTR || errno == EAGAIN) {
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
- if (svr_sock_ != INVALID_SOCKET) {
|
|
|
|
|
- detail::close_socket(svr_sock_);
|
|
|
|
|
|
|
+ // Take the descriptor out of svr_sock_ before closing it: a later
|
|
|
|
|
+ // stop() would otherwise shutdown()/close() a value the OS may have
|
|
|
|
|
+ // reused, and keep_alive() watches svr_sock_ to notice the server is
|
|
|
|
|
+ // gone. The exchange also settles the race with a concurrent stop(),
|
|
|
|
|
+ // since whichever side takes the descriptor closes it exactly once.
|
|
|
|
|
+ auto listen_sock = svr_sock_.exchange(INVALID_SOCKET);
|
|
|
|
|
+ if (listen_sock != INVALID_SOCKET) {
|
|
|
|
|
+ detail::close_socket(listen_sock);
|
|
|
ret = false;
|
|
ret = false;
|
|
|
output_error_log(Error::Connection, nullptr);
|
|
output_error_log(Error::Connection, nullptr);
|
|
|
} else {
|
|
} else {
|