Skip to content

Commit 9a5d720

Browse files
committed
win,tcp: make uv_close work like unix
The comment here seems mixed up between send and recv buffers. The default behavior on calling `closesocket` is already to do a graceful shutdown (see https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-closesocket with default l_onoff=zero) if it is the last open handle. The expect behavior if there are pending reads in flight is to send an RST packet, notifying the client that the server connection was destroyed before acknowledging the EOF. Refs: libuv#3035 Refs: nodejs/node#35946 Refs: nodejs/node#35904 Fixes: libuv#3034 PR-URL:
1 parent 11dd3b4 commit 9a5d720

1 file changed

Lines changed: 23 additions & 45 deletions

File tree

src/win/tcp.c

Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
237237
handle->reqs_pending == 0) {
238238
assert(!(handle->flags & UV_HANDLE_CLOSED));
239239

240-
if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
241-
closesocket(handle->socket);
242-
handle->socket = INVALID_SOCKET;
243-
handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
244-
}
240+
assert(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED);
245241

246242
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
247243
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
@@ -1442,48 +1438,32 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
14421438
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
14431439
int close_socket = 1;
14441440

1445-
if (tcp->flags & UV_HANDLE_READ_PENDING) {
1446-
/* In order for winsock to do a graceful close there must not be any any
1447-
* pending reads, or the socket must be shut down for writing */
1448-
if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
1449-
/* Just do shutdown on non-shared sockets, which ensures graceful close. */
1450-
shutdown(tcp->socket, SD_SEND);
1451-
1452-
} else if (uv_tcp_try_cancel_io(tcp) == 0) {
1453-
/* In case of a shared socket, we try to cancel all outstanding I/O,. If
1454-
* that works, don't close the socket yet - wait for the read req to
1455-
* return and close the socket in uv_tcp_endgame. */
1456-
close_socket = 0;
1457-
1458-
} else {
1459-
/* When cancelling isn't possible - which could happen when an LSP is
1460-
* present on an old Windows version, we will have to close the socket
1461-
* with a read pending. That is not nice because trailing sent bytes may
1462-
* not make it to the other side. */
1463-
}
1464-
1465-
} else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
1466-
tcp->tcp.serv.accept_reqs != NULL) {
1441+
if (tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) {
14671442
/* Under normal circumstances closesocket() will ensure that all pending
14681443
* accept reqs are canceled. However, when the socket is shared the
14691444
* presence of another reference to the socket in another process will keep
14701445
* the accept reqs going, so we have to ensure that these are canceled. */
1471-
if (uv_tcp_try_cancel_io(tcp) != 0) {
1472-
/* When cancellation is not possible, there is another option: we can
1473-
* close the incoming sockets, which will also cancel the accept
1474-
* operations. However this is not cool because we might inadvertently
1475-
* close a socket that just accepted a new connection, which will cause
1476-
* the connection to be aborted. */
1477-
unsigned int i;
1478-
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
1479-
uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
1480-
if (req->accept_socket != INVALID_SOCKET &&
1481-
!HasOverlappedIoCompleted(&req->u.io.overlapped)) {
1482-
closesocket(req->accept_socket);
1483-
req->accept_socket = INVALID_SOCKET;
1446+
if (tcp->tcp.serv.accept_reqs != NULL) {
1447+
if (uv_tcp_try_cancel_io(tcp) != 0) {
1448+
/* When cancellation is not possible, there is another option: we can
1449+
* close the incoming sockets, which will also cancel the accept
1450+
* operations. However this is not cool because we might inadvertently
1451+
* close a socket that just accepted a new connection, which will cause
1452+
* the connection to be aborted. */
1453+
unsigned int i;
1454+
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
1455+
uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
1456+
if (req->accept_socket != INVALID_SOCKET &&
1457+
!HasOverlappedIoCompleted(&req->u.io.overlapped)) {
1458+
closesocket(req->accept_socket);
1459+
req->accept_socket = INVALID_SOCKET;
1460+
}
14841461
}
14851462
}
14861463
}
1464+
else if (tcp->flags & UV_HANDLE_READ_PENDING) {
1465+
uv_tcp_try_cancel_io(tcp);
1466+
}
14871467
}
14881468

14891469
if (tcp->flags & UV_HANDLE_READING) {
@@ -1496,11 +1476,9 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
14961476
DECREASE_ACTIVE_COUNT(loop, tcp);
14971477
}
14981478

1499-
if (close_socket) {
1500-
closesocket(tcp->socket);
1501-
tcp->socket = INVALID_SOCKET;
1502-
tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
1503-
}
1479+
closesocket(tcp->socket);
1480+
tcp->socket = INVALID_SOCKET;
1481+
tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
15041482

15051483
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
15061484
uv__handle_closing(tcp);

0 commit comments

Comments
 (0)