summaryrefslogtreecommitdiff
path: root/deps/uv/src/win/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'deps/uv/src/win/tcp.c')
-rw-r--r--deps/uv/src/win/tcp.c65
1 files changed, 41 insertions, 24 deletions
diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c
index ccd7a11e2c..a213ad63e7 100644
--- a/deps/uv/src/win/tcp.c
+++ b/deps/uv/src/win/tcp.c
@@ -156,6 +156,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
handle->func_acceptex = NULL;
handle->func_connectex = NULL;
handle->processed_accepts = 0;
+ handle->delayed_error = 0;
return 0;
}
@@ -235,6 +236,17 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
}
+/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
+ * allow binding to addresses that are in use by sockets in TIME_WAIT, it
+ * effectively allows 'stealing' a port which is in use by another application.
+ *
+ * SO_EXCLUSIVEADDRUSE is also not good here because it does cehck all sockets,
+ * regardless of state, so we'd get an error even if the port is in use by a
+ * socket in TIME_WAIT state.
+ *
+ * See issue #1360.
+ *
+ */
static int uv_tcp_try_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
@@ -291,8 +303,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
err = WSAGetLastError();
if (err == WSAEADDRINUSE) {
/* Some errors are not to be reported until connect() or listen() */
- handle->bind_error = err;
- handle->flags |= UV_HANDLE_BIND_ERROR;
+ handle->delayed_error = err;
} else {
return err;
}
@@ -517,8 +528,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
return WSAEISCONN;
}
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return handle->bind_error;
+ if (handle->delayed_error) {
+ return handle->delayed_error;
}
if (!(handle->flags & UV_HANDLE_BOUND)) {
@@ -528,6 +539,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
0);
if (err)
return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
}
if (!handle->func_acceptex) {
@@ -699,8 +712,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
DWORD bytes;
int err;
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return handle->bind_error;
+ if (handle->delayed_error) {
+ return handle->delayed_error;
}
if (!(handle->flags & UV_HANDLE_BOUND)) {
@@ -714,6 +727,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err)
return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
}
if (!handle->func_connectex) {
@@ -762,8 +777,8 @@ int uv_tcp_getsockname(const uv_tcp_t* handle,
return UV_EINVAL;
}
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return uv_translate_sys_error(handle->bind_error);
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
}
result = getsockname(handle->socket, name, namelen);
@@ -784,8 +799,8 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
return UV_EINVAL;
}
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return uv_translate_sys_error(handle->bind_error);
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
}
result = getpeername(handle->socket, name, namelen);
@@ -839,7 +854,7 @@ int uv_tcp_write(uv_loop_t* loop,
uv_insert_pending_req(loop, (uv_req_t*) req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */
- req->queued_bytes = uv_count_bufs(bufs, nbufs);
+ req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->reqs_pending++;
handle->write_reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
@@ -1009,8 +1024,12 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
}
if (req->cb) {
- err = GET_REQ_SOCK_ERROR(req);
- req->cb(req, uv_translate_sys_error(err));
+ err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
+ if (err == UV_ECONNABORTED) {
+ /* use UV_ECANCELED for consistency with Unix */
+ err = UV_ECANCELED;
+ }
+ req->cb(req, err);
}
handle->write_reqs_pending--;
@@ -1102,14 +1121,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
}
-int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection) {
int err;
-
SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
- socket_protocol_info,
+ &socket_info_ex->socket_info,
0,
WSA_FLAG_OVERLAPPED);
@@ -1126,7 +1144,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
err = uv_tcp_set_socket(tcp->loop,
tcp,
socket,
- socket_protocol_info->iAddressFamily,
+ socket_info_ex->socket_info.iAddressFamily,
1);
if (err) {
closesocket(socket);
@@ -1141,6 +1159,8 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
tcp->flags |= UV_HANDLE_BOUND;
tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+ tcp->delayed_error = socket_info_ex->delayed_error;
+
tcp->loop->active_tcp_streams++;
return 0;
}
@@ -1201,13 +1221,10 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
return ERROR_INVALID_PARAMETER;
}
- /* Report any deferred bind errors now. */
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return handle->bind_error;
- }
-
- if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
- return WSAGetLastError();
+ if (!(handle->delayed_error)) {
+ if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
+ handle->delayed_error = WSAGetLastError();
+ }
}
}
}