w_stm_t w_stm_connect_named_pipe(const char *path, int timeoutms) { w_stm_t stm = NULL; HANDLE handle; DWORD err; DWORD64 deadline = GetTickCount64() + timeoutms; if (strlen(path) > 255) { w_log(W_LOG_ERR, "w_stm_connect_named_pipe(%s) path is too long\n", path); errno = E2BIG; return NULL; } retry_connect: handle = CreateFile(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (handle != INVALID_HANDLE_VALUE) { stm = w_stm_handleopen(handle); if (!stm) { CloseHandle(handle); } return stm; } err = GetLastError(); if (timeoutms > 0) { timeoutms -= (DWORD)(GetTickCount64() - deadline); } if (timeoutms <= 0 || (err != ERROR_PIPE_BUSY && err != ERROR_FILE_NOT_FOUND)) { // either we're out of time, or retrying won't help with this error errno = map_win32_err(err); return NULL; } // We can retry if (!WaitNamedPipe(path, timeoutms)) { err = GetLastError(); if (err == ERROR_SEM_TIMEOUT) { errno = map_win32_err(err); return NULL; } if (err == ERROR_FILE_NOT_FOUND) { // Grace to allow it to be created SleepEx(10, true); } } goto retry_connect; }
w_stm_t w_stm_open(const char *path, int flags, ...) { w_stm_t stm; HANDLE h = w_handle_open(path, flags); if (h == INVALID_HANDLE_VALUE) { return NULL; } stm = w_stm_handleopen(h); if (!stm) { CloseHandle(h); } return stm; }
static void named_pipe_accept_loop(const char *path) { HANDLE handles[2]; OVERLAPPED olap; HANDLE connected_event = CreateEvent(NULL, FALSE, TRUE, NULL); if (!connected_event) { w_log(W_LOG_ERR, "named_pipe_accept_loop: CreateEvent failed: %s\n", win32_strerror(GetLastError())); return; } listener_thread_event = CreateEvent(NULL, FALSE, TRUE, NULL); handles[0] = connected_event; handles[1] = listener_thread_event; memset(&olap, 0, sizeof(olap)); olap.hEvent = connected_event; w_log(W_LOG_ERR, "waiting for pipe clients on %s\n", path); while (!stopping) { w_stm_t stm; HANDLE client_fd; DWORD res; client_fd = CreateNamedPipe( path, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE| PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, WATCHMAN_IO_BUF_SIZE, 512, 0, NULL); if (client_fd == INVALID_HANDLE_VALUE) { w_log(W_LOG_ERR, "CreateNamedPipe(%s) failed: %s\n", path, win32_strerror(GetLastError())); continue; } ResetEvent(connected_event); if (!ConnectNamedPipe(client_fd, &olap)) { res = GetLastError(); if (res == ERROR_PIPE_CONNECTED) { goto good_client; } if (res != ERROR_IO_PENDING) { w_log(W_LOG_ERR, "ConnectNamedPipe: %s\n", win32_strerror(GetLastError())); CloseHandle(client_fd); continue; } res = WaitForMultipleObjectsEx(2, handles, false, INFINITE, true); if (res == WAIT_OBJECT_0 + 1) { // Signalled to stop CancelIoEx(client_fd, &olap); CloseHandle(client_fd); continue; } if (res == WAIT_OBJECT_0) { goto good_client; } w_log(W_LOG_ERR, "WaitForMultipleObjectsEx: ConnectNamedPipe: " "unexpected status %u\n", res); CancelIoEx(client_fd, &olap); CloseHandle(client_fd); } else { good_client: stm = w_stm_handleopen(client_fd); if (!stm) { w_log(W_LOG_ERR, "Failed to allocate stm for pipe handle: %s\n", strerror(errno)); CloseHandle(client_fd); continue; } make_new_client(stm); } } }