diff options
Diffstat (limited to 'Utilities/cmlibuv/src/win')
-rw-r--r-- | Utilities/cmlibuv/src/win/error.c | 2 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/fs-event.c | 6 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/fs.c | 67 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/internal.h | 4 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/pipe.c | 229 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/poll.c | 3 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/process-stdio.c | 96 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/process.c | 9 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/stream.c | 23 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/tcp.c | 260 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/udp.c | 4 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/util.c | 20 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/winapi.c | 10 | ||||
-rw-r--r-- | Utilities/cmlibuv/src/win/winapi.h | 7 |
14 files changed, 503 insertions, 237 deletions
diff --git a/Utilities/cmlibuv/src/win/error.c b/Utilities/cmlibuv/src/win/error.c index 3ec984c..3a269da 100644 --- a/Utilities/cmlibuv/src/win/error.c +++ b/Utilities/cmlibuv/src/win/error.c @@ -105,7 +105,6 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; case WSAEPFNOSUPPORT: return UV_EINVAL; - case WSAESOCKTNOSUPPORT: return UV_EINVAL; case ERROR_BEGINNING_OF_MEDIA: return UV_EIO; case ERROR_BUS_RESET: return UV_EIO; case ERROR_CRC: return UV_EIO; @@ -168,6 +167,7 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_NOT_SAME_DEVICE: return UV_EXDEV; case ERROR_INVALID_FUNCTION: return UV_EISDIR; case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG; + case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT; default: return UV_UNKNOWN; } } diff --git a/Utilities/cmlibuv/src/win/fs-event.c b/Utilities/cmlibuv/src/win/fs-event.c index 0126c5e..76da077 100644 --- a/Utilities/cmlibuv/src/win/fs-event.c +++ b/Utilities/cmlibuv/src/win/fs-event.c @@ -574,10 +574,10 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } - if (!(handle->flags & UV_HANDLE_CLOSING)) { - uv_fs_event_queue_readdirchanges(loop, handle); - } else { + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*)handle); + } else if (uv__is_active(handle)) { + uv_fs_event_queue_readdirchanges(loop, handle); } } diff --git a/Utilities/cmlibuv/src/win/fs.c b/Utilities/cmlibuv/src/win/fs.c index d6ff7ed..9037641 100644 --- a/Utilities/cmlibuv/src/win/fs.c +++ b/Utilities/cmlibuv/src/win/fs.c @@ -92,30 +92,24 @@ return; \ } -#define MILLIONu (1000U * 1000U) -#define BILLIONu (1000U * 1000U * 1000U) +#define MILLION ((int64_t) 1000 * 1000) +#define BILLION ((int64_t) 1000 * 1000 * 1000) -#define FILETIME_TO_UINT(filetime) \ - (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu) - -#define FILETIME_TO_TIME_T(filetime) \ - (FILETIME_TO_UINT(filetime) / (10u * MILLIONu)) - -#define FILETIME_TO_TIME_NS(filetime, secs) \ - ((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U) - -#define FILETIME_TO_TIMESPEC(ts, filetime) \ - do { \ - (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \ - (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \ - } while(0) +static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) { + filetime -= 116444736 * BILLION; + ts->tv_sec = (long) (filetime / (10 * MILLION)); + ts->tv_nsec = (long) ((filetime - ts->tv_sec * 10 * MILLION) * 100U); + if (ts->tv_nsec < 0) { + ts->tv_sec -= 1; + ts->tv_nsec += 1e9; + } +} #define TIME_T_TO_FILETIME(time, filetime_ptr) \ do { \ - uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \ - (uint64_t) 116444736 * BILLIONu; \ - (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \ - (filetime_ptr)->dwHighDateTime = bigtime >> 32; \ + int64_t bigtime = ((time) * 10 * MILLION + 116444736 * BILLION); \ + (filetime_ptr)->dwLowDateTime = (uint64_t) bigtime & 0xFFFFFFFF; \ + (filetime_ptr)->dwHighDateTime = (uint64_t) bigtime >> 32; \ } while(0) #define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') @@ -764,7 +758,7 @@ void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) { void* view; if (rw_flags == UV_FS_O_WRONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); return; } if (fd_info->is_directory) { @@ -918,6 +912,11 @@ void fs__read(uv_fs_t* req) { SET_REQ_RESULT(req, bytes); } else { error = GetLastError(); + + if (error == ERROR_ACCESS_DENIED) { + error = ERROR_INVALID_FLAGS; + } + if (error == ERROR_HANDLE_EOF) { SET_REQ_RESULT(req, bytes); } else { @@ -942,7 +941,7 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file, FILETIME ft; if (rw_flags == UV_FS_O_RDONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); return; } if (fd_info->is_directory) { @@ -1058,6 +1057,7 @@ void fs__write(uv_fs_t* req) { OVERLAPPED overlapped, *overlapped_ptr; LARGE_INTEGER offset_; DWORD bytes; + DWORD error; int result; unsigned int index; LARGE_INTEGER original_position; @@ -1117,7 +1117,13 @@ void fs__write(uv_fs_t* req) { if (result || bytes > 0) { SET_REQ_RESULT(req, bytes); } else { - SET_REQ_WIN32_ERROR(req, GetLastError()); + error = GetLastError(); + + if (error == ERROR_ACCESS_DENIED) { + error = ERROR_INVALID_FLAGS; + } + + SET_REQ_WIN32_ERROR(req, error); } } @@ -1224,7 +1230,8 @@ void fs__mkdir(uv_fs_t* req) { SET_REQ_RESULT(req, 0); } else { SET_REQ_WIN32_ERROR(req, GetLastError()); - if (req->sys_errno_ == ERROR_INVALID_NAME) + if (req->sys_errno_ == ERROR_INVALID_NAME || + req->sys_errno_ == ERROR_DIRECTORY) req->result = UV_EINVAL; } } @@ -1791,10 +1798,14 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | ((_S_IREAD | _S_IWRITE) >> 6); - FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime); - FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime); - FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime); - FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime); + uv__filetime_to_timespec(&statbuf->st_atim, + file_info.BasicInformation.LastAccessTime.QuadPart); + uv__filetime_to_timespec(&statbuf->st_ctim, + file_info.BasicInformation.ChangeTime.QuadPart); + uv__filetime_to_timespec(&statbuf->st_mtim, + file_info.BasicInformation.LastWriteTime.QuadPart); + uv__filetime_to_timespec(&statbuf->st_birthtim, + file_info.BasicInformation.CreationTime.QuadPart); statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart; diff --git a/Utilities/cmlibuv/src/win/internal.h b/Utilities/cmlibuv/src/win/internal.h index 3f56777..7e1aef4 100644 --- a/Utilities/cmlibuv/src/win/internal.h +++ b/Utilities/cmlibuv/src/win/internal.h @@ -119,8 +119,8 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); /* * Pipes */ -int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, - char* name, size_t nameSize); +int uv__create_stdio_pipe_pair(uv_loop_t* loop, + uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags); int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); diff --git a/Utilities/cmlibuv/src/win/pipe.c b/Utilities/cmlibuv/src/win/pipe.c index f81245e..912aed9 100644 --- a/Utilities/cmlibuv/src/win/pipe.c +++ b/Utilities/cmlibuv/src/win/pipe.c @@ -202,17 +202,17 @@ static void close_pipe(uv_pipe_t* pipe) { } -int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, - char* name, size_t nameSize) { +static int uv__pipe_server( + HANDLE* pipeHandle_ptr, DWORD access, + char* name, size_t nameSize, char* random) { HANDLE pipeHandle; int err; - char* ptr = (char*)handle; for (;;) { - uv_unique_pipe_name(ptr, name, nameSize); + uv_unique_pipe_name(random, name, nameSize); pipeHandle = CreateNamedPipeA(name, - access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC, + access | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0, NULL); @@ -226,26 +226,225 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, goto error; } - /* Pipe name collision. Increment the pointer and try again. */ - ptr++; + /* Pipe name collision. Increment the random number and try again. */ + random++; } - if (CreateIoCompletionPort(pipeHandle, + *pipeHandle_ptr = pipeHandle; + + return 0; + + error: + if (pipeHandle != INVALID_HANDLE_VALUE) + CloseHandle(pipeHandle); + + return err; +} + + +static int uv__create_pipe_pair( + HANDLE* server_pipe_ptr, HANDLE* client_pipe_ptr, + unsigned int server_flags, unsigned int client_flags, + int inherit_client, char* random) { + /* allowed flags are: UV_READABLE_PIPE | UV_WRITABLE_PIPE | UV_NONBLOCK_PIPE */ + char pipe_name[64]; + SECURITY_ATTRIBUTES sa; + DWORD server_access; + DWORD client_access; + HANDLE server_pipe; + HANDLE client_pipe; + int err; + + server_pipe = INVALID_HANDLE_VALUE; + client_pipe = INVALID_HANDLE_VALUE; + + server_access = 0; + if (server_flags & UV_READABLE_PIPE) + server_access |= PIPE_ACCESS_INBOUND; + if (server_flags & UV_WRITABLE_PIPE) + server_access |= PIPE_ACCESS_OUTBOUND; + if (server_flags & UV_NONBLOCK_PIPE) + server_access |= FILE_FLAG_OVERLAPPED; + server_access |= WRITE_DAC; + + client_access = 0; + if (client_flags & UV_READABLE_PIPE) + client_access |= GENERIC_READ; + else + client_access |= FILE_READ_ATTRIBUTES; + if (client_flags & UV_WRITABLE_PIPE) + client_access |= GENERIC_WRITE; + else + client_access |= FILE_WRITE_ATTRIBUTES; + client_access |= WRITE_DAC; + + /* Create server pipe handle. */ + err = uv__pipe_server(&server_pipe, + server_access, + pipe_name, + sizeof(pipe_name), + random); + if (err) + goto error; + + /* Create client pipe handle. */ + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = inherit_client; + + client_pipe = CreateFileA(pipe_name, + client_access, + 0, + &sa, + OPEN_EXISTING, + (client_flags & UV_NONBLOCK_PIPE) ? FILE_FLAG_OVERLAPPED : 0, + NULL); + if (client_pipe == INVALID_HANDLE_VALUE) { + err = GetLastError(); + goto error; + } + +#ifndef NDEBUG + /* Validate that the pipe was opened in the right mode. */ + { + DWORD mode; + BOOL r; + r = GetNamedPipeHandleState(client_pipe, &mode, NULL, NULL, NULL, NULL, 0); + if (r == TRUE) { + assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT)); + } else { + fprintf(stderr, "libuv assertion failure: GetNamedPipeHandleState failed\n"); + } + } +#endif + + /* Do a blocking ConnectNamedPipe. This should not block because we have + * both ends of the pipe created. */ + if (!ConnectNamedPipe(server_pipe, NULL)) { + if (GetLastError() != ERROR_PIPE_CONNECTED) { + err = GetLastError(); + goto error; + } + } + + *client_pipe_ptr = client_pipe; + *server_pipe_ptr = server_pipe; + return 0; + + error: + if (server_pipe != INVALID_HANDLE_VALUE) + CloseHandle(server_pipe); + + if (client_pipe != INVALID_HANDLE_VALUE) + CloseHandle(client_pipe); + + return err; +} + + +int uv_pipe(uv_file fds[2], int read_flags, int write_flags) { + uv_file temp[2]; + int err; + HANDLE readh; + HANDLE writeh; + + /* Make the server side the inbound (read) end, */ + /* so that both ends will have FILE_READ_ATTRIBUTES permission. */ + /* TODO: better source of local randomness than &fds? */ + read_flags |= UV_READABLE_PIPE; + write_flags |= UV_WRITABLE_PIPE; + err = uv__create_pipe_pair(&readh, &writeh, read_flags, write_flags, 0, (char*) &fds[0]); + if (err != 0) + return err; + temp[0] = _open_osfhandle((intptr_t) readh, 0); + if (temp[0] == -1) { + if (errno == UV_EMFILE) + err = UV_EMFILE; + else + err = UV_UNKNOWN; + CloseHandle(readh); + CloseHandle(writeh); + return err; + } + temp[1] = _open_osfhandle((intptr_t) writeh, 0); + if (temp[1] == -1) { + if (errno == UV_EMFILE) + err = UV_EMFILE; + else + err = UV_UNKNOWN; + _close(temp[0]); + CloseHandle(writeh); + return err; + } + fds[0] = temp[0]; + fds[1] = temp[1]; + return 0; +} + + +int uv__create_stdio_pipe_pair(uv_loop_t* loop, + uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { + /* The parent_pipe is always the server_pipe and kept by libuv. + * The child_pipe is always the client_pipe and is passed to the child. + * The flags are specified with respect to their usage in the child. */ + HANDLE server_pipe; + HANDLE client_pipe; + unsigned int server_flags; + unsigned int client_flags; + int err; + + server_pipe = INVALID_HANDLE_VALUE; + client_pipe = INVALID_HANDLE_VALUE; + + server_flags = 0; + client_flags = 0; + if (flags & UV_READABLE_PIPE) { + /* The server needs inbound (read) access too, otherwise CreateNamedPipe() + * won't give us the FILE_READ_ATTRIBUTES permission. We need that to probe + * the state of the write buffer when we're trying to shutdown the pipe. */ + server_flags |= UV_READABLE_PIPE | UV_WRITABLE_PIPE; + client_flags |= UV_READABLE_PIPE; + } + if (flags & UV_WRITABLE_PIPE) { + server_flags |= UV_READABLE_PIPE; + client_flags |= UV_WRITABLE_PIPE; + } + server_flags |= UV_NONBLOCK_PIPE; + if (flags & UV_NONBLOCK_PIPE || parent_pipe->ipc) { + client_flags |= UV_NONBLOCK_PIPE; + } + + err = uv__create_pipe_pair(&server_pipe, &client_pipe, + server_flags, client_flags, 1, (char*) server_pipe); + if (err) + goto error; + + if (CreateIoCompletionPort(server_pipe, loop->iocp, - (ULONG_PTR)handle, + (ULONG_PTR) parent_pipe, 0) == NULL) { err = GetLastError(); goto error; } - uv_pipe_connection_init(handle); - handle->handle = pipeHandle; + uv_pipe_connection_init(parent_pipe); + parent_pipe->handle = server_pipe; + *child_pipe_ptr = client_pipe; + + /* The server end is now readable and/or writable. */ + if (flags & UV_READABLE_PIPE) + parent_pipe->flags |= UV_HANDLE_WRITABLE; + if (flags & UV_WRITABLE_PIPE) + parent_pipe->flags |= UV_HANDLE_READABLE; return 0; error: - if (pipeHandle != INVALID_HANDLE_VALUE) - CloseHandle(pipeHandle); + if (server_pipe != INVALID_HANDLE_VALUE) + CloseHandle(server_pipe); + + if (client_pipe != INVALID_HANDLE_VALUE) + CloseHandle(client_pipe); return err; } @@ -712,9 +911,8 @@ error: handle->name = NULL; } - if (pipeHandle != INVALID_HANDLE_VALUE) { + if (pipeHandle != INVALID_HANDLE_VALUE) CloseHandle(pipeHandle); - } /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, err); @@ -1054,7 +1252,6 @@ static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) { assert(req != NULL); assert(req->type == UV_WRITE); assert(handle->type == UV_NAMED_PIPE); - assert(req->write_buffer.base); result = WriteFile(handle->handle, req->write_buffer.base, diff --git a/Utilities/cmlibuv/src/win/poll.c b/Utilities/cmlibuv/src/win/poll.c index 8785859..9d37759 100644 --- a/Utilities/cmlibuv/src/win/poll.c +++ b/Utilities/cmlibuv/src/win/poll.c @@ -488,7 +488,8 @@ static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) { assert(handle->type == UV_POLL); assert(!(handle->flags & UV_HANDLE_CLOSING)); - assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT | + UV_PRIORITIZED)) == 0); handle->events = events; handle->poll_cb = cb; diff --git a/Utilities/cmlibuv/src/win/process-stdio.c b/Utilities/cmlibuv/src/win/process-stdio.c index 355d618..0db3572 100644 --- a/Utilities/cmlibuv/src/win/process-stdio.c +++ b/Utilities/cmlibuv/src/win/process-stdio.c @@ -95,102 +95,6 @@ void uv_disable_stdio_inheritance(void) { } -static int uv__create_stdio_pipe_pair(uv_loop_t* loop, - uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { - char pipe_name[64]; - SECURITY_ATTRIBUTES sa; - DWORD server_access = 0; - DWORD client_access = 0; - HANDLE child_pipe = INVALID_HANDLE_VALUE; - int err; - int overlap; - - if (flags & UV_READABLE_PIPE) { - /* The server needs inbound access too, otherwise CreateNamedPipe() won't - * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the - * state of the write buffer when we're trying to shutdown the pipe. */ - server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND; - client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; - } - if (flags & UV_WRITABLE_PIPE) { - server_access |= PIPE_ACCESS_INBOUND; - client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; - } - - /* Create server pipe handle. */ - err = uv_stdio_pipe_server(loop, - server_pipe, - server_access, - pipe_name, - sizeof(pipe_name)); - if (err) - goto error; - - /* Create child pipe handle. */ - sa.nLength = sizeof sa; - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - - overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE); - child_pipe = CreateFileA(pipe_name, - client_access, - 0, - &sa, - OPEN_EXISTING, - overlap ? FILE_FLAG_OVERLAPPED : 0, - NULL); - if (child_pipe == INVALID_HANDLE_VALUE) { - err = GetLastError(); - goto error; - } - -#ifndef NDEBUG - /* Validate that the pipe was opened in the right mode. */ - { - DWORD mode; - BOOL r = GetNamedPipeHandleState(child_pipe, - &mode, - NULL, - NULL, - NULL, - NULL, - 0); - assert(r == TRUE); - assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT)); - } -#endif - - /* Do a blocking ConnectNamedPipe. This should not block because we have both - * ends of the pipe created. */ - if (!ConnectNamedPipe(server_pipe->handle, NULL)) { - if (GetLastError() != ERROR_PIPE_CONNECTED) { - err = GetLastError(); - goto error; - } - } - - /* The server end is now readable and/or writable. */ - if (flags & UV_READABLE_PIPE) - server_pipe->flags |= UV_HANDLE_WRITABLE; - if (flags & UV_WRITABLE_PIPE) - server_pipe->flags |= UV_HANDLE_READABLE; - - *child_pipe_ptr = child_pipe; - return 0; - - error: - if (server_pipe->handle != INVALID_HANDLE_VALUE) { - uv_pipe_cleanup(loop, server_pipe); - } - - if (child_pipe != INVALID_HANDLE_VALUE) { - CloseHandle(child_pipe); - } - - return err; -} - - static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { HANDLE current_process; diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c index aada889..9ca4122 100644 --- a/Utilities/cmlibuv/src/win/process.c +++ b/Utilities/cmlibuv/src/win/process.c @@ -169,10 +169,9 @@ static WCHAR* search_path_join_test(const WCHAR* dir, size_t cwd_len) { WCHAR *result, *result_pos; DWORD attrs; - if ( - (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') || - (dir_len > 2 && dir[0] == L'/' && dir[1] == L'/') - ) { + if (dir_len > 2 && + ((dir[0] == L'\\' || dir[0] == L'/') && + (dir[1] == L'\\' || dir[1] == L'/'))) { /* It's a UNC path so ignore cwd */ cwd_len = 0; } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { @@ -645,7 +644,7 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { assert(r==nb); B[nb] = L'\0'; - while (1) { + for (;;) { wchar_t AA = *A++; wchar_t BB = *B++; if (AA < BB) { diff --git a/Utilities/cmlibuv/src/win/stream.c b/Utilities/cmlibuv/src/win/stream.c index 46a0709..abf477f 100644 --- a/Utilities/cmlibuv/src/win/stream.c +++ b/Utilities/cmlibuv/src/win/stream.c @@ -65,18 +65,11 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { } -int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, - uv_read_cb read_cb) { +int uv__read_start(uv_stream_t* handle, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { int err; - if (handle->flags & UV_HANDLE_READING) { - return UV_EALREADY; - } - - if (!(handle->flags & UV_HANDLE_READABLE)) { - return UV_ENOTCONN; - } - err = ERROR_INVALID_PARAMETER; switch (handle->type) { case UV_TCP: @@ -195,6 +188,16 @@ int uv_try_write(uv_stream_t* stream, } +int uv_try_write2(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle) { + if (send_handle != NULL) + return UV_EAGAIN; + return uv_try_write(stream, bufs, nbufs); +} + + int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { uv_loop_t* loop = handle->loop; diff --git a/Utilities/cmlibuv/src/win/tcp.c b/Utilities/cmlibuv/src/win/tcp.c index 0dcaa97..cf2dbd8 100644 --- a/Utilities/cmlibuv/src/win/tcp.c +++ b/Utilities/cmlibuv/src/win/tcp.c @@ -236,12 +236,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); - - if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { - closesocket(handle->socket); - handle->socket = INVALID_SOCKET; - handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; - } + assert(handle->socket == INVALID_SOCKET); if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { if (handle->flags & UV_HANDLE_EMULATE_IOCP) { @@ -599,6 +594,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { } } + /* If this flag is set, we already made this listen call in xfer. */ if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && listen(handle->socket, backlog) == SOCKET_ERROR) { return WSAGetLastError(); @@ -769,7 +765,7 @@ static int uv__is_loopback(const struct sockaddr_storage* storage) { } // Check if Windows version is 10.0.16299 or later -static int uv__is_fast_loopback_fail_supported() { +static int uv__is_fast_loopback_fail_supported(void) { OSVERSIONINFOW os_info; if (!pRtlGetVersion) return 0; @@ -800,9 +796,8 @@ static int uv_tcp_try_connect(uv_connect_t* req, if (err) return err; - if (handle->delayed_error) { - return handle->delayed_error; - } + if (handle->delayed_error != 0) + goto out; if (!(handle->flags & UV_HANDLE_BOUND)) { if (addrlen == sizeof(uv_addr_ip4_any_)) { @@ -815,8 +810,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->delayed_error != 0) + goto out; } if (!handle->tcp.conn.func_connectex) { @@ -844,11 +839,21 @@ static int uv_tcp_try_connect(uv_connect_t* req, NULL); } +out: + UV_REQ_INIT(req, UV_CONNECT); req->handle = (uv_stream_t*) handle; req->cb = cb; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + if (handle->delayed_error != 0) { + /* Process the req without IOCP. */ + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*)req); + return 0; + } + success = handle->tcp.conn.func_connectex(handle->socket, (const struct sockaddr*) &converted, addrlen, @@ -1015,6 +1020,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, */ err = WSAECONNRESET; } + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(err), @@ -1096,6 +1102,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, * Unix. */ err = WSAECONNRESET; } + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(err), @@ -1149,9 +1156,14 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, } handle->stream.conn.write_reqs_pending--; - if (handle->stream.conn.shutdown_req != NULL && - handle->stream.conn.write_reqs_pending == 0) { - uv_want_endgame(loop, (uv_handle_t*)handle); + if (handle->stream.conn.write_reqs_pending == 0) { + if (handle->flags & UV_HANDLE_CLOSING) { + closesocket(handle->socket); + handle->socket = INVALID_SOCKET; + } + if (handle->stream.conn.shutdown_req != NULL) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } } DECREASE_PENDING_REQ_COUNT(handle); @@ -1215,7 +1227,14 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, UNREGISTER_HANDLE_REQ(loop, handle, req); err = 0; - if (REQ_SUCCESS(req)) { + if (handle->delayed_error) { + /* To smooth over the differences between unixes errors that + * were reported synchronously on the first connect can be delayed + * until the next tick--which is now. + */ + err = handle->delayed_error; + handle->delayed_error = 0; + } else if (REQ_SUCCESS(req)) { if (handle->flags & UV_HANDLE_CLOSING) { /* use UV_ECANCELED for consistency with Unix */ err = ERROR_OPERATION_ABORTED; @@ -1320,7 +1339,7 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { if (handle->socket != INVALID_SOCKET) { err = uv__tcp_nodelay(handle, handle->socket, enable); if (err) - return err; + return uv_translate_sys_error(err); } if (enable) { @@ -1339,7 +1358,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { if (handle->socket != INVALID_SOCKET) { err = uv__tcp_keepalive(handle, handle->socket, enable, delay); if (err) - return err; + return uv_translate_sys_error(err); } if (enable) { @@ -1386,9 +1405,24 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } -static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { - SOCKET socket = tcp->socket; +static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) { + SOCKET socket; int non_ifs_lsp; + int reading; + int writing; + + socket = tcp->socket; + reading = tcp->flags & UV_HANDLE_READING; + writing = tcp->stream.conn.write_reqs_pending > 0; + if (!reading && !writing) + return; + + /* TODO: in libuv v2, keep explicit track of write_reqs, so we can cancel + * them each explicitly with CancelIoEx (like unix). */ + if (reading) + CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped); + if (writing) + CancelIo((HANDLE) socket); /* Check if we have any non-IFS LSPs stacked on top of TCP */ non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : @@ -1408,71 +1442,41 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { NULL, NULL) != 0) { /* Failed. We can't do CancelIo. */ - return -1; + return; } } assert(socket != 0 && socket != INVALID_SOCKET); - if (!CancelIo((HANDLE) socket)) { - return GetLastError(); + if (socket != tcp->socket) { + if (reading) + CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped); + if (writing) + CancelIo((HANDLE) socket); } - - /* It worked. */ - return 0; } void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { - int close_socket = 1; - - if (tcp->flags & UV_HANDLE_READ_PENDING) { - /* In order for winsock to do a graceful close there must not be any any - * pending reads, or the socket must be shut down for writing */ - if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { - /* Just do shutdown on non-shared sockets, which ensures graceful close. */ - shutdown(tcp->socket, SD_SEND); - - } else if (uv_tcp_try_cancel_io(tcp) == 0) { - /* In case of a shared socket, we try to cancel all outstanding I/O,. If - * that works, don't close the socket yet - wait for the read req to - * return and close the socket in uv_tcp_endgame. */ - close_socket = 0; - - } else { - /* When cancelling isn't possible - which could happen when an LSP is - * present on an old Windows version, we will have to close the socket - * with a read pending. That is not nice because trailing sent bytes may - * not make it to the other side. */ + if (tcp->flags & UV_HANDLE_CONNECTION) { + uv_tcp_try_cancel_reqs(tcp); + if (tcp->flags & UV_HANDLE_READING) { + uv_read_stop((uv_stream_t*) tcp); } - - } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && - tcp->tcp.serv.accept_reqs != NULL) { - /* Under normal circumstances closesocket() will ensure that all pending - * accept reqs are canceled. However, when the socket is shared the - * presence of another reference to the socket in another process will keep - * the accept reqs going, so we have to ensure that these are canceled. */ - if (uv_tcp_try_cancel_io(tcp) != 0) { - /* When cancellation is not possible, there is another option: we can - * close the incoming sockets, which will also cancel the accept - * operations. However this is not cool because we might inadvertently - * close a socket that just accepted a new connection, which will cause - * the connection to be aborted. */ + } else { + if (tcp->tcp.serv.accept_reqs != NULL) { + /* First close the incoming sockets to cancel the accept operations before + * we free their resources. */ unsigned int i; for (i = 0; i < uv_simultaneous_server_accepts; i++) { uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; - if (req->accept_socket != INVALID_SOCKET && - !HasOverlappedIoCompleted(&req->u.io.overlapped)) { + if (req->accept_socket != INVALID_SOCKET) { closesocket(req->accept_socket); req->accept_socket = INVALID_SOCKET; } } } - } - - if (tcp->flags & UV_HANDLE_READING) { - tcp->flags &= ~UV_HANDLE_READING; - DECREASE_ACTIVE_COUNT(loop, tcp); + assert(!(tcp->flags & UV_HANDLE_READING)); } if (tcp->flags & UV_HANDLE_LISTENING) { @@ -1480,10 +1484,15 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { DECREASE_ACTIVE_COUNT(loop, tcp); } - if (close_socket) { + /* If any overlapped req failed to cancel, calling `closesocket` now would + * cause Win32 to send an RST packet. Try to avoid that for writes, if + * possibly applicable, by waiting to process the completion notifications + * first (which typically should be cancellations). There's not much we can + * do about canceled reads, which also will generate an RST packet. */ + if (!(tcp->flags & UV_HANDLE_CONNECTION) || + tcp->stream.conn.write_reqs_pending == 0) { closesocket(tcp->socket); tcp->socket = INVALID_SOCKET; - tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); @@ -1571,3 +1580,118 @@ int uv__tcp_connect(uv_connect_t* req, return 0; } + +#ifndef WSA_FLAG_NO_HANDLE_INHERIT +/* Added in Windows 7 SP1. Specify this to avoid race conditions, */ +/* but also manually clear the inherit flag in case this failed. */ +#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 +#endif + +int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) { + SOCKET server = INVALID_SOCKET; + SOCKET client0 = INVALID_SOCKET; + SOCKET client1 = INVALID_SOCKET; + SOCKADDR_IN name; + LPFN_ACCEPTEX func_acceptex; + WSAOVERLAPPED overlap; + char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; + int namelen; + int err; + DWORD bytes; + DWORD flags; + DWORD client0_flags = WSA_FLAG_NO_HANDLE_INHERIT; + DWORD client1_flags = WSA_FLAG_NO_HANDLE_INHERIT; + + if (flags0 & UV_NONBLOCK_PIPE) + client0_flags |= WSA_FLAG_OVERLAPPED; + if (flags1 & UV_NONBLOCK_PIPE) + client1_flags |= WSA_FLAG_OVERLAPPED; + + server = WSASocketW(AF_INET, type, protocol, NULL, 0, + WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT); + if (server == INVALID_SOCKET) + goto wsaerror; + if (!SetHandleInformation((HANDLE) server, HANDLE_FLAG_INHERIT, 0)) + goto error; + name.sin_family = AF_INET; + name.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + name.sin_port = 0; + if (bind(server, (SOCKADDR*) &name, sizeof(name)) != 0) + goto wsaerror; + if (listen(server, 1) != 0) + goto wsaerror; + namelen = sizeof(name); + if (getsockname(server, (SOCKADDR*) &name, &namelen) != 0) + goto wsaerror; + client0 = WSASocketW(AF_INET, type, protocol, NULL, 0, client0_flags); + if (client0 == INVALID_SOCKET) + goto wsaerror; + if (!SetHandleInformation((HANDLE) client0, HANDLE_FLAG_INHERIT, 0)) + goto error; + if (connect(client0, (SOCKADDR*) &name, sizeof(name)) != 0) + goto wsaerror; + client1 = WSASocketW(AF_INET, type, protocol, NULL, 0, client1_flags); + if (client1 == INVALID_SOCKET) + goto wsaerror; + if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0)) + goto error; + if (!uv_get_acceptex_function(server, &func_acceptex)) { + err = WSAEAFNOSUPPORT; + goto cleanup; + } + memset(&overlap, 0, sizeof(overlap)); + if (!func_acceptex(server, + client1, + accept_buffer, + 0, + sizeof(struct sockaddr_storage), + sizeof(struct sockaddr_storage), + &bytes, + &overlap)) { + err = WSAGetLastError(); + if (err == ERROR_IO_PENDING) { + /* Result should complete immediately, since we already called connect, + * but emperically, we sometimes have to poll the kernel a couple times + * until it notices that. */ + while (!WSAGetOverlappedResult(client1, &overlap, &bytes, FALSE, &flags)) { + err = WSAGetLastError(); + if (err != WSA_IO_INCOMPLETE) + goto cleanup; + SwitchToThread(); + } + } + else { + goto cleanup; + } + } + if (setsockopt(client1, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + (char*) &server, sizeof(server)) != 0) { + goto wsaerror; + } + + closesocket(server); + + fds[0] = client0; + fds[1] = client1; + + return 0; + + wsaerror: + err = WSAGetLastError(); + goto cleanup; + + error: + err = GetLastError(); + goto cleanup; + + cleanup: + if (server != INVALID_SOCKET) + closesocket(server); + if (client0 != INVALID_SOCKET) + closesocket(client0); + if (client1 != INVALID_SOCKET) + closesocket(client1); + + assert(err); + return uv_translate_sys_error(err); +} diff --git a/Utilities/cmlibuv/src/win/udp.c b/Utilities/cmlibuv/src/win/udp.c index 68ca728..3043f2d 100644 --- a/Utilities/cmlibuv/src/win/udp.c +++ b/Utilities/cmlibuv/src/win/udp.c @@ -284,7 +284,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { handle->flags &= ~UV_HANDLE_ZERO_READ; handle->recv_buffer = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); + handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer); if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); return; @@ -501,7 +501,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, /* Do a nonblocking receive. * TODO: try to read multiple datagrams at once. FIONREAD maybe? */ buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf); if (buf.base == NULL || buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); goto done; diff --git a/Utilities/cmlibuv/src/win/util.c b/Utilities/cmlibuv/src/win/util.c index aad8f1a..33e874a 100644 --- a/Utilities/cmlibuv/src/win/util.c +++ b/Utilities/cmlibuv/src/win/util.c @@ -1664,26 +1664,36 @@ int uv_os_unsetenv(const char* name) { int uv_os_gethostname(char* buffer, size_t* size) { - char buf[UV_MAXHOSTNAMESIZE]; + WCHAR buf[UV_MAXHOSTNAMESIZE]; size_t len; + char* utf8_str; + int convert_result; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; uv__once_init(); /* Initialize winsock */ - if (gethostname(buf, sizeof(buf)) != 0) + if (pGetHostNameW == NULL) + return UV_ENOSYS; + + if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) return uv_translate_sys_error(WSAGetLastError()); - buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ - len = strlen(buf); + convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str); + + if (convert_result != 0) + return convert_result; + len = strlen(utf8_str); if (len >= *size) { *size = len + 1; + uv__free(utf8_str); return UV_ENOBUFS; } - memcpy(buffer, buf, len + 1); + memcpy(buffer, utf8_str, len + 1); + uv__free(utf8_str); *size = len; return 0; } diff --git a/Utilities/cmlibuv/src/win/winapi.c b/Utilities/cmlibuv/src/win/winapi.c index bb86ec8..bf306cd 100644 --- a/Utilities/cmlibuv/src/win/winapi.c +++ b/Utilities/cmlibuv/src/win/winapi.c @@ -45,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; /* User32.dll function pointer */ sSetWinEventHook pSetWinEventHook; +/* ws2_32.dll function pointer */ +uv_sGetHostNameW pGetHostNameW; void uv_winapi_init(void) { HMODULE ntdll_module; HMODULE powrprof_module; HMODULE user32_module; HMODULE kernel32_module; + HMODULE ws2_32_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -134,4 +137,11 @@ void uv_winapi_init(void) { pSetWinEventHook = (sSetWinEventHook) GetProcAddress(user32_module, "SetWinEventHook"); } + + ws2_32_module = LoadLibraryA("ws2_32.dll"); + if (ws2_32_module != NULL) { + pGetHostNameW = (uv_sGetHostNameW) GetProcAddress( + ws2_32_module, + "GetHostNameW"); + } } diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h index 9bc4559..e815f8f 100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h @@ -4768,4 +4768,11 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi /* User32.dll function pointer */ extern sSetWinEventHook pSetWinEventHook; +/* ws2_32.dll function pointer */ +/* mingw doesn't have this definition, so let's declare it here locally */ +typedef int (WINAPI *uv_sGetHostNameW) + (PWSTR, + int); +extern uv_sGetHostNameW pGetHostNameW; + #endif /* UV_WIN_WINAPI_H_ */ |