diff --git a/src/unix/tty.c b/src/unix/tty.c index 18a89216..c1429660 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -76,8 +76,8 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) { raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; - /* Put terminal in raw mode after flushing */ - if (tcsetattr(fd, TCSAFLUSH, &raw)) { + /* Put terminal in raw mode after draining */ + if (tcsetattr(fd, TCSADRAIN, &raw)) { goto fatal; } diff --git a/src/win/error.c b/src/win/error.c index bc7cfdf0..1922f203 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -108,6 +108,9 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_INVALID_PARAMETER: return UV_EINVAL; case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET; case ERROR_BROKEN_PIPE: return UV_EOF; + case ERROR_BAD_PIPE: return UV_EPIPE; + case ERROR_NO_DATA: return UV_EPIPE; + case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE; case ERROR_PIPE_BUSY: return UV_EBUSY; case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT; case WSAETIMEDOUT: return UV_ETIMEDOUT; diff --git a/src/win/fs.c b/src/win/fs.c index 94da2919..9c112b80 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -294,6 +294,7 @@ void fs__read(uv_fs_t* req, uv_file file, void *buf, size_t length, OVERLAPPED overlapped, *overlapped_ptr; LARGE_INTEGER offset_; DWORD bytes; + DWORD error; VERIFY_UV_FILE(file, req); @@ -323,7 +324,12 @@ void fs__read(uv_fs_t* req, uv_file file, void *buf, size_t length, if (ReadFile(handle, buf, length, &bytes, overlapped_ptr)) { SET_REQ_RESULT(req, bytes); } else { - SET_REQ_WIN32_ERROR(req, GetLastError()); + error = GetLastError(); + if (error == ERROR_HANDLE_EOF) { + SET_REQ_RESULT(req, bytes); + } else { + SET_REQ_WIN32_ERROR(req, error); + } } } diff --git a/src/win/internal.h b/src/win/internal.h index 0dc551db..bd5ec1ae 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -337,6 +337,10 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, /* Whether ipv6 is supported */ extern int uv_allow_ipv6; +/* Whether there are any non-IFS LSPs stacked on TCP */ +extern int uv_tcp_non_ifs_lsp_ipv4; +extern int uv_tcp_non_ifs_lsp_ipv6; + /* Ip address used to bind to any port at any interface */ extern struct sockaddr_in uv_addr_ip4_any_; extern struct sockaddr_in6 uv_addr_ip6_any_; diff --git a/src/win/tcp.c b/src/win/tcp.c index f810913f..956053c6 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -81,6 +81,7 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, SOCKET socket, int imported) { DWORD yes = 1; + int non_ifs_lsp; assert(handle->socket == INVALID_SOCKET); @@ -110,7 +111,10 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, } } - if (pSetFileCompletionNotificationModes) { + non_ifs_lsp = (handle->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : + uv_tcp_non_ifs_lsp_ipv4; + + if (pSetFileCompletionNotificationModes && !non_ifs_lsp) { if (pSetFileCompletionNotificationModes((HANDLE) socket, FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { @@ -1035,6 +1039,10 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info) { tcp->flags |= UV_HANDLE_BOUND; tcp->flags |= UV_HANDLE_SHARED_TCP_SERVER; + if (socket_protocol_info->iAddressFamily == AF_INET6) { + tcp->flags |= UV_HANDLE_IPV6; + } + return uv_tcp_set_socket(tcp->loop, tcp, socket, 1); } diff --git a/src/win/winsock.c b/src/win/winsock.c index 78acba90..667145dd 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -28,6 +28,10 @@ /* Whether ipv6 is supported */ int uv_allow_ipv6; +/* Whether there are any non-IFS LSPs stacked on TCP */ +int uv_tcp_non_ifs_lsp_ipv4; +int uv_tcp_non_ifs_lsp_ipv6; + /* Ip address used to bind to any port at any interface */ struct sockaddr_in uv_addr_ip4_any_; struct sockaddr_in6 uv_addr_ip6_any_; @@ -80,7 +84,9 @@ void uv_winsock_init() { WSADATA wsa_data; int errorno; - SOCKET dummy6; + SOCKET dummy; + WSAPROTOCOL_INFOW protocol_info; + int opt_len; /* Initialize winsock */ errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); @@ -92,11 +98,48 @@ void uv_winsock_init() { uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0); uv_addr_ip6_any_ = uv_ip6_addr("::", 0); - /* Detect IPV6 support */ - dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); - if (dummy6 != INVALID_SOCKET) { + /* Detect non-IFS LSPs */ + dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (dummy == INVALID_SOCKET) { + uv_fatal_error(WSAGetLastError(), "socket"); + } + + opt_len = (int) sizeof protocol_info; + if (!getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "socket"); + } + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) { + uv_tcp_non_ifs_lsp_ipv4 = 1; + } + + if (closesocket(dummy) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "closesocket"); + } + + /* Detect IPV6 support and non-IFS LSPs */ + dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); + if (dummy != INVALID_SOCKET) { uv_allow_ipv6 = TRUE; - if (closesocket(dummy6) == SOCKET_ERROR) { + + opt_len = (int) sizeof protocol_info; + if (!getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "socket"); + } + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) { + uv_tcp_non_ifs_lsp_ipv6 = 1; + } + + if (closesocket(dummy) == SOCKET_ERROR) { uv_fatal_error(WSAGetLastError(), "closesocket"); } }