sock: properly detect closed sockets when EPOLLONESHOT is set
This commit is contained in:
parent
35b2354413
commit
ddb8bfc9d6
31
src/sock.c
31
src/sock.c
@ -36,12 +36,9 @@ typedef struct _ep_sock_private {
|
||||
} _ep_sock_private_t;
|
||||
|
||||
static DWORD _epoll_events_to_afd_events(uint32_t epoll_events) {
|
||||
DWORD afd_events;
|
||||
|
||||
/* These events should always be monitored. */
|
||||
assert(epoll_events & EPOLLERR);
|
||||
assert(epoll_events & EPOLLHUP);
|
||||
afd_events = AFD_POLL_ABORT | AFD_POLL_CONNECT_FAIL | AFD_POLL_LOCAL_CLOSE;
|
||||
/* Always monitor for AFD_POLL_LOCAL_CLOSE, which is triggered when the
|
||||
* socket is closed with closesocket() or CloseHandle(). */
|
||||
DWORD afd_events = AFD_POLL_LOCAL_CLOSE;
|
||||
|
||||
if (epoll_events & (EPOLLIN | EPOLLRDNORM))
|
||||
afd_events |= AFD_POLL_RECEIVE | AFD_POLL_ACCEPT;
|
||||
@ -51,6 +48,10 @@ static DWORD _epoll_events_to_afd_events(uint32_t epoll_events) {
|
||||
afd_events |= AFD_POLL_SEND | AFD_POLL_CONNECT;
|
||||
if (epoll_events & (EPOLLIN | EPOLLRDNORM | EPOLLRDHUP))
|
||||
afd_events |= AFD_POLL_DISCONNECT;
|
||||
if (epoll_events & EPOLLHUP)
|
||||
afd_events |= AFD_POLL_ABORT;
|
||||
if (epoll_events & EPOLLERR)
|
||||
afd_events |= AFD_POLL_CONNECT_FAIL;
|
||||
|
||||
return afd_events;
|
||||
}
|
||||
@ -235,7 +236,9 @@ int ep_sock_set_event(ep_port_t* port_info,
|
||||
const struct epoll_event* ev) {
|
||||
_ep_sock_private_t* sock_private = _ep_sock_private(sock_info);
|
||||
|
||||
/* EPOLLERR and EPOLLHUP are always reported, even when no sollicited. */
|
||||
/* EPOLLERR and EPOLLHUP are always reported, even when not requested by the
|
||||
* caller. However they are disabled after a event has been reported for a
|
||||
* socket for which the EPOLLONESHOT flag as set. */
|
||||
uint32_t events = ev->events | EPOLLERR | EPOLLHUP;
|
||||
|
||||
sock_private->user_events = events;
|
||||
@ -250,7 +253,7 @@ int ep_sock_set_event(ep_port_t* port_info,
|
||||
int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) {
|
||||
_ep_sock_private_t* sock_private = _ep_sock_private(sock_info);
|
||||
SOCKET driver_socket = poll_group_get_socket(sock_private->poll_group);
|
||||
bool broken = false;
|
||||
bool socket_closed = false;
|
||||
|
||||
assert(ep_port_is_socket_update_pending(port_info, sock_info));
|
||||
|
||||
@ -283,7 +286,7 @@ int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) {
|
||||
driver_socket) < 0) {
|
||||
if (GetLastError() == ERROR_INVALID_HANDLE)
|
||||
/* The socket is broken. It will be dropped from the epoll set. */
|
||||
broken = true;
|
||||
socket_closed = true;
|
||||
else
|
||||
/* Another error occurred, which is propagated to the caller. */
|
||||
return -1;
|
||||
@ -301,7 +304,7 @@ int ep_sock_update(ep_port_t* port_info, ep_sock_t* sock_info) {
|
||||
ep_port_clear_socket_update(port_info, sock_info);
|
||||
|
||||
/* If we saw an ERROR_INVALID_HANDLE error, drop the socket. */
|
||||
if (broken)
|
||||
if (socket_closed)
|
||||
ep_sock_delete(port_info, sock_info);
|
||||
|
||||
return 0;
|
||||
@ -314,7 +317,7 @@ int ep_sock_feed_event(ep_port_t* port_info,
|
||||
container_of(overlapped, _ep_sock_private_t, poll_req.overlapped);
|
||||
ep_sock_t* sock_info = &sock_private->pub;
|
||||
uint32_t epoll_events;
|
||||
bool drop_socket;
|
||||
bool socket_closed;
|
||||
int ev_count = 0;
|
||||
|
||||
sock_private->poll_status = _POLL_IDLE;
|
||||
@ -327,7 +330,7 @@ int ep_sock_feed_event(ep_port_t* port_info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
_poll_req_complete(&sock_private->poll_req, &epoll_events, &drop_socket);
|
||||
_poll_req_complete(&sock_private->poll_req, &epoll_events, &socket_closed);
|
||||
|
||||
/* Filter events that the user didn't ask for. */
|
||||
epoll_events &= sock_private->user_events;
|
||||
@ -344,10 +347,10 @@ int ep_sock_feed_event(ep_port_t* port_info,
|
||||
ev_count = 1;
|
||||
}
|
||||
|
||||
if (drop_socket)
|
||||
if (socket_closed)
|
||||
/* Drop the socket from the epoll set. */
|
||||
ep_sock_delete(port_info, sock_info);
|
||||
else if (sock_private->user_events != 0)
|
||||
else
|
||||
/* Put the socket back onto the attention list so a new poll request will
|
||||
* be submitted. */
|
||||
ep_port_request_socket_update(port_info, sock_info);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user