/* Starts listening for connections for the given pipe. */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { int i, errno; uv_pipe_accept_t* req; HANDLE pipeHandle; if (handle->flags & UV_HANDLE_BIND_ERROR) { uv_set_error(UV_EINVAL, 0); return -1; } if (!(handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) { uv_set_error(UV_EINVAL, 0); return -1; } if (handle->flags & UV_HANDLE_LISTENING || handle->flags & UV_HANDLE_READING) { uv_set_error(UV_EALREADY, 0); return -1; } if (!(handle->flags & UV_HANDLE_PIPESERVER) && !(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) { uv_set_error(UV_ENOTSUP, 0); return -1; } handle->flags |= UV_HANDLE_LISTENING; handle->connection_cb = cb; if (handle->flags & UV_HANDLE_GIVEN_OS_HANDLE) { handle->flags |= UV_HANDLE_PIPESERVER; pipeHandle = handle->handle; assert(pipeHandle != INVALID_HANDLE_VALUE); req = &handle->accept_reqs[0]; uv_req_init((uv_req_t*) req); req->pipeHandle = pipeHandle; req->type = UV_ACCEPT; req->data = handle; req->next_pending = NULL; if (uv_set_pipe_handle(handle, pipeHandle)) { uv_set_sys_error(GetLastError()); return -1; } uv_pipe_queue_accept(handle, req, TRUE); } else { /* First pipe handle should have already been created in uv_pipe_bind */ assert(handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE); for (i = 0; i < COUNTOF(handle->accept_reqs); i++) { uv_pipe_queue_accept(handle, &handle->accept_reqs[i], i == 0); } } return 0; }
static void uv_pipe_queue_accept(uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL firstInstance) { assert(handle->flags & UV_HANDLE_LISTENING); if (!firstInstance) { assert(req->pipeHandle == INVALID_HANDLE_VALUE); req->pipeHandle = CreateNamedPipeW(handle->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); if (req->pipeHandle == INVALID_HANDLE_VALUE) { req->error = uv_new_sys_error(GetLastError()); uv_insert_pending_req((uv_req_t*) req); handle->reqs_pending++; return; } if (uv_set_pipe_handle(handle, req->pipeHandle)) { CloseHandle(req->pipeHandle); req->pipeHandle = INVALID_HANDLE_VALUE; req->error = uv_new_sys_error(GetLastError()); uv_insert_pending_req((uv_req_t*) req); handle->reqs_pending++; return; } } assert(req->pipeHandle != INVALID_HANDLE_VALUE); /* Prepare the overlapped structure. */ memset(&(req->overlapped), 0, sizeof(req->overlapped)); if (!ConnectNamedPipe(req->pipeHandle, &req->overlapped) && GetLastError() != ERROR_IO_PENDING) { if (GetLastError() == ERROR_PIPE_CONNECTED) { req->error = uv_ok_; } else { CloseHandle(req->pipeHandle); req->pipeHandle = INVALID_HANDLE_VALUE; /* Make this req pending reporting an error. */ req->error = uv_new_sys_error(GetLastError()); } uv_insert_pending_req((uv_req_t*) req); handle->reqs_pending++; return; } handle->reqs_pending++; }
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { HANDLE pipeHandle = INVALID_HANDLE_VALUE; int errno; uv_pipe_t* handle; uv_connect_t* req; req = (uv_connect_t*)parameter; assert(req); handle = (uv_pipe_t*)req->handle; assert(handle); /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = CreateFileW(handle->name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (pipeHandle != INVALID_HANDLE_VALUE) { break; } } if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(handle, pipeHandle)) { handle->handle = pipeHandle; req->error = uv_ok_; } else { req->error = uv_new_sys_error(GetLastError()); } memset(&req->overlapped, 0, sizeof(req->overlapped)); /* Post completed */ if (!PostQueuedCompletionStatus(LOOP->iocp, 0, 0, &req->overlapped)) { uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); } return 0; }
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { HANDLE pipeHandle = INVALID_HANDLE_VALUE; int errno; uv_loop_t* loop; uv_pipe_t* handle; uv_connect_t* req; req = (uv_connect_t*) parameter; assert(req); handle = (uv_pipe_t*) req->handle; assert(handle); loop = handle->loop; assert(loop); /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ /* We wait for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = CreateFileW(handle->name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (pipeHandle != INVALID_HANDLE_VALUE) { break; } SwitchToThread(); } if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(loop, handle, pipeHandle)) { handle->handle = pipeHandle; SET_REQ_SUCCESS(req); } else { SET_REQ_ERROR(req, GetLastError()); } /* Post completed */ POST_COMPLETION_FOR_REQ(loop, req); return 0; }
void uv_pipe_open(uv_pipe_t* pipe, uv_file file) { HANDLE os_handle = (HANDLE)_get_osfhandle(file); if (os_handle == INVALID_HANDLE_VALUE || uv_set_pipe_handle(pipe->loop, pipe, os_handle) == -1) { return; } uv_pipe_connection_init(pipe); pipe->handle = os_handle; if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); pipe->ipc_pid = uv_parent_pid(); assert(pipe->ipc_pid != -1); } }
int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { HANDLE os_handle = (HANDLE)_get_osfhandle(file); if (os_handle == INVALID_HANDLE_VALUE || uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) { uv__set_sys_error(pipe->loop, WSAEINVAL); return -1; } uv_pipe_connection_init(pipe); pipe->handle = os_handle; pipe->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); pipe->ipc_pid = uv_parent_pid(); assert(pipe->ipc_pid != -1); } return 0; }
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { uv_loop_t* loop; uv_pipe_t* handle; uv_connect_t* req; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; req = (uv_connect_t*) parameter; assert(req); handle = (uv_pipe_t*) req->handle; assert(handle); loop = handle->loop; assert(loop); /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ /* We wait for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = open_named_pipe(handle->name, &duplex_flags); if (pipeHandle != INVALID_HANDLE_VALUE) { break; } SwitchToThread(); } if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(loop, handle, pipeHandle, duplex_flags)) { SET_REQ_SUCCESS(req); } else { SET_REQ_ERROR(req, GetLastError()); } /* Post completed */ POST_COMPLETION_FOR_REQ(loop, req); return 0; }
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int errorno, nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; uv_req_init(loop, (uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; /* Convert name to UTF16. */ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { errorno = GetLastError(); goto error; } pipeHandle = open_named_pipe(handle->name, &duplex_flags); if (pipeHandle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_PIPE_BUSY) { /* Wait for the server to make a pipe instance available. */ if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) { errorno = GetLastError(); goto error; } REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; return; } errorno = GetLastError(); goto error; } assert(pipeHandle != INVALID_HANDLE_VALUE); if (uv_set_pipe_handle(loop, (uv_pipe_t*) req->handle, pipeHandle, duplex_flags)) { errorno = GetLastError(); goto error; } SET_REQ_SUCCESS(req); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); return; error: if (handle->name) { free(handle->name); handle->name = NULL; } if (pipeHandle != INVALID_HANDLE_VALUE) { CloseHandle(pipeHandle); } /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, errorno); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); return; }
/* Creates a pipe server. */ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { uv_loop_t* loop = handle->loop; int i, errorno, nameSize; uv_pipe_accept_t* req; if (handle->flags & UV_HANDLE_BOUND) { uv__set_sys_error(loop, WSAEINVAL); return -1; } if (!name) { uv__set_sys_error(loop, WSAEINVAL); return -1; } if (!(handle->flags & UV_HANDLE_PIPESERVER)) { handle->pending_instances = default_pending_pipe_instances; } handle->accept_reqs = (uv_pipe_accept_t*) malloc(sizeof(uv_pipe_accept_t) * handle->pending_instances); if (!handle->accept_reqs) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } for (i = 0; i < handle->pending_instances; i++) { req = &handle->accept_reqs[i]; uv_req_init(loop, (uv_req_t*) req); req->type = UV_ACCEPT; req->data = handle; req->pipeHandle = INVALID_HANDLE_VALUE; req->next_pending = NULL; } /* Convert name to UTF16. */ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { uv__set_sys_error(loop, GetLastError()); return -1; } /* * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. * If this fails then there's already a pipe server for the given pipe name. */ handle->accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); if (handle->accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) { errorno = GetLastError(); if (errorno == ERROR_ACCESS_DENIED) { uv__set_error(loop, UV_EADDRINUSE, errorno); } else if (errorno == ERROR_PATH_NOT_FOUND || errorno == ERROR_INVALID_NAME) { uv__set_error(loop, UV_EACCES, errorno); } else { uv__set_sys_error(loop, errorno); } goto error; } if (uv_set_pipe_handle(loop, handle, handle->accept_reqs[0].pipeHandle, 0)) { uv__set_sys_error(loop, GetLastError()); goto error; } handle->pending_accepts = NULL; handle->flags |= UV_HANDLE_PIPESERVER; handle->flags |= UV_HANDLE_BOUND; return 0; error: if (handle->name) { free(handle->name); handle->name = NULL; } if (handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) { CloseHandle(handle->accept_reqs[0].pipeHandle); handle->accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE; } return -1; }
int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { int errno, nameSize; HANDLE pipeHandle; handle->handle = INVALID_HANDLE_VALUE; uv_req_init((uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; /* Convert name to UTF16. */ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t); handle->name = (wchar_t*)malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) { errno = GetLastError(); goto error; } pipeHandle = CreateFileW(handle->name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (pipeHandle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_PIPE_BUSY) { /* Wait for the server to make a pipe instance available. */ if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) { errno = GetLastError(); goto error; } return 0; } errno = GetLastError(); goto error; } if (uv_set_pipe_handle((uv_pipe_t*)req->handle, pipeHandle)) { errno = GetLastError(); goto error; } handle->handle = pipeHandle; req->error = uv_ok_; uv_insert_pending_req((uv_req_t*) req); handle->reqs_pending++; return 0; error: if (handle->name) { free(handle->name); handle->name = NULL; } if (pipeHandle != INVALID_HANDLE_VALUE) { CloseHandle(pipeHandle); } uv_set_sys_error(errno); return -1; }
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int errno, nameSize; handle->handle = INVALID_HANDLE_VALUE; uv_req_init(loop, (uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; /* Convert name to UTF16. */ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t); handle->name = (wchar_t*)malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) { errno = GetLastError(); goto error; } if (open_named_pipe(handle) != 0) { if (GetLastError() == ERROR_PIPE_BUSY) { /* Wait for the server to make a pipe instance available. */ if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) { errno = GetLastError(); goto error; } handle->reqs_pending++; return; } errno = GetLastError(); goto error; } assert(handle->handle != INVALID_HANDLE_VALUE); /* Ensure that what we just opened is actually a pipe */ if (!GetNamedPipeInfo(handle->handle, NULL, NULL, NULL, NULL)) { errno = WSAENOTSOCK; goto error; } if (uv_set_pipe_handle(loop, (uv_pipe_t*)req->handle, handle->handle)) { errno = GetLastError(); goto error; } SET_REQ_SUCCESS(req); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; return; error: if (handle->name) { free(handle->name); handle->name = NULL; } if (handle->handle != INVALID_HANDLE_VALUE) { CloseHandle(handle->handle); handle->handle = INVALID_HANDLE_VALUE; } /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, errno); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; return; }