int32_t NamedPipeInfo::DoWrite() { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(!mHasPendingWrite); MOZ_ASSERT(mWriteBegin < mWriteEnd); DWORD bytesWritten = 0; BOOL success = WriteFile(mPipe, &mWriteBuffer[mWriteBegin], mWriteEnd - mWriteBegin, &bytesWritten, IsNonblocking() ? &mWriteOverlapped : nullptr); if (success) { mWriteBegin += bytesWritten; LOG_NPIO_DEBUG("[%s][%p] %d bytes written", __func__, this, bytesWritten); return bytesWritten; } if (GetLastError() != ERROR_IO_PENDING) { LOG_NPIO_ERROR("[%s] WriteFile failed (%d)", __func__, GetLastError()); Disconnect(); PR_SetError(PR_IO_ERROR, 0); return -1; } mHasPendingWrite = true; return 0; }
int32_t NamedPipeInfo::Write(const void* aBuffer, int32_t aSize) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(mWriteBegin <= mWriteEnd); if (!IsConnected()) { // pipe unconnected PR_SetError(PR_NOT_CONNECTED_ERROR, 0); return -1; } if (mWriteBegin == mWriteEnd) { mWriteBegin = mWriteEnd = 0; } int32_t bytesToWrite = std::min<int32_t>(aSize, sizeof(mWriteBuffer) - mWriteEnd); MOZ_ASSERT(bytesToWrite >= 0); if (bytesToWrite == 0) { PR_SetError(IsNonblocking() ? PR_WOULD_BLOCK_ERROR : PR_IO_PENDING_ERROR, 0); return -1; } memcpy(&mWriteBuffer[mWriteEnd], aBuffer, bytesToWrite); mWriteEnd += bytesToWrite; /** * Triggers internal write operation by calling |GetPollFlags|. * This is required for callers that use blocking I/O because they don't call * |GetPollFlags| to write data, but this also works for non-blocking I/O. */ int16_t outFlag; GetPollFlags(PR_POLL_WRITE, &outFlag); return bytesToWrite; }
// @return: data has been read and is available int32_t NamedPipeInfo::DoRead() { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(!mHasPendingRead); MOZ_ASSERT(mReadBegin == mReadEnd); // the buffer should be empty mReadBegin = 0; mReadEnd = 0; BOOL success = ReadFile(mPipe, mReadBuffer, sizeof(mReadBuffer), &mReadEnd, IsNonblocking() ? &mReadOverlapped : nullptr); if (success) { LOG_NPIO_DEBUG("[%s][%p] %d bytes read", __func__, this, mReadEnd); return mReadEnd; } switch (GetLastError()) { case ERROR_MORE_DATA: // has more data to read mHasPendingRead = true; return DoReadContinue(); case ERROR_IO_PENDING: // read is pending mHasPendingRead = true; break; default: LOG_NPIO_ERROR("[%s] ReadFile failed (%d)", __func__, GetLastError()); Disconnect(); PR_SetError(PR_IO_ERROR, 0); return -1; } return 0; }
uint32_t NamedPipeInfo::Peek(void* aBuffer, int32_t aSize) { MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(mReadBegin <= mReadEnd); if (!IsConnected()) { // pipe unconnected PR_SetError(PR_NOT_CONNECTED_ERROR, 0); return -1; } /** * If there's nothing in the read buffer, try to trigger internal read * operation by calling |GetPollFlags|. This is required for callers that * use blocking I/O because they don't call |GetPollFlags| to read data, * but this also works for non-blocking I/O. */ if (!Available()) { int16_t outFlag; GetPollFlags(PR_POLL_READ, &outFlag); if (!(outFlag & PR_POLL_READ)) { PR_SetError(IsNonblocking() ? PR_WOULD_BLOCK_ERROR : PR_IO_PENDING_ERROR, 0); return -1; } } // Available() can't return more than what fits to the buffer at the read offset. int32_t bytesRead = std::min<int32_t>(aSize, Available()); MOZ_ASSERT(bytesRead >= 0); MOZ_ASSERT(mReadBegin + bytesRead <= mReadEnd); memcpy(aBuffer, &mReadBuffer[mReadBegin], bytesRead); return bytesRead; }
//------------------------------------------------------------------------------ // // ConnectTCP() - // //------------------------------------------------------------------------------ bool TDSocket::ConnectTCP(const char *pAddr, i16 nPort) { bool bRetVal = false; struct in_addr stIpAddress; //------------------------------------------------------------------ // Preconnection setup that must be preformed //------------------------------------------------------------------ memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); m_stServerSockaddr.sin_family = AF_INET; hostent * pHE = NULL; if ((pHE = GETHOSTBYNAME(pAddr)) == NULL) { #ifdef WIN32 TranslateSocketError(); #else if (h_errno == HOST_NOT_FOUND) { SetSocketError(SocketInvalidAddress); } #endif return bRetVal; } memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; if ((i32)m_stServerSockaddr.sin_addr.s_addr == TDSocket::SocketError) { TranslateSocketError(); return bRetVal; } m_stServerSockaddr.sin_port = htons(nPort); //------------------------------------------------------------------ // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. // //------------------------------------------------------------------ if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) == TDSocket::SocketError) { //-------------------------------------------------------------- // Get error value this might be a non-blocking socket so we // must first check. //-------------------------------------------------------------- TranslateSocketError(); //-------------------------------------------------------------- // If the socket is non-blocking and the current socket error // is SocketEinprogress or SocketEwouldblock then poll connection // with select for designated timeout period. // Linux returns EINPROGRESS and Windows returns WSAEWOULDBLOCK. //-------------------------------------------------------------- if ((IsNonblocking()) && ((GetSocketError() == TDSocket::SocketEwouldblock) || (GetSocketError() == TDSocket::SocketEinprogress))) { bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec()); } } else { TranslateSocketError(); bRetVal = true; } return bRetVal; }