/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * Both blocking/non-blocking mode are supported in this class. * The default mode is non-blocking mode, however, the client may change its * mode to blocking mode during hand-shaking (e.g. nsSOCKSSocketInfo). * * In non-blocking mode, |Read| and |Write| should be called by clients only * when |GetPollFlags| reports data availability. That is, the client calls * |GetPollFlags| with |PR_POLL_READ| and/or |PR_POLL_WRITE| set, and * according to the flags that set, |GetPollFlags| will check buffers status * and decide corresponding actions: * * ------------------------------------------------------------------- * | | data in buffer | empty buffer | * |---------------+-------------------------+-----------------------| * | PR_POLL_READ | out: PR_POLL_READ | DoRead/DoReadContinue | * |---------------+-------------------------+-----------------------| * | PR_POLL_WRITE | DoWrite/DoWriteContinue | out: PR_POLL_WRITE | * ------------------------------------------+------------------------ * * |DoRead| and |DoWrite| initiate read/write operations asynchronously, and * the |DoReadContinue| and |DoWriteContinue| are used to check the amount * of the data are read/written to/from buffers. * * The output parameter and the return value of |GetPollFlags| are identical * because we don't rely on the low-level select function to wait for data * availability, we instead use nsNamedPipeService to poll I/O completeness. * * When client get |PR_POLL_READ| or |PR_POLL_WRITE| from |GetPollFlags|, * they are able to use |Read| or |Write| to access the data in the buffer, * and this is supposed to be very fast because no network traffic is * involved. * * In blocking mode, the flow is quite similar to non-blocking mode, but * |DoReadContinue| and |DoWriteContinue| are never been used since the * operations are done synchronously, which could lead to slow responses.
*/
int32_t Read(void* aBuffer, int32_t aSize);
int32_t Write(constvoid* aBuffer, int32_t aSize);
// Like Read, but doesn't remove data in internal buffer.
uint32_t Peek(void* aBuffer, int32_t aSize);
// Number of bytes available to read in internal buffer.
int32_t Available() const;
// Flush write buffer // // @return whether the buffer has been flushed bool Sync(uint32_t aTimeout); void SetNonblocking(bool nonblocking);
// Initiate and check current status for read/write operations.
int16_t GetPollFlags(int16_t aInFlags, int16_t* aOutFlags);
private: virtual ~NamedPipeInfo();
/** * DoRead/DoWrite starts a read/write call synchronously or asynchronously * depending on |mNonblocking|. In blocking mode, they return when the action * has been done and in non-blocking mode it returns the number of bytes that * were read/written if the operation is done immediately. If it takes some * time to finish the operation, zero is returned and * DoReadContinue/DoWriteContinue must be called to get async I/O result.
*/
int32_t DoRead();
int32_t DoReadContinue();
int32_t DoWrite();
int32_t DoWriteContinue();
/** * There was a write size limitation of named pipe, * see https://support.microsoft.com/en-us/kb/119218 for more information. * The limitation no longer exists, so feel free to change the value.
*/ staticconst uint32_t kBufferSize = 65536;
nsCOMPtr<nsINamedPipeService> mNamedPipeService;
HANDLE mPipe; // the handle to the named pipe.
OVERLAPPED mReadOverlapped; // used for asynchronous read operations.
OVERLAPPED mWriteOverlapped; // used for asynchronous write operations.
uint8_t mReadBuffer[kBufferSize]; // octets read from pipe.
/** * These indicates the [begin, end) position of the data in the buffer.
*/
DWORD mReadBegin;
DWORD mReadEnd;
bool mHasPendingRead; // previous asynchronous read is not finished yet.
uint8_t mWriteBuffer[kBufferSize]; // octets to be written to pipe.
/** * These indicates the [begin, end) position of the data in the buffer.
*/
DWORD mWriteBegin; // how many bytes are already written.
DWORD mWriteEnd; // valid amount of data in the buffer.
bool mHasPendingWrite; // previous asynchronous write is not finished yet.
/** * current blocking mode is non-blocking or not, accessed only in socket * thread.
*/ bool mNonblocking;
Atomic<DWORD> mErrorCode; // error code from Named Pipe Service.
};
/** * 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);
/** * 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);
// 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;
}
int32_t NamedPipeInfo::Available() const {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(mReadBegin <= mReadEnd);
MOZ_ASSERT(mReadEnd - mReadBegin <= 0x7FFFFFFF); // no more than int32_max return mReadEnd - mReadBegin;
}
bool NamedPipeInfo::Sync(uint32_t aTimeout) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread"); if (!mHasPendingWrite) { returntrue;
} return WaitForSingleObject(mWriteOverlapped.hEvent, aTimeout) ==
WAIT_OBJECT_0;
}
if (aInFlags & PR_POLL_READ) {
int32_t bytesToRead = 0; if (mReadBegin < mReadEnd) { // data in buffer and is ready to be read
bytesToRead = Available();
} elseif (mHasPendingRead) { // nonblocking I/O and has pending task
bytesToRead = DoReadContinue();
} else { // read bufer is empty.
bytesToRead = DoRead();
}
// @return: data has been read and is available
int32_t NamedPipeInfo::DoRead() {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(!mHasPendingRead);
MOZ_ASSERT(mReadBegin == mReadEnd); // the buffer should be empty
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.