int write(int fh, void const* buf, unsigned int count) { if (folly::portability::sockets::is_fh_socket(fh)) { SOCKET s = (SOCKET)_get_osfhandle(fh); if (s != INVALID_SOCKET) { auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0); if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) { errno = EAGAIN; } return r; } } auto r = _write(fh, buf, count); if ((r > 0 && r != count) || (r == -1 && errno == ENOSPC)) { // Writing to a pipe with a full buffer doesn't generate // any error type, unless it caused us to write exactly 0 // bytes, so we have to see if we have a pipe first. We // don't touch the errno for anything else. HANDLE h = (HANDLE)_get_osfhandle(fh); if (GetFileType(h) == FILE_TYPE_PIPE) { DWORD state = 0; if (GetNamedPipeHandleState( h, &state, nullptr, nullptr, nullptr, nullptr, 0)) { if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) { errno = EAGAIN; return -1; } } } } return r; }
ssize_t rpl_read (int fd, void *buf, size_t count) { ssize_t ret = read_nothrow (fd, buf, count); # if GNULIB_NONBLOCKING if (ret < 0 && GetLastError () == ERROR_NO_DATA) { HANDLE h = (HANDLE) _get_osfhandle (fd); if (GetFileType (h) == FILE_TYPE_PIPE) { /* h is a pipe or socket. */ DWORD state; if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0) && (state & PIPE_NOWAIT) != 0) /* h is a pipe in non-blocking mode. Change errno from EINVAL to EAGAIN. */ errno = EAGAIN; } } # endif return ret; }
int get_nonblocking_flag (int desc) { HANDLE h = (HANDLE) _get_osfhandle (desc); if (h == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } if (GetFileType (h) == FILE_TYPE_PIPE) { /* h is a pipe or socket. */ DWORD state; if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0)) /* h is a pipe. */ return (state & PIPE_NOWAIT) != 0; else /* h is a socket. */ errno = ENOSYS; return -1; } else /* The native Windows API does not support non-blocking on regular files. */ return 0; }
HRESULT PipeStream::GetState(DWORD* state, DWORD* instances, DWORD* max_collections, DWORD* collect_timeout) { if (!IsValid()) return E_HANDLE; if (!GetNamedPipeHandleState(handle_, state, instances, max_collections, collect_timeout, nullptr, 0)) return HRESULT_FROM_LAST_ERROR(); return S_OK; }
HRESULT NamedPipeChannel::GetHandleState(DWORD* mode, DWORD* instances, wchar_t* user_name, DWORD user_name_size) const { if (!IsValid()) return E_HANDLE; if (!GetNamedPipeHandleState(handle_, mode, instances, nullptr, nullptr, user_name, user_name_size)) return HRESULT_FROM_WIN32(GetLastError()); return S_OK; }
int set_nonblocking_flag (int desc, bool value) { HANDLE h = (HANDLE) _get_osfhandle (desc); if (h == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } if (GetFileType (h) == FILE_TYPE_PIPE) { /* h is a pipe or socket. */ DWORD state; if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0)) { /* h is a pipe. */ if ((state & PIPE_NOWAIT) != 0) { if (value) return 0; state &= ~PIPE_NOWAIT; } else { if (!value) return 0; state |= PIPE_NOWAIT; } if (SetNamedPipeHandleState (h, &state, NULL, NULL)) return 0; errno = EINVAL; return -1; } else { /* h is a socket. */ int v = value; return ioctl (desc, FIONBIO, &v); } } else { /* The native Windows API does not support non-blocking on regular files. */ if (!value) return 0; errno = ENOTSUP; return -1; } }
String Pipe::UserName() { Assert(_Handle != NULL, "Pipe invalid in Pipe::UserName"); char Buffer[512]; BOOL Success = GetNamedPipeHandleState( _Handle, NULL, NULL, NULL, NULL, Buffer, 512); Assert(Success != FALSE, "GetNamedPipeHandleState failed in Pipe::UserName"); return String(Buffer); }
UINT Pipe::ActiveInstances() { Assert(_Handle != NULL, "Pipe invalid in Pipe::ActiveInstances"); DWORD Instances; BOOL Success = GetNamedPipeHandleState( _Handle, NULL, &Instances, NULL, NULL, NULL, 0); Assert(Success != FALSE, "GetNamedPipeHandleState failed in Pipe::ActiveInstances"); return Instances; }
UINT Pipe::activeInstances() { MLIB_ASSERT_STR(m_handle != nullptr, "Pipe invalid in Pipe::ActiveInstances"); DWORD Instances; BOOL success = GetNamedPipeHandleState( m_handle, nullptr, &Instances, nullptr, nullptr, nullptr, 0); MLIB_ASSERT_STR(success != FALSE, "GetNamedPipeHandleState failed in Pipe::ActiveInstances"); return Instances; }
static int retrievePeerCredentials (PeerCredentials *credentials, FileDescriptor fd) { char buffer[0X100+1]; if (GetNamedPipeHandleState(fd, NULL, NULL, NULL, NULL, buffer, sizeof(buffer))) { buffer[sizeof(buffer) - 1] = 0; if ((credentials->user = strdup(buffer))) { return 1; } } else { switch (GetLastError()) { default: logWindowsSystemError("GetNamedPipeHandleState"); case ERROR_INSUFFICIENT_BUFFER: /* buffer too small */ case ERROR_INVALID_HANDLE: /* not a named pipe */ case ERROR_CANNOT_IMPERSONATE: /* no data transferred yet */ break; } } return 0; }
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; if (flags & UV_READABLE_PIPE) { server_access |= PIPE_ACCESS_OUTBOUND; client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; } if (flags & UV_WRITABLE_PIPE) { server_access |= PIPE_ACCESS_INBOUND; client_access |= GENERIC_WRITE; } /* Create server pipe handle. */ if (uv_stdio_pipe_server(loop, server_pipe, server_access, pipe_name, sizeof(pipe_name)) < 0) { goto error; } /* Create child pipe handle. */ sa.nLength = sizeof sa; sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; child_pipe = CreateFileA(pipe_name, client_access, 0, &sa, OPEN_EXISTING, server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, NULL); if (child_pipe == INVALID_HANDLE_VALUE) { uv__set_sys_error(loop, 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) { uv__set_sys_error(loop, GetLastError()); goto error; } } *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 -1; }
// nTimeout - таймаут подключения HANDLE ExecuteOpenPipe(const wchar_t* szPipeName, wchar_t (&szErr)[MAX_PATH*2], const wchar_t* szModule, DWORD nServerPID, DWORD nTimeout) { HANDLE hPipe = NULL; DWORD dwErr = 0, dwMode = 0; BOOL fSuccess = FALSE; DWORD dwStartTick = GetTickCount(); DWORD nSleepError = 10; int nTries = 10; // допустимое количество обломов, отличных от ERROR_PIPE_BUSY. после каждого - Sleep(nSleepError); DWORD nOpenPipeTimeout = nTimeout ? max(nTimeout,EXECUTE_CMD_OPENPIPE_TIMEOUT) : EXECUTE_CMD_OPENPIPE_TIMEOUT; BOOL bWaitPipeRc = FALSE, bWaitCalled = FALSE; DWORD nWaitPipeErr = 0; DWORD nDuration = 0; #ifdef _DEBUG wchar_t szDbgMsg[512], szTitle[128]; #endif _ASSERTE(LocalSecurity()!=NULL); #ifdef _DEBUG BOOL lbServerIsDebugged = FALSE; // WinXP SP1 и выше typedef BOOL (WINAPI* CheckRemoteDebuggerPresent_t)(HANDLE hProcess, PBOOL pbDebuggerPresent); static CheckRemoteDebuggerPresent_t _CheckRemoteDebuggerPresent = NULL; if (nServerPID) { if (!_CheckRemoteDebuggerPresent) _CheckRemoteDebuggerPresent = (CheckRemoteDebuggerPresent_t)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "CheckRemoteDebuggerPresent"); if (_CheckRemoteDebuggerPresent) { HANDLE hProcess = OpenProcess(MY_PROCESS_ALL_ACCESS, FALSE, nServerPID); if (hProcess) { BOOL lb = FALSE; if (_CheckRemoteDebuggerPresent(hProcess, &lb) && lb) lbServerIsDebugged = TRUE; CloseHandle(hProcess); } } } #endif // Try to open a named pipe; wait for it, if necessary. while (1) { hPipe = CreateFile( szPipeName, // pipe name GENERIC_READ|GENERIC_WRITE, 0, // no sharing LocalSecurity(), // default security attributes OPEN_EXISTING, // opens existing pipe 0, // default attributes NULL); // no template file dwErr = GetLastError(); // Break if the pipe handle is valid. if (hPipe != INVALID_HANDLE_VALUE) break; // OK, открыли #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); msprintf(szDbgMsg, countof(szDbgMsg), L"Can't open pipe, ErrCode=%u\n%s\nWait: %u,%u,%u", dwErr, szPipeName, bWaitCalled, bWaitPipeRc, nWaitPipeErr); int nBtn = ::MessageBox(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL|MB_RETRYCANCEL); if (nBtn == IDCANCEL) return NULL; } #endif nDuration = GetTickCount() - dwStartTick; if (dwErr == ERROR_PIPE_BUSY) { if ((nTries > 0) && (nDuration < nOpenPipeTimeout)) { bWaitCalled = TRUE; // All pipe instances are busy, so wait for 500 ms. bWaitPipeRc = WaitNamedPipe(szPipeName, 500); nWaitPipeErr = GetLastError(); UNREFERENCED_PARAMETER(bWaitPipeRc); UNREFERENCED_PARAMETER(nWaitPipeErr); // -- 120602 раз они заняты (но живы), то будем ждать, пока не освободятся //nTries--; continue; } else { _ASSERTEX(dwErr != ERROR_PIPE_BUSY); } } // Сделаем так, чтобы хотя бы пару раз он попробовал повторить if ((nTries <= 0) || (nDuration > nOpenPipeTimeout)) { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X, Timeout", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); } return NULL; } else { nTries--; } // Может быть пайп еще не создан (в процессе срабатывания семафора) if (dwErr == ERROR_FILE_NOT_FOUND) { Sleep(nSleepError); continue; } // Exit if an error other than ERROR_PIPE_BUSY occurs. // -- if (dwErr != ERROR_PIPE_BUSY) // уже проверено выше { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); } return NULL; } // Уже сделано выше //// All pipe instances are busy, so wait for 500 ms. //WaitNamedPipe(szPipeName, 500); //if (!WaitNamedPipe(szPipeName, 1000) ) //{ // dwErr = GetLastError(); // if (pszErr) // { // StringCchPrintf(pszErr, countof(pszErr), L"%s: WaitNamedPipe(%s) failed, code=0x%08X, WaitNamedPipe", // szModule ? szModule : L"Unknown", szPipeName, dwErr); // // Видимо это возникает в момент запуска (обычно для ShiftEnter - новая консоль) // // не сразу срабатывает GUI и RCon еще не создал Pipe для HWND консоли // _ASSERTE(dwErr == 0); // } // return NULL; //} } #ifdef _DEBUG DWORD nCurState = 0, nCurInstances = 0; BOOL bCurState = GetNamedPipeHandleState(hPipe, &nCurState, &nCurInstances, NULL, NULL, NULL, 0); #endif // The pipe connected; change to message-read mode. dwMode = PIPE_READMODE_MESSAGE; fSuccess = SetNamedPipeHandleState( hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL); // don't set maximum time #if 0 if (!fSuccess) { dwErr = GetLastError(); _ASSERTE(fSuccess); //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: SetNamedPipeHandleState(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); #ifdef _DEBUG int nCurLen = lstrlen(szErr); msprintf(szErr+nCurLen, countof(szErr)-nCurLen, L"\nCurState: %u,x%08X,%u", bCurState, nCurState, nCurInstances); #endif } CloseHandle(hPipe); #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); ::MessageBox(NULL, szErr, szTitle, MB_SYSTEMMODAL); } #endif return NULL; } #endif return hPipe; }
ssize_t rpl_write (int fd, const void *buf, size_t count) { for (;;) { ssize_t ret = write_nothrow (fd, buf, count); if (ret < 0) { # if GNULIB_NONBLOCKING if (errno == ENOSPC) { HANDLE h = (HANDLE) _get_osfhandle (fd); if (GetFileType (h) == FILE_TYPE_PIPE) { /* h is a pipe or socket. */ DWORD state; if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0) && (state & PIPE_NOWAIT) != 0) { /* h is a pipe in non-blocking mode. We can get here in four situations: 1. When the pipe buffer is full. 2. When count <= pipe_buf_size and the number of free bytes in the pipe buffer is < count. 3. When count > pipe_buf_size and the number of free bytes in the pipe buffer is > 0, < pipe_buf_size. 4. When count > pipe_buf_size and the pipe buffer is entirely empty. The cases 1 and 2 are POSIX compliant. In cases 3 and 4 POSIX specifies that write() must split the request and succeed with a partial write. We fix case 4. We don't fix case 3 because it is not essential for programs. */ DWORD out_size; /* size of the buffer for outgoing data */ DWORD in_size; /* size of the buffer for incoming data */ if (GetNamedPipeInfo (h, NULL, &out_size, &in_size, NULL)) { size_t reduced_count = count; /* In theory we need only one of out_size, in_size. But I don't know which of the two. The description is ambiguous. */ if (out_size != 0 && out_size < reduced_count) reduced_count = out_size; if (in_size != 0 && in_size < reduced_count) reduced_count = in_size; if (reduced_count < count) { /* Attempt to write only the first part. */ count = reduced_count; continue; } } /* Change errno from ENOSPC to EAGAIN. */ errno = EAGAIN; } } } else # endif { # if GNULIB_SIGPIPE if (GetLastError () == ERROR_NO_DATA && GetFileType ((HANDLE) _get_osfhandle (fd)) == FILE_TYPE_PIPE) { /* Try to raise signal SIGPIPE. */ raise (SIGPIPE); /* If it is currently blocked or ignored, change errno from EINVAL to EPIPE. */ errno = EPIPE; } # endif } } return ret; } }
// nTimeout - таймаут подключения HANDLE ExecuteOpenPipe(const wchar_t* szPipeName, wchar_t (&szErr)[MAX_PATH*2], const wchar_t* szModule, DWORD nServerPID, DWORD nTimeout, BOOL Overlapped /*= FALSE*/, HANDLE hStop /*= NULL*/) { HANDLE hPipe = NULL; DWORD dwErr = 0, dwMode = 0; BOOL fSuccess = FALSE; DWORD dwStartTick = GetTickCount(); DWORD nSleepError = 10; // допустимое количество обломов, отличных от ERROR_PIPE_BUSY. после каждого - Sleep(nSleepError); int nTries = 10; // nTimeout должен ограничивать ВЕРХНЮЮ границу времени ожидания _ASSERTE(EXECUTE_CMD_OPENPIPE_TIMEOUT >= nTimeout); DWORD nOpenPipeTimeout = nTimeout ? min(nTimeout,EXECUTE_CMD_OPENPIPE_TIMEOUT) : EXECUTE_CMD_OPENPIPE_TIMEOUT; _ASSERTE(nOpenPipeTimeout > 0); DWORD nWaitPipeTimeout = min(250,nOpenPipeTimeout); BOOL bWaitPipeRc = FALSE, bWaitCalled = FALSE; DWORD nWaitPipeErr = 0; DWORD nDuration = 0; DWORD nStopWaitRc = (DWORD)-1; #ifdef _DEBUG wchar_t szDbgMsg[512], szTitle[128]; #endif // WinXP SP1 и выше DEBUGTEST(BOOL lbServerIsDebugged = nServerPID ? IsProcessDebugged(nServerPID) : FALSE); _ASSERTE(LocalSecurity()!=NULL); // Try to open a named pipe; wait for it, if necessary. while (1) { hPipe = CreateFile( szPipeName, // pipe name GENERIC_READ|GENERIC_WRITE, 0, // no sharing LocalSecurity(), // default security attributes OPEN_EXISTING, // opens existing pipe (Overlapped ? FILE_FLAG_OVERLAPPED : 0), // default attributes NULL); // no template file dwErr = GetLastError(); // Break if the pipe handle is valid. if (hPipe != INVALID_HANDLE_VALUE) { _ASSERTE(hPipe); break; // OK, открыли } #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); msprintf(szDbgMsg, countof(szDbgMsg), L"Can't open pipe, ErrCode=%u\n%s\nWait: %u,%u,%u", dwErr, szPipeName, bWaitCalled, bWaitPipeRc, nWaitPipeErr); int nBtn = ::MessageBox(NULL, szDbgMsg, szTitle, MB_SYSTEMMODAL|MB_RETRYCANCEL); if (nBtn == IDCANCEL) return NULL; } #endif nDuration = GetTickCount() - dwStartTick; if (hStop) { // Затребовано завершение приложения или еще что-то nStopWaitRc = WaitForSingleObject(hStop, 0); if (nStopWaitRc == WAIT_OBJECT_0) { return NULL; } } if (dwErr == ERROR_PIPE_BUSY) { if ((nTries > 0) && (nDuration < nOpenPipeTimeout)) { bWaitCalled = TRUE; // All pipe instances are busy, so wait for a while (not more 500 ms). bWaitPipeRc = WaitNamedPipe(szPipeName, nWaitPipeTimeout); nWaitPipeErr = GetLastError(); UNREFERENCED_PARAMETER(bWaitPipeRc); UNREFERENCED_PARAMETER(nWaitPipeErr); // -- 120602 раз они заняты (но живы), то будем ждать, пока не освободятся //nTries--; continue; } else { _ASSERTEX(dwErr != ERROR_PIPE_BUSY); } } // Сделаем так, чтобы хотя бы пару раз он попробовал повторить if ((nTries <= 0) || (nDuration > nOpenPipeTimeout)) { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X, Timeout", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); _ASSERTEX(FALSE && "Pipe open failed with timeout!"); } return NULL; } else { nTries--; } // Может быть пайп еще не создан (в процессе срабатывания семафора) if (dwErr == ERROR_FILE_NOT_FOUND) { // Wait for a while (10 ms) Sleep(nSleepError); continue; } // Exit if an error other than ERROR_PIPE_BUSY occurs. // -- if (dwErr != ERROR_PIPE_BUSY) // уже проверено выше { //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: CreateFile(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); } return NULL; } // Уже сделано выше //// All pipe instances are busy, so wait for 500 ms. //WaitNamedPipe(szPipeName, 500); //if (!WaitNamedPipe(szPipeName, 1000) ) //{ // dwErr = GetLastError(); // if (pszErr) // { // StringCchPrintf(pszErr, countof(pszErr), L"%s: WaitNamedPipe(%s) failed, code=0x%08X, WaitNamedPipe", // szModule ? szModule : L"Unknown", szPipeName, dwErr); // // Видимо это возникает в момент запуска (обычно для ShiftEnter - новая консоль) // // не сразу срабатывает GUI и RCon еще не создал Pipe для HWND консоли // _ASSERTE(dwErr == 0); // } // return NULL; //} } #ifdef _DEBUG DWORD nCurState = 0, nCurInstances = 0; BOOL bCurState = GetNamedPipeHandleState(hPipe, &nCurState, &nCurInstances, NULL, NULL, NULL, 0); #endif // The pipe connected; change to message-read mode. dwMode = CE_PIPE_READMODE; fSuccess = SetNamedPipeHandleState( hPipe, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL); // don't set maximum time #if 0 if (!fSuccess) { dwErr = GetLastError(); _ASSERTE(fSuccess); //if (pszErr) { msprintf(szErr, countof(szErr), L"%s.%u: SetNamedPipeHandleState(%s) failed, code=0x%08X", ModuleName(szModule), GetCurrentProcessId(), szPipeName, dwErr); #ifdef _DEBUG int nCurLen = lstrlen(szErr); msprintf(szErr+nCurLen, countof(szErr)-nCurLen, L"\nCurState: %u,x%08X,%u", bCurState, nCurState, nCurInstances); #endif } CloseHandle(hPipe); #ifdef _DEBUG if (gbPipeDebugBoxes) { szDbgMsg[0] = 0; GetModuleFileName(NULL, szDbgMsg, countof(szDbgMsg)); msprintf(szTitle, countof(szTitle), L"%s: PID=%u", PointToName(szDbgMsg), GetCurrentProcessId()); ::MessageBox(NULL, szErr, szTitle, MB_SYSTEMMODAL); } #endif return NULL; } #endif UNREFERENCED_PARAMETER(bWaitCalled); UNREFERENCED_PARAMETER(fSuccess); return hPipe; }
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; 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; child_pipe = CreateFileA(pipe_name, client_access, 0, &sa, OPEN_EXISTING, server_pipe->ipc ? 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; }
RTDECL(int) RTPipeFromNative(PRTPIPE phPipe, RTHCINTPTR hNativePipe, uint32_t fFlags) { AssertPtrReturn(phPipe, VERR_INVALID_POINTER); AssertReturn(!(fFlags & ~RTPIPE_N_VALID_MASK), VERR_INVALID_PARAMETER); AssertReturn(!!(fFlags & RTPIPE_N_READ) != !!(fFlags & RTPIPE_N_WRITE), VERR_INVALID_PARAMETER); /* * Get and validate the pipe handle info. */ HANDLE hNative = (HANDLE)hNativePipe; AssertReturn(GetFileType(hNative) == FILE_TYPE_PIPE, VERR_INVALID_HANDLE); DWORD cMaxInstances; DWORD fInfo; if (!GetNamedPipeInfo(hNative, &fInfo, NULL, NULL, &cMaxInstances)) return RTErrConvertFromWin32(GetLastError()); AssertReturn(!(fInfo & PIPE_TYPE_MESSAGE), VERR_INVALID_HANDLE); AssertReturn(cMaxInstances == 1, VERR_INVALID_HANDLE); DWORD cInstances; DWORD fState; if (!GetNamedPipeHandleState(hNative, &fState, &cInstances, NULL, NULL, NULL, 0)) return RTErrConvertFromWin32(GetLastError()); AssertReturn(!(fState & PIPE_NOWAIT), VERR_INVALID_HANDLE); AssertReturn(!(fState & PIPE_READMODE_MESSAGE), VERR_INVALID_HANDLE); AssertReturn(cInstances <= 1, VERR_INVALID_HANDLE); /* * Looks kind of OK, create a handle so we can try rtPipeQueryInfo on it * and see if we need to duplicate it to make that call work. */ RTPIPEINTERNAL *pThis = (RTPIPEINTERNAL *)RTMemAllocZ(sizeof(RTPIPEINTERNAL)); if (!pThis) return VERR_NO_MEMORY; int rc = RTCritSectInit(&pThis->CritSect); if (RT_SUCCESS(rc)) { pThis->Overlapped.hEvent = CreateEvent(NULL, TRUE /*fManualReset*/, TRUE /*fInitialState*/, NULL /*pName*/); if (pThis->Overlapped.hEvent != NULL) { pThis->u32Magic = RTPIPE_MAGIC; pThis->hPipe = hNative; pThis->fRead = !!(fFlags & RTPIPE_N_READ); //pThis->fIOPending = false; //pThis->fZeroByteRead = false; //pThis->fBrokenPipe = false; //pThisR->fPromisedWritable= false; //pThis->cUsers = 0; //pThis->pbBounceBuf = NULL; //pThis->cbBounceBufUsed = 0; //pThis->cbBounceBufAlloc= 0; pThis->hPollSet = NIL_RTPOLLSET; HANDLE hNative2 = INVALID_HANDLE_VALUE; FILE_PIPE_LOCAL_INFORMATION Info; if (rtPipeQueryInfo(pThis, &Info)) rc = VINF_SUCCESS; else { if (DuplicateHandle(GetCurrentProcess() /*hSrcProcess*/, hNative /*hSrcHandle*/, GetCurrentProcess() /*hDstProcess*/, &hNative2 /*phDstHandle*/, pThis->fRead ? GENERIC_READ : GENERIC_WRITE | FILE_READ_ATTRIBUTES /*dwDesiredAccess*/, !!(fFlags & RTPIPE_N_INHERIT) /*fInheritHandle*/, 0 /*dwOptions*/)) { pThis->hPipe = hNative2; if (rtPipeQueryInfo(pThis, &Info)) rc = VINF_SUCCESS; else { rc = VERR_ACCESS_DENIED; CloseHandle(hNative2); } } else hNative2 = INVALID_HANDLE_VALUE; } if (RT_SUCCESS(rc)) { /* * Verify the pipe state and correct the inheritability. */ AssertStmt( Info.NamedPipeState == FILE_PIPE_CONNECTED_STATE || Info.NamedPipeState == FILE_PIPE_CLOSING_STATE || Info.NamedPipeState == FILE_PIPE_DISCONNECTED_STATE, VERR_INVALID_HANDLE); AssertStmt( Info.NamedPipeConfiguration == ( Info.NamedPipeEnd == FILE_PIPE_SERVER_END ? (pThis->fRead ? FILE_PIPE_INBOUND : FILE_PIPE_OUTBOUND) : (pThis->fRead ? FILE_PIPE_OUTBOUND : FILE_PIPE_INBOUND) ), VERR_INVALID_HANDLE); if ( RT_SUCCESS(rc) && hNative2 == INVALID_HANDLE_VALUE && !SetHandleInformation(hNative, HANDLE_FLAG_INHERIT /*dwMask*/, fFlags & RTPIPE_N_INHERIT ? HANDLE_FLAG_INHERIT : 0)) { rc = RTErrConvertFromWin32(GetLastError()); AssertMsgFailed(("%Rrc\n", rc)); } if (RT_SUCCESS(rc)) { /* * Ok, we're good! */ if (hNative2 != INVALID_HANDLE_VALUE) CloseHandle(hNative); *phPipe = pThis; return VINF_SUCCESS; } } /* Bail out. */ if (hNative2 != INVALID_HANDLE_VALUE) CloseHandle(hNative2); CloseHandle(pThis->Overlapped.hEvent); } RTCritSectDelete(&pThis->CritSect); } RTMemFree(pThis); return rc; }