bool CEC_LogicalDevice::TransmitWait(int targetAddress, unsigned char* buffer, int count) { while (_waitingTransmit){ Run(); } _waitingTransmit = true; _transmitResult = false; if (!TransmitFrame(targetAddress, buffer, count)) { _waitingTransmit = false; return false; } while (_waitingTransmit){ Run(); } return _transmitResult; }
nsresult Http2PushedStream::ReadSegments(nsAHttpSegmentReader *reader, uint32_t, uint32_t *count) { nsresult rv = NS_OK; *count = 0; switch (mUpstreamState) { case GENERATING_HEADERS: // The request headers for this has been processed, so we need to verify // that :authority, :scheme, and :path MUST be present. :method MUST NOT be // present CreatePushHashKey(mHeaderScheme, mHeaderHost, mSession->Serial(), mHeaderPath, mOrigin, mHashKey); LOG3(("Http2PushStream 0x%X hash key %s\n", mStreamID, mHashKey.get())); // the write side of a pushed transaction just involves manipulating a little state SetSentFin(true); Http2Stream::mRequestHeadersDone = 1; Http2Stream::mOpenGenerated = 1; Http2Stream::ChangeState(UPSTREAM_COMPLETE); break; case UPSTREAM_COMPLETE: // Let's just clear the stream's transmit buffer by pushing it into // the session. This is probably a window adjustment. LOG3(("Http2Push::ReadSegments 0x%X \n", mStreamID)); mSegmentReader = reader; rv = TransmitFrame(nullptr, nullptr, true); mSegmentReader = nullptr; break; case GENERATING_BODY: case SENDING_BODY: case SENDING_FIN_STREAM: default: break; } return rv; }
nsresult SpdyStream::OnReadSegment(const char *buf, PRUint32 count, PRUint32 *countRead) { LOG3(("SpdyStream::OnReadSegment %p count=%d state=%x", this, count, mUpstreamState)); NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); NS_ABORT_IF_FALSE(mSegmentReader, "OnReadSegment with null mSegmentReader"); nsresult rv = NS_ERROR_UNEXPECTED; PRUint32 dataLength; switch (mUpstreamState) { case GENERATING_SYN_STREAM: // The buffer is the HTTP request stream, including at least part of the // HTTP request header. This state's job is to build a SYN_STREAM frame // from the header information. count is the number of http bytes available // (which may include more than the header), and in countRead we return // the number of those bytes that we consume (i.e. the portion that are // header bytes) rv = ParseHttpRequestHeaders(buf, count, countRead); if (NS_FAILED(rv)) return rv; LOG3(("ParseHttpRequestHeaders %p used %d of %d. complete = %d", this, *countRead, count, mSynFrameComplete)); if (mSynFrameComplete) { NS_ABORT_IF_FALSE(mTxInlineFrameSize, "OnReadSegment SynFrameComplete 0b"); rv = TransmitFrame(nsnull, nsnull); if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead) rv = NS_OK; if (mTxInlineFrameSize) ChangeState(SENDING_SYN_STREAM); else ChangeState(GENERATING_REQUEST_BODY); break; } NS_ABORT_IF_FALSE(*countRead == count, "Header parsing not complete but unused data"); break; case GENERATING_REQUEST_BODY: NS_ABORT_IF_FALSE(!mTxInlineFrameSent, "OnReadSegment in generating_request_body with " "frame in progress"); dataLength = NS_MIN(count, mChunkSize); LOG3(("SpdyStream %p id %x request len remaining %d, " "count avail %d, chunk used %d", this, mStreamID, mRequestBodyLen, count, dataLength)); if (dataLength > mRequestBodyLen) return NS_ERROR_UNEXPECTED; mRequestBodyLen -= dataLength; GenerateDataFrameHeader(dataLength, !mRequestBodyLen); ChangeState(SENDING_REQUEST_BODY); // NO BREAK case SENDING_REQUEST_BODY: NS_ABORT_IF_FALSE(mTxInlineFrameSize, "OnReadSegment Send Data Header 0b"); rv = TransmitFrame(buf, countRead); LOG3(("TransmitFrame() rv=%x returning %d data bytes. " "Header is %d/%d Body is %d/%d.", rv, *countRead, mTxInlineFrameSent, mTxInlineFrameSize, mTxStreamFrameSent, mTxStreamFrameSize)); if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead) rv = NS_OK; // If that frame was all sent, look for another one if (!mTxInlineFrameSize) ChangeState(GENERATING_REQUEST_BODY); break; case SENDING_SYN_STREAM: rv = NS_BASE_STREAM_WOULD_BLOCK; break; case SENDING_FIN_STREAM: NS_ABORT_IF_FALSE(false, "resuming partial fin stream out of OnReadSegment"); break; default: NS_ABORT_IF_FALSE(false, "SpdyStream::OnReadSegment non-write state"); break; } return rv; }
nsresult SpdyStream::ReadSegments(nsAHttpSegmentReader *reader, PRUint32 count, PRUint32 *countRead) { LOG3(("SpdyStream %p ReadSegments reader=%p count=%d state=%x", this, reader, count, mUpstreamState)); NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); nsresult rv = NS_ERROR_UNEXPECTED; mBlockedOnWrite = 0; mRequestBlockedOnRead = 0; switch (mUpstreamState) { case GENERATING_SYN_STREAM: case GENERATING_REQUEST_BODY: case SENDING_REQUEST_BODY: // Call into the HTTP Transaction to generate the HTTP request // stream. That stream will show up in OnReadSegment(). mSegmentReader = reader; rv = mTransaction->ReadSegments(this, count, countRead); mSegmentReader = nsnull; if (NS_SUCCEEDED(rv) && mUpstreamState == GENERATING_SYN_STREAM && !mSynFrameComplete) mBlockedOnWrite = 1; // Mark that we are blocked on read if we the http transaction // is going to get us going again. if (rv == NS_BASE_STREAM_WOULD_BLOCK && !mBlockedOnWrite) mRequestBlockedOnRead = 1; if (!mBlockedOnWrite && NS_SUCCEEDED(rv) && (!*countRead)) { LOG3(("ReadSegments %p Send Request data complete from %x", this, mUpstreamState)); if (mSentFinOnData) { ChangeState(UPSTREAM_COMPLETE); } else { GenerateDataFrameHeader(0, true); ChangeState(SENDING_FIN_STREAM); mBlockedOnWrite = 1; rv = NS_BASE_STREAM_WOULD_BLOCK; } } break; case SENDING_SYN_STREAM: // We were trying to send the SYN-STREAM but only got part of it out // before being blocked. Try and send more. mSegmentReader = reader; rv = TransmitFrame(nsnull, nsnull); mSegmentReader = nsnull; *countRead = 0; if (NS_SUCCEEDED(rv)) rv = NS_BASE_STREAM_WOULD_BLOCK; if (!mTxInlineFrameSize) { if (mSentFinOnData) { ChangeState(UPSTREAM_COMPLETE); rv = NS_OK; } else { ChangeState(GENERATING_REQUEST_BODY); mBlockedOnWrite = 1; } } break; case SENDING_FIN_STREAM: // We were trying to send the SYN-STREAM but only got part of it out // before being blocked. Try and send more. if (!mSentFinOnData) { mSegmentReader = reader; rv = TransmitFrame(nsnull, nsnull); mSegmentReader = nsnull; if (!mTxInlineFrameSize) ChangeState(UPSTREAM_COMPLETE); } else { rv = NS_OK; mTxInlineFrameSize = 0; // cancel fin data packet ChangeState(UPSTREAM_COMPLETE); } *countRead = 0; // don't change OK to WOULD BLOCK. we are really done sending if OK break; default: NS_ABORT_IF_FALSE(false, "SpdyStream::ReadSegments unknown state"); break; } return rv; }
nsresult SpdyStream2::OnReadSegment(const char *buf, uint32_t count, uint32_t *countRead) { LOG3(("SpdyStream2::OnReadSegment %p count=%d state=%x", this, count, mUpstreamState)); NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); NS_ABORT_IF_FALSE(mSegmentReader, "OnReadSegment with null mSegmentReader"); nsresult rv = NS_ERROR_UNEXPECTED; uint32_t dataLength; switch (mUpstreamState) { case GENERATING_SYN_STREAM: // The buffer is the HTTP request stream, including at least part of the // HTTP request header. This state's job is to build a SYN_STREAM frame // from the header information. count is the number of http bytes available // (which may include more than the header), and in countRead we return // the number of those bytes that we consume (i.e. the portion that are // header bytes) rv = ParseHttpRequestHeaders(buf, count, countRead); if (NS_FAILED(rv)) return rv; LOG3(("ParseHttpRequestHeaders %p used %d of %d. complete = %d", this, *countRead, count, mSynFrameComplete)); if (mSynFrameComplete) { NS_ABORT_IF_FALSE(mTxInlineFrameUsed, "OnReadSegment SynFrameComplete 0b"); rv = TransmitFrame(nullptr, nullptr, true); if (rv == NS_BASE_STREAM_WOULD_BLOCK) { // this can't happen NS_ABORT_IF_FALSE(false, "Transmit Frame SYN_FRAME must at least buffer data"); rv = NS_ERROR_UNEXPECTED; } ChangeState(GENERATING_REQUEST_BODY); break; } NS_ABORT_IF_FALSE(*countRead == count, "Header parsing not complete but unused data"); break; case GENERATING_REQUEST_BODY: dataLength = std::min(count, mChunkSize); LOG3(("SpdyStream2 %p id %x request len remaining %d, " "count avail %d, chunk used %d", this, mStreamID, mRequestBodyLenRemaining, count, dataLength)); if (dataLength > mRequestBodyLenRemaining) return NS_ERROR_UNEXPECTED; mRequestBodyLenRemaining -= dataLength; GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining); ChangeState(SENDING_REQUEST_BODY); // NO BREAK case SENDING_REQUEST_BODY: NS_ABORT_IF_FALSE(mTxInlineFrameUsed, "OnReadSegment Send Data Header 0b"); rv = TransmitFrame(buf, countRead, false); NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed, "Transmit Frame should be all or nothing"); LOG3(("TransmitFrame() rv=%x returning %d data bytes. " "Header is %d Body is %d.", rv, *countRead, mTxInlineFrameUsed, mTxStreamFrameSize)); // normalize a partial write with a WOULD_BLOCK into just a partial write // as some code will take WOULD_BLOCK to mean an error with nothing // written (e.g. nsHttpTransaction::ReadRequestSegment() if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead) rv = NS_OK; // If that frame was all sent, look for another one if (!mTxInlineFrameUsed) ChangeState(GENERATING_REQUEST_BODY); break; case SENDING_FIN_STREAM: NS_ABORT_IF_FALSE(false, "resuming partial fin stream out of OnReadSegment"); break; default: NS_ABORT_IF_FALSE(false, "SpdyStream2::OnReadSegment non-write state"); break; } return rv; }
nsresult SpdyStream2::ReadSegments(nsAHttpSegmentReader *reader, uint32_t count, uint32_t *countRead) { LOG3(("SpdyStream2 %p ReadSegments reader=%p count=%d state=%x", this, reader, count, mUpstreamState)); NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); nsresult rv = NS_ERROR_UNEXPECTED; mRequestBlockedOnRead = 0; switch (mUpstreamState) { case GENERATING_SYN_STREAM: case GENERATING_REQUEST_BODY: case SENDING_REQUEST_BODY: // Call into the HTTP Transaction to generate the HTTP request // stream. That stream will show up in OnReadSegment(). mSegmentReader = reader; rv = mTransaction->ReadSegments(this, count, countRead); mSegmentReader = nullptr; // Check to see if the transaction's request could be written out now. // If not, mark the stream for callback when writing can proceed. if (NS_SUCCEEDED(rv) && mUpstreamState == GENERATING_SYN_STREAM && !mSynFrameComplete) mSession->TransactionHasDataToWrite(this); // mTxinlineFrameUsed represents any queued un-sent frame. It might // be 0 if there is no such frame, which is not a gurantee that we // don't have more request body to send - just that any data that was // sent comprised a complete SPDY frame. Likewise, a non 0 value is // a queued, but complete, spdy frame length. // Mark that we are blocked on read if the http transaction needs to // provide more of the request message body and there is nothing queued // for writing if (rv == NS_BASE_STREAM_WOULD_BLOCK && !mTxInlineFrameUsed) mRequestBlockedOnRead = 1; if (!mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) { LOG3(("ReadSegments %p: Sending request data complete, mUpstreamState=%x", this, mUpstreamState)); if (mSentFinOnData) { ChangeState(UPSTREAM_COMPLETE); } else { GenerateDataFrameHeader(0, true); ChangeState(SENDING_FIN_STREAM); mSession->TransactionHasDataToWrite(this); rv = NS_BASE_STREAM_WOULD_BLOCK; } } break; case SENDING_FIN_STREAM: // We were trying to send the FIN-STREAM but were blocked from // sending it out - try again. if (!mSentFinOnData) { mSegmentReader = reader; rv = TransmitFrame(nullptr, nullptr, false); mSegmentReader = nullptr; NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed, "Transmit Frame should be all or nothing"); if (NS_SUCCEEDED(rv)) ChangeState(UPSTREAM_COMPLETE); } else { rv = NS_OK; mTxInlineFrameUsed = 0; // cancel fin data packet ChangeState(UPSTREAM_COMPLETE); } *countRead = 0; // don't change OK to WOULD BLOCK. we are really done sending if OK break; case UPSTREAM_COMPLETE: *countRead = 0; rv = NS_OK; break; default: NS_ABORT_IF_FALSE(false, "SpdyStream2::ReadSegments unknown state"); break; } return rv; }