示例#1
0
void HTTPRequest::AppendDateField()
{
    Assert(OSThread::GetCurrent() != NULL);
    DateBuffer* theDateBuffer = OSThread::GetCurrent()->GetDateBuffer();
    theDateBuffer->InexactUpdate(); // Update the date buffer to the current date & time
    StrPtrLen theDate(theDateBuffer->GetDateBuffer(), DateBuffer::kDateBufferLen);
  
    // Append date
    this->AppendResponseHeader(httpDateHeader, &theDate);
}
示例#2
0
void HTTPRequest::AppendDateAndExpiresFields()
{
    Assert(OSThread::GetCurrent() != NULL);
    DateBuffer* theDateBuffer = OSThread::GetCurrent()->GetDateBuffer();
    theDateBuffer->InexactUpdate(); // Update the date buffer to the current date & time
    StrPtrLen theDate(theDateBuffer->GetDateBuffer(), DateBuffer::kDateBufferLen);
  
    // Append dates, and have this response expire immediately
    this->AppendResponseHeader(httpDateHeader, &theDate);
    this->AppendResponseHeader(httpExpiresHeader, &theDate);
}
void RTSPRequestInterface::AppendDateAndExpires()
{
    if (!fStandardHeadersWritten)
        this->WriteStandardHeaders();

    Assert(OSThread::GetCurrent() != NULL);
    DateBuffer* theDateBuffer = OSThread::GetCurrent()->GetDateBuffer();
    theDateBuffer->InexactUpdate(); // Update the date buffer to the current date & time
    StrPtrLen theDate(theDateBuffer->GetDateBuffer(), DateBuffer::kDateBufferLen);
    
    // Append dates, and have this response expire immediately
    this->AppendHeader(qtssDateHeader, &theDate);
    this->AppendHeader(qtssExpiresHeader, &theDate);
}
QTSS_Error HTTPResponseStream::Flush()
{
    UInt32 amtInBuffer = this->GetCurrentOffset() - fBytesSentInBuffer;
    if (amtInBuffer > 0)
    {
        if (fPrintMSG)
        {
            DateBuffer theDate;
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time

            qtss_printf("\n#S->C:\n#time: ms=%" _U32BITARG_ " date=%s\n", (UInt32)OS::StartTimeMilli_Int(), theDate.GetDateBuffer());
            StrPtrLen str(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer);
            str.PrintStrEOL();
        }

        UInt32 theLengthSent = 0;
        //(void)fSocket->Send(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer, &theLengthSent);

        QTSS_Error theErr = fSocket->Send(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer, &theLengthSent);
        if ((theErr != QTSS_NoErr) && (theErr != EAGAIN))
        {
            return theErr;
        }

        // Refresh the timeout if we were able to send any data
        if (theLengthSent > 0)
            fTimeoutTask->RefreshTimeout();

        if (theLengthSent == amtInBuffer)
        {
            // We were able to send all the data in the buffer. Great. Flush it.
            this->Reset();
            fBytesSentInBuffer = 0;
        }
        else
        {
            // Not all the data was sent, so report an EAGAIN

            fBytesSentInBuffer += theLengthSent;
            Assert(fBytesSentInBuffer < this->GetCurrentOffset());
            return EAGAIN;
        }
    }
    return QTSS_NoErr;
}
/* 先统计buffer中还有多少待送出的数据,再用Socket::Send()向外发送数据.只要能够送出数据,就refresh timeout.假如一次全部送出数据,就flush清空它,否则累计已送出的数据,返回EAGAIN */
QTSS_Error RTSPResponseStream::Flush()
{
	/* 得到剩余数据的长度 */
    UInt32 amtInBuffer = this->GetCurrentOffset() - fBytesSentInBuffer;
    if (amtInBuffer > 0)
    {
		/*********** 逐行打印出剩余数据的信息,注意打印信息就是从这里出来的 **************/
        if (fPrintRTSP)
        {
            DateBuffer theDate;
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time

 			qtss_printf("\n#S->C:\n#time: ms=%lu date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer() );
			StrPtrLen str(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer);
			str.PrintStrEOL();
        }

        UInt32 theLengthSent = 0;
		/* 使用TCPSocket发送出RTSP Response流缓存中剩余的数据,实际发送数据长为theLengthSent */
        (void)fSocket->Send(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer, &theLengthSent);
       
        // Refresh the timeout if we were able to send any data
		/* 只要能发送出数据,就刷新超时 */
        if (theLengthSent > 0)
            fTimeoutTask->RefreshTimeout();
         
		/* 假如成功发送出所有数据,就重置缓冲区指针和已发送数据长度 */
        if (theLengthSent == amtInBuffer)
        {
            // We were able to send all the data in the buffer. Great. Flush it.
            this->Reset();
            fBytesSentInBuffer = 0;
        }
        else
        {
            // Not all the data was sent, so report an EAGAIN
            /* 否则,累计发送出的数据,返回EAGAIN */
            fBytesSentInBuffer += theLengthSent;
            Assert(fBytesSentInBuffer < this->GetCurrentOffset());
            return EAGAIN;
        }
    }
    return QTSS_NoErr;
}
QTSS_Error HTTPResponseStream::WriteV(iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength,
                                            UInt32* outLengthSent, UInt32 inSendType)
{
    QTSS_Error theErr = QTSS_NoErr;
    UInt32 theLengthSent = 0;
    UInt32 amtInBuffer = this->GetCurrentOffset() - fBytesSentInBuffer;
        
    if (amtInBuffer > 0)
    {

        // There is some data in the output buffer. Make sure to send that
        // first, using the empty space in the ioVec.
            
        inVec[0].iov_base = this->GetBufPtr() + fBytesSentInBuffer;
        inVec[0].iov_len = amtInBuffer;
        theErr = fSocket->GetSocket()->WriteV(inVec, inNumVectors, &theLengthSent);
        
		if (fPrintMsg)
		{
            DateBuffer theDate;
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time

 			qtss_printf("\n#S->C:\n#time: ms=%"_U32BITARG_" date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer() );
 			for (UInt32 i =0; i < inNumVectors; i++)
			{   StrPtrLen str((char*)inVec[i].iov_base, (UInt32) inVec[i].iov_len);
				str.PrintStrEOL();
  			}
 		}

        if (theLengthSent >= amtInBuffer)
        {
            // We were able to send all the data in the buffer. Great. Flush it.
            this->Reset();
            fBytesSentInBuffer = 0;
            
            // Make theLengthSent reflect the amount of data sent in the ioVec
            theLengthSent -= amtInBuffer;
        }
        else
        {
            // Uh oh. Not all the data in the buffer was sent. Update the
            // fBytesSentInBuffer count, and set theLengthSent to 0.
            
            fBytesSentInBuffer += theLengthSent;
            Assert(fBytesSentInBuffer < this->GetCurrentOffset());
            theLengthSent = 0;
        }
        // theLengthSent now represents how much data in the ioVec was sent
    }
    else if (inNumVectors > 1)
    {
        theErr = fSocket->GetSocket()->WriteV(&inVec[1], inNumVectors - 1, &theLengthSent);
    }
    // We are supposed to refresh the timeout if there is a successful write.
    if (theErr == QTSS_NoErr)
        fTimeoutTask->RefreshTimeout();
        
    // If there was an error, don't alter anything, just bail
    if ((theErr != QTSS_NoErr) && (theErr != EAGAIN))
        return theErr;
    
    // theLengthSent at this point is the amount of data passed into
    // this function that was sent.
    if (outLengthSent != NULL)
        *outLengthSent = theLengthSent;

    // Update the StringFormatter fBytesWritten variable... this data
    // wasn't buffered in the output buffer at any time, so if we
    // don't do this, this amount would get lost
    fBytesWritten += theLengthSent;
    
    // All of the data was sent... whew!
    if (theLengthSent == inTotalLength)
        return QTSS_NoErr;
    
    // We need to determine now whether to copy the remaining unsent
    // iovec data into the buffer. This is determined based on
    // the inSendType parameter passed in.
    if (inSendType == kDontBuffer)
        return theErr;
    if ((inSendType == kAllOrNothing) && (theLengthSent == 0))
        return EAGAIN;
        
    // Some or none of the iovec data was sent. Copy the remainder into the output
    // buffer.
    
    // The caller should consider this data sent.
    if (outLengthSent != NULL)
        *outLengthSent = inTotalLength;
        
    UInt32 curVec = 1;
    while (theLengthSent >= inVec[curVec].iov_len)
    {
        // Skip over the vectors that were in fact sent.
        Assert(curVec < inNumVectors);
        theLengthSent -= inVec[curVec].iov_len;
        curVec++;
    }
    
    while (curVec < inNumVectors)
    {
        // Copy the remaining vectors into the buffer
        this->Put(  ((char*)inVec[curVec].iov_base) + theLengthSent,
                    inVec[curVec].iov_len - theLengthSent);
        theLengthSent = 0;
        curVec++;       
    }
    return QTSS_NoErr;
}
QTSS_Error HTTPResponseStream::Flush()
{
	QTSS_Error theErr = QTSS_NoErr;

	while(true)
	{	
		// 获取缓冲区中需要发送的数据长度
		UInt32 amtInBuffer = this->GetCurrentOffset() - fBytesSentInBuffer;

		// 多次发送缓冲区中的数据
		if (amtInBuffer > QTSS_MAX_REQUEST_BUFFER_SIZE)
			amtInBuffer = QTSS_MAX_REQUEST_BUFFER_SIZE;

		printf("this->GetCurrentOffset(%d) - fBytesSentInBuffer(%d) = amtInBuffer(%d)\n", this->GetCurrentOffset(), fBytesSentInBuffer, amtInBuffer);

		if (amtInBuffer > 0)
		{
			if (fPrintMsg)
			{
				DateBuffer theDate;
				DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time

 				qtss_printf("\n#S->C:\n#time: ms=%"_U32BITARG_" date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer() );
				StrPtrLen str(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer);
				str.PrintStrEOL();
			}

			//UInt32 theLengthSent = 0;
			//(void)fSocket->GetSocket()->Send(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer, &theLengthSent);
			theErr = fSocket->Send(this->GetBufPtr() + fBytesSentInBuffer, amtInBuffer);
	       
			//// Refresh the timeout if we were able to send any data
			//if (theLengthSent > 0)
			//    fTimeoutTask->RefreshTimeout();

			// 单次发送成功,继续发送
			if (theErr == OS_NoErr)
			{
				fBytesSentInBuffer += amtInBuffer;
				Assert(fBytesSentInBuffer < this->GetCurrentOffset());
			}
			else
				return theErr;
	            
			if(fBytesSentInBuffer < this->GetCurrentOffset())
			{
				continue;
			}
			else
			{
				// We were able to send all the data in the buffer. Great. Flush it.
				this->Reset();
				fBytesSentInBuffer = 0;
				break;
			}
		}
		else
		{
			// We were able to send all the data in the buffer. Great. Flush it.
			this->Reset();
			fBytesSentInBuffer = 0;
			break;
		}
	}
    return theErr;
}
QTSS_Error RTSPRequestStream::ReadRequest()
{
    while (true)
    {
        UInt32 newOffset = 0;
        
        //If this is the case, we already HAVE a request on this session, and we now are done
        //with the request and want to move onto the next one. The first thing we should do
        //is check whether there is any lingering data in the stream. If there is, the parent
        //session believes that is part of a new request
        if (fRequestPtr != NULL)
        {
            fRequestPtr = NULL;//flag that we no longer have a complete request
            
            // Take all the retreated leftover data and move it to the beginning of the buffer
            if ((fRetreatBytes > 0) && (fRequest.Len > 0))
                ::memmove(fRequest.Ptr, fRequest.Ptr + fRequest.Len + fRetreatBytesRead, fRetreatBytes);

            // if we are decoding, we need to also move over the remaining encoded bytes
            // to the right position in the fRequestBuffer
            if (fEncodedBytesRemaining > 0)
            {
                //Assert(fEncodedBytesRemaining < 4);
                
                // The right position is at fRetreatBytes offset in the request buffer. The reason for this is:
                //  1) We need to find a place in the request buffer where we know we have enough space to store
                //  fEncodedBytesRemaining. fRetreatBytes + fEncodedBytesRemaining will always be less than
                //  kRequestBufferSize because all this data must have been in the same request buffer, together, at one point.
                //
                //  2) We need to make sure that there is always more data in the RequestBuffer than in the decoded
                //  request buffer, otherwise we could overrun the decoded request buffer (we bounds check on the encoded
                //  buffer, not the decoded buffer). Leaving fRetreatBytes as empty space in the request buffer ensures
                //  that this principle is maintained. 
                ::memmove(&fRequestBuffer[fRetreatBytes], &fRequestBuffer[fCurOffset - fEncodedBytesRemaining], fEncodedBytesRemaining);
                fCurOffset = fRetreatBytes + fEncodedBytesRemaining;
                Assert(fCurOffset < kRequestBufferSizeInBytes);
            }
            else
                fCurOffset = fRetreatBytes;
                
            newOffset = fRequest.Len = fRetreatBytes;
            fRetreatBytes = fRetreatBytesRead = 0;
        }

        // We don't have any new data, so try and get some
        if (newOffset == 0)
        {
            if (fRetreatBytes > 0)
            {
                // This will be true if we've just snarfed another input stream, in which case the encoded data
                // is copied into our request buffer, and its length is tracked in fRetreatBytes.
                // If this is true, just fall through and decode the data.
                newOffset = fRetreatBytes;
                fRetreatBytes = 0;
                Assert(fEncodedBytesRemaining == 0);
            }
            else
            {
                // We don't have any new data, get some from the socket...
                QTSS_Error sockErr = fSocket->Read(&fRequestBuffer[fCurOffset], 
                                                    (kRequestBufferSizeInBytes - fCurOffset) - 1, &newOffset);
                //assume the client is dead if we get an error back
                if (sockErr == EAGAIN)
                    return QTSS_NoErr;
                if (sockErr != QTSS_NoErr)
                {
                    Assert(!fSocket->IsConnected());
                    return sockErr;
                }
            }   

            if (fDecode)
            {
                // If we need to decode this data, do it now.
                Assert(fCurOffset >= fEncodedBytesRemaining);
                QTSS_Error decodeErr = this->DecodeIncomingData(&fRequestBuffer[fCurOffset - fEncodedBytesRemaining],
                                                                    newOffset + fEncodedBytesRemaining);
                // If the above function returns an error, it is because we've
                // encountered some non-base64 data in the stream. We can process
                // everything up until that point, but all data after this point will
                // be ignored.
                if (decodeErr == QTSS_NoErr)
                    Assert(fEncodedBytesRemaining < 4);
            }
            else
                fRequest.Len += newOffset;
            Assert(fRequest.Len < kRequestBufferSizeInBytes);
            fCurOffset += newOffset;
        }
        Assert(newOffset > 0);

        // See if this is an interleaved data packet
        if ('$' == *(fRequest.Ptr))
        {   
            if (fRequest.Len < 4)
                continue;
            UInt16* dataLenP = (UInt16*)fRequest.Ptr;
            UInt32 interleavedPacketLen = ntohs(dataLenP[1]) + 4;
            if (interleavedPacketLen > fRequest.Len)
                continue;
                
            //put back any data that is not part of the header
            fRetreatBytes += fRequest.Len - interleavedPacketLen;
            fRequest.Len = interleavedPacketLen;
        
            fRequestPtr = &fRequest;
            fIsDataPacket = true;
            return QTSS_RequestArrived;
        }
        fIsDataPacket = false;

        if (fPrintRTSP)
        {
            DateBuffer theDate;
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time
			qtss_printf("\n\n#C->S:\n#time: ms=%lu date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer());

            if (fSocket != NULL)    
            {
                UInt16 serverPort = fSocket->GetLocalPort();
                UInt16 clientPort = fSocket->GetRemotePort();    
                StrPtrLen* theLocalAddrStr = fSocket->GetLocalAddrStr();
                StrPtrLen* theRemoteAddrStr = fSocket->GetRemoteAddrStr();
                if (theLocalAddrStr != NULL)
                {	qtss_printf("#server: ip="); theLocalAddrStr->PrintStr(); qtss_printf(" port=%u\n" , serverPort );
                }
                else
              	{	qtss_printf("#server: ip=NULL port=%u\n" , serverPort );
              	}
               	
                if (theRemoteAddrStr != NULL)
                {	qtss_printf("#client: ip="); theRemoteAddrStr->PrintStr(); qtss_printf(" port=%u\n" , clientPort );
                }
            	else
            	{	qtss_printf("#client: ip=NULL port=%u\n" , clientPort );
            	}

            }

			StrPtrLen str(fRequest);
			str.PrintStrEOL("\n\r\n", "\n");// print the request but stop on \n\r\n and add a \n afterwards.
        }
        
        //use a StringParser object to search for a double EOL, which signifies the end of
        //the header.
        Bool16 weAreDone = false;
        StringParser headerParser(&fRequest);
        
        UInt16 lcount = 0;
        while (headerParser.GetThruEOL(NULL))
        {
            lcount++;
            if (headerParser.ExpectEOL())
            {
                //The legal end-of-header sequences are \r\r, \r\n\r\n, & \n\n. NOT \r\n\r!
                //If the packets arrive just a certain way, we could get here with the latter
                //combo, and not wait for a final \n.
                if ((headerParser.GetDataParsedLen() > 2) &&
                    (memcmp(headerParser.GetCurrentPosition() - 3, "\r\n\r", 3) == 0))
                    continue;
                weAreDone = true;
                break;
            }
            else if (lcount == 1) {
                // if this request is actually a ShoutCast password it will be 
                // in the form of "xxxxxx\r" where "xxxxx" is the password.
                // If we get a 1st request line ending in \r with no blanks we will
                // assume that this is the end of the request.
                UInt16 flag = 0;
                UInt16 i = 0;
                for (i=0; i<fRequest.Len; i++)
                {
                    if (fRequest.Ptr[i] == ' ')
                        flag++;
                }
                if (flag == 0)
                {
                    weAreDone = true;
                    break;
                }
            }
        }
        
        //weAreDone means we have gotten a full request
        if (weAreDone)
        {
            //put back any data that is not part of the header
            fRequest.Len -= headerParser.GetDataRemaining();
            fRetreatBytes += headerParser.GetDataRemaining();
            
            fRequestPtr = &fRequest;
            return QTSS_RequestArrived;
        }
        
        //check for a full buffer
        if (fCurOffset == kRequestBufferSizeInBytes - 1)
        {
            fRequestPtr = &fRequest;
            return E2BIG;
        }
    }
}
示例#9
0
QTSS_Error	QTSSModuleUtils::SendHTTPErrorResponse( QTSS_RTSPRequestObject inRequest,
													QTSS_SessionStatusCode inStatusCode,
                                                    Bool16 inKillSession,
                                                    char *errorMessage)
{
    static Bool16 sFalse = false;
    
    //set status code for access log
    (void)QTSS_SetValue(inRequest, qtssRTSPReqStatusCode, 0, &inStatusCode, sizeof(inStatusCode));

    if (inKillSession) // tell the server to end the session
        (void)QTSS_SetValue(inRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse));
    
    ResizeableStringFormatter theErrorMessage(NULL, 0); //allocates and deletes memory
    ResizeableStringFormatter bodyMessage(NULL,0); //allocates and deletes memory

    char messageLineBuffer[64]; // used for each line
    static const int maxMessageBufferChars = sizeof(messageLineBuffer) -1;
    messageLineBuffer[maxMessageBufferChars] = 0; // guarantee termination

    // ToDo: put in a more meaningful http error message for each error. Not required by spec.
    // ToDo: maybe use the HTTP protcol class static error strings.
    char* errorMsg = "error"; 

    DateBuffer theDate;
    DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time

    UInt32 realCode = 0;
    UInt32 len = sizeof(realCode);
    (void) QTSS_GetValue(inRequest, qtssRTSPReqRealStatusCode, 0,  (void*)&realCode,&len);

    char serverHeaderBuffer[64]; // the qtss Server: header field
    len = sizeof(serverHeaderBuffer) -1; // leave room for terminator
    (void) QTSS_GetValue(sServer, qtssSvrRTSPServerHeader, 0,  (void*)serverHeaderBuffer,&len);
    serverHeaderBuffer[len] = 0; // terminate.
 
    qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "HTTP/1.1 %"_U32BITARG_" %s",realCode, errorMsg);
    theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));
    theErrorMessage.PutEOL();

    theErrorMessage.Put(serverHeaderBuffer,::strlen(serverHeaderBuffer));
    theErrorMessage.PutEOL();
 
    qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "Date: %s",theDate.GetDateBuffer());
    theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));
    theErrorMessage.PutEOL();
 
    Bool16 addBody =  (errorMessage != NULL && ::strlen(errorMessage) != 0); // body error message so add body headers
    if (addBody) // body error message so add body headers
    {
        // first create the html body
        static const StrPtrLen htmlBodyStart("<html><body>\n");
        bodyMessage.Put(htmlBodyStart.Ptr,htmlBodyStart.Len);
 
        //<h1>errorMessage</h1>\n
        static const StrPtrLen hStart("<h1>");
        bodyMessage.Put(hStart.Ptr,hStart.Len);

        bodyMessage.Put(errorMessage,::strlen(errorMessage));

        static const StrPtrLen hTerm("</h1>\n");
        bodyMessage.Put(hTerm.Ptr,hTerm.Len);
 
        static const StrPtrLen htmlBodyTerm("</body></html>\n");
        bodyMessage.Put(htmlBodyTerm.Ptr,htmlBodyTerm.Len);

        // write body headers
        static const StrPtrLen bodyHeaderType("Content-Type: text/html");
        theErrorMessage.Put(bodyHeaderType.Ptr,bodyHeaderType.Len);
        theErrorMessage.PutEOL();

        qtss_snprintf(messageLineBuffer,maxMessageBufferChars, "Content-Length: %"_U32BITARG_"", bodyMessage.GetBytesWritten());
        theErrorMessage.Put(messageLineBuffer,::strlen(messageLineBuffer));        
        theErrorMessage.PutEOL();
    }

    static const StrPtrLen headerClose("Connection: close");
    theErrorMessage.Put(headerClose.Ptr,headerClose.Len);
    theErrorMessage.PutEOL();

    theErrorMessage.PutEOL();  // terminate headers with empty line

    if (addBody) // add html body
    {
        theErrorMessage.Put(bodyMessage.GetBufPtr(),bodyMessage.GetBytesWritten());
    }

    //
    // Now that we've formatted the message into the temporary buffer,
    // write it out to the request stream and the Client Session object
    (void)QTSS_Write(inRequest, theErrorMessage.GetBufPtr(), theErrorMessage.GetBytesWritten(), NULL, 0);
    (void)QTSS_SetValue(inRequest, qtssRTSPReqRespMsg, 0, theErrorMessage.GetBufPtr(), theErrorMessage.GetBytesWritten());
    
    return QTSS_RequestFailed;
}
/* 使用writev(),若RTSP Response流的缓冲区中有待发数据,首先将其发送出去,否则将其他缓冲区的数据发送出,
并刷新超时任务,最后比较发送的总长度outLengthSent与要发送数据总长度inTotalLength的差值,将该段剩余数据
以及随后的iovec放入缓冲区待发送,依据第5个参数决定是否缓存(利用StringFormatter::Put())没有发送出的iovec data?
*/
QTSS_Error RTSPResponseStream::WriteV(iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength,
                                            UInt32* outLengthSent, UInt32 inSendType)
{
    QTSS_Error theErr = QTSS_NoErr;
	/* 用TCPSocket已经送出数据的长度,注意这个量十分重要 */
    UInt32 theLengthSent = 0;
	/* 缓存中剩余data的字节数 */
    UInt32 amtInBuffer = this->GetCurrentOffset() - fBytesSentInBuffer;
    
	/* 假如buffer中还有剩余数据,就把它用Socket写入RTSP Response流中 */
    if (amtInBuffer > 0)
    {

        // There is some data in the output buffer. Make sure to send that
        // first, using the empty space in the ioVec.
         
		/* 确定buffer中剩余数据的起点和长度,配置为inVec的第一个分量 */
        inVec[0].iov_base = this->GetBufPtr() + fBytesSentInBuffer;
        inVec[0].iov_len = amtInBuffer;

		/* 用Socket::Writev()写入数据,送出的数据长度是theLengthSent */
        theErr = fSocket->WriteV(inVec, inNumVectors, &theLengthSent);
        
		/* 假如打印RTSP信息,就输出RTSP Response的指定格式的信息 */
		if (fPrintRTSP)
		{
			/* 类似RTSPRequestStream::ReadRequest() */
			/* 得到当前的GTM时间,格式为"Mon, 04 Nov 1996 21:42:17 GMT",并打印这些信息 */
            DateBuffer theDate;			
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time
 			qtss_printf("\n#S->C:\n#time: ms=%lu date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer() );
 			
			/* 对每个向量,逐行打印其被'\n'或'\r'分割的内容(多个C-String)和'\n'或'\r' */
			for (UInt32 i =0; i < inNumVectors; i++)
			{  
				StrPtrLen str((char*)inVec[i].iov_base, (UInt32) inVec[i].iov_len);
				str.PrintStrEOL();
  			}
 		}

		/* 假如TCPSocket送出的数据超过了剩余要送的数据,将当前指针fCurrentPut移动开头,更新相应量 */
        if (theLengthSent >= amtInBuffer)
        {
            // We were able to send all the data in the buffer. Great(好极了). Flush it.
			/* 根据入参0重置fCurrentPut的位置为fStartPut,即,将当前指针移动开头 */
            this->Reset();
			/* 更新,此时buffer中没有数据要送 */
            fBytesSentInBuffer = 0;
            
            // Make theLengthSent reflect the amount of data sent in the ioVec
			/* 及时更新theLengthSent */
            theLengthSent -= amtInBuffer;
        }
        else /* 还有数据没有送完 */
        {
            // Uh oh. Not all the data in the buffer was sent. Update the
            // fBytesSentInBuffer count, and set theLengthSent to 0.
            
			/* 累计buffer中TCPSocket送出数据的总字节数 */
            fBytesSentInBuffer += theLengthSent;
            Assert(fBytesSentInBuffer < this->GetCurrentOffset());
			/* 以便下次用fSocket->WriteV() */
            theLengthSent = 0;
        }
        // theLengthSent now represents how much data in the ioVec was sent
    }/* 假如当前buffer中没有数据,就从第二个向量开始发送其它向量中的数据,其实际发送数据的长度是theLengthSent */
    else if (inNumVectors > 1)
    {
        theErr = fSocket->WriteV(&inVec[1], inNumVectors - 1, &theLengthSent);
    }

    // We are supposed to refresh the timeout if there is a successful write.
    if (theErr == QTSS_NoErr)
        fTimeoutTask->RefreshTimeout();
        
    // If there was an error, don't alter anything, just bail
	/* 假如Socket::WriteV()结果不是送完或者还要送,就返回实际错误 */
    if ((theErr != QTSS_NoErr) && (theErr != EAGAIN))
        return theErr;
    
    // theLengthSent at this point is the amount of data passed into
    // this function that was sent.
	/* 记录使用fSocket->WriteV()时输出数据的总长度,后面会对这个值更新 */
    if (outLengthSent != NULL)
        *outLengthSent = theLengthSent;

    // Update the StringFormatter fBytesWritten variable... this data
    // wasn't buffered in the output buffer at any time, so if we
    // don't do this, this amount would get lost
	// A way of keeping count of how many bytes have been written total,see StringFormatter.h
	/* 计算共有多少字节被写入,将统计信息加入fBytesWritten,以防丢失 */
    fBytesWritten += theLengthSent;
    
    // All of the data was sent... whew!
	/* 假如所有的数据被发送出,正确返回 */
    if (theLengthSent == inTotalLength)
        return QTSS_NoErr;
    
	/* 下面根据第5个参数决定是否缓存剩余没有发送出的iovec data,假如使用缓存
	(利用StringFormatter::Put()),则这些数据将在下次WriteV时首先发送给client */
    // We need to determine now whether to copy the remaining unsent
    // iovec data into the buffer. This is determined based on
    // the inSendType parameter passed in.

	/* case 1:当发送类型是kDontBuffer,不缓存remaining unsent iovec data */
    if (inSendType == kDontBuffer)
        return theErr;

	/* case 2:当发送类型是kAllOrNothing,且还有数据待发送时,返回EAGAIN */
	/* If no data could be sent, return EWOULDBLOCK. Otherwise,buffer any unsent data. */
    if ((inSendType == kAllOrNothing) && (theLengthSent == 0))
        return EAGAIN;
     
    /* case 3:当发送类型是kAlwaysBuffer,先确定未发送数据长度,再缓存remaining unsent iovec data */

    // Some or none of the iovec data was sent. Copy the remainder into the output
    // buffer.
	/* 注意这是下面一段的思路 */
    
    // The caller should consider this data sent.
	/* 一定要使所有的inVec[]中的数据(长度为inTotalLength)全部发送出 */
    if (outLengthSent != NULL)
        *outLengthSent = inTotalLength;
     
	/* 跳过那些已经送出的数据,更新还要送出数据的量theLengthSent,它已不足某个索引curVec的iov的长度 */
	/* 注意这里的取值是1,没从0开始,因为它已经读了 */
    UInt32 curVec = 1;
    while (theLengthSent >= inVec[curVec].iov_len)
    {
        // Skip over the vectors that were in fact sent.
        Assert(curVec < inNumVectors);
        theLengthSent -= inVec[curVec].iov_len;
        curVec++;
    }
    
	/* 将剩下的不够一个inVec[curVec].iov_len长度的数据(实际大小为inVec[curVec].iov_len - theLengthSent)放入指定缓存,并更新相关量 */
    while (curVec < inNumVectors)
    {
        // Copy the remaining vectors into the buffer
        this->Put(  ((char*)inVec[curVec].iov_base) + theLengthSent,
                    inVec[curVec].iov_len - theLengthSent);
        theLengthSent = 0;//以后的iovec都放入整个长度
        curVec++;       
    }
    return QTSS_NoErr;
}
/* 从RTSP Request stream中获取full RTSP Request Header,打印fRequest相关信息,解析得到它的尾部,并配置相应数据成员的值 */
QTSS_Error RTSPRequestStream::ReadRequest()
{
    while (true)
    {
		/* 注意这个量非常重要 */
        UInt32 newOffset = 0;
        
        //If this is the case, we already HAVE a request on this session, and we now are done
        //with the request and want to move onto the next one. The first thing we should do
        //is check whether there is any lingering(延迟的) data in the stream. If there is, the parent
        //session believes that is part of a new request
        if (fRequestPtr != NULL)
        {
			/* 标记不再有complete RTSP client Request  */
            fRequestPtr = NULL;//flag that we no longer have a complete request
            
            // Take all the retreated leftover(剩余的) data and move it to the beginning of the buffer
            if ((fRetreatBytes > 0) && (fRequest.Len > 0))
                ::memmove(fRequest.Ptr, fRequest.Ptr + fRequest.Len + fRetreatBytesRead/* NOTE! */, fRetreatBytes);

            // if we are decoding, we need to also move over the remaining encoded bytes
            // to the right position in the fRequestBuffer
            if (fEncodedBytesRemaining > 0)
            {
				/* 参见RTSPRequestStream::DecodeIncomingData() */
                //Assert(fEncodedBytesRemaining < 4);
                
                // The right position is at fRetreatBytes offset in the request buffer. The reason for this is:
                //  1) We need to find a place in the request buffer where we know we have enough space to store
                //  fEncodedBytesRemaining. fRetreatBytes + fEncodedBytesRemaining will always be less than
                //  kRequestBufferSize because all this data must have been in the same request buffer, together, at one point.
                //
                //  2) We need to make sure that there is always more data in the RequestBuffer than in the decoded
                //  request buffer, otherwise we could overrun(超出限度) the decoded request buffer (we bounds check on the encoded
                //  buffer, not the decoded buffer). Leaving fRetreatBytes as empty space in the request buffer ensures
                //  that this principle is maintained. 
                ::memmove(&fRequestBuffer[fRetreatBytes], &fRequestBuffer[fCurOffset - fEncodedBytesRemaining], fEncodedBytesRemaining);
                fCurOffset = fRetreatBytes + fEncodedBytesRemaining;
                Assert(fCurOffset < kRequestBufferSizeInBytes);
            }
            else
                fCurOffset = fRetreatBytes;
                
            newOffset = fRequest.Len = fRetreatBytes;
			/* 因为已将Retreat data移位了 */
            fRetreatBytes = fRetreatBytesRead = 0;
        }

        // We don't have any new data, so try and get some
		/* 以下操作是确保newOffset>0 */
        if (newOffset == 0)
        {
            if (fRetreatBytes > 0)
            {
                // This will be true if we've just snarfed(复制) another input stream, in which case the encoded data
                // is copied into our request buffer, and its length is tracked(追踪) in fRetreatBytes.
                // If this is true, just fall through(进行下去) and decode the data.
                newOffset = fRetreatBytes;
                fRetreatBytes = 0;
                Assert(fEncodedBytesRemaining == 0);
            }
            else
            {
                // We don't have any new data, get some from the socket...
				/* 利用TCPSocket的::recv()来接收数据,第一,二个参数是缓存地址和长度,第三个参数是接收数据的长度 */
                QTSS_Error sockErr = fSocket->Read(&fRequestBuffer[fCurOffset], 
                                                    (kRequestBufferSizeInBytes - fCurOffset) - 1, &newOffset);
                //assume the client is dead if we get an error back
				/* 目前缓冲区无数据可读 */
				/* 当recv系统调用返回这个值时表示recv读数据时,对方没有发送数据过来。 */
                if (sockErr == EAGAIN)
                    return QTSS_NoErr;
				/* 假如返回出错,一定是连接断开 */
                if (sockErr != QTSS_NoErr)
                {
                    Assert(!fSocket->IsConnected());
                    return sockErr;
                }
            }   

			/* 当要base64 decode时 */
            if (fDecode)
            {
                // If we need to decode this data, do it now.
				/* 确保数据偏移量大于内存中需要decode的数据 */
                Assert(fCurOffset >= fEncodedBytesRemaining);
				/* 解密读进来的数据 */
                QTSS_Error decodeErr = this->DecodeIncomingData(&fRequestBuffer[fCurOffset - fEncodedBytesRemaining],
                                                                    newOffset + fEncodedBytesRemaining);
                // If the above function returns an error, it is because we've
                // encountered some non-base64 data in the stream. We can process
                // everything up until that point, but all data after this point will
                // be ignored.
				/* 解码成功时,确保最后剩下的未解码的数据少于4个字节,参见下面的RTSPRequestStream::DecodeIncomingData() */
                if (decodeErr == QTSS_NoErr)
                    Assert(fEncodedBytesRemaining < 4);
            }
            else
                fRequest.Len += newOffset;

            Assert(fRequest.Len < kRequestBufferSizeInBytes);
            fCurOffset += newOffset;
        }
		/* 最后一定要达到这个结论! */
        Assert(newOffset > 0);

        // See if this is an interleaved data packet
		/* 查找data packet,配置fIsDataPacket的值 */
		/* 找到data packet */
        if ('$' == *(fRequest.Ptr))
        {   
            if (fRequest.Len < 4)
                continue;
            UInt16* dataLenP = (UInt16*)fRequest.Ptr;
			/* 获取混叠包长度 */
            UInt32 interleavedPacketLen = ntohs(dataLenP[1]) + 4;
            if (interleavedPacketLen > fRequest.Len)
                continue;
                
            //put back any data that is not part of the header
			/* 将不是header部分的数据放回失控数据处 */
            fRetreatBytes += fRequest.Len - interleavedPacketLen;
            fRequest.Len = interleavedPacketLen;
        
            fRequestPtr = &fRequest;
            fIsDataPacket = true;
            return QTSS_RequestArrived;
        }
        fIsDataPacket = false;

		/* 当打印RTSP info时,打印出如下信息:
		
		   (空两行)
		   #C->S;
		   #time: ms=***  data=Mon,29 July 2009 15:17:17 GTM
		   #server: ip=172.16.32.37 port=***
	     或#server: ip=NULL port=***
		   #client: ip=172.16.39.30 port=***
	     或#client: ip=NULL port=***
		   *********fRequest info***************
		*/
        if (fPrintRTSP)
        {
			/* 类似RTSPResponseStream::WriteV() */
			/* 得到当前的GTM时间,格式为"Mon, 04 Nov 1996 21:42:17 GMT" */
            DateBuffer theDate;
            DateTranslator::UpdateDateBuffer(&theDate, 0); // get the current GMT date and time
			/* OS::StartTimeMilli_Int()表示服务器运行多长时间? */
			qtss_printf("\n\n#C->S:\n#time: ms=%lu date=%s\n", (UInt32) OS::StartTimeMilli_Int(), theDate.GetDateBuffer());

			/* 假如有TCPSocket存在,就获取并打印其相关信息 */
            if (fSocket != NULL)    
            {
                UInt16 serverPort = fSocket->GetLocalPort();
                UInt16 clientPort = fSocket->GetRemotePort();    
                StrPtrLen* theLocalAddrStr = fSocket->GetLocalAddrStr();
                StrPtrLen* theRemoteAddrStr = fSocket->GetRemoteAddrStr();
                if (theLocalAddrStr != NULL)
                {	qtss_printf("#server: ip="); theLocalAddrStr->PrintStr(); qtss_printf(" port=%u\n" , serverPort );
                }
                else
              	{	qtss_printf("#server: ip=NULL port=%u\n" , serverPort );
              	}
               	
                if (theRemoteAddrStr != NULL)
                {	qtss_printf("#client: ip="); theRemoteAddrStr->PrintStr(); qtss_printf(" port=%u\n" , clientPort );
                }
            	else
            	{	qtss_printf("#client: ip=NULL port=%u\n" , clientPort );
            	}

            }

			/* 打印fRequest字符串 */
			StrPtrLen str(fRequest);
			str.PrintStrEOL("\n\r\n", "\n");// print the request but stop on \n\r\n and add a \n afterwards.
        }
        
        //use a StringParser object to search for a double EOL, which signifies the end of
        //the header.
		/* 下面要查找client发出的RTSP Request Header的末尾处 */

		/* 找到fRequest末端了吗? */
        Bool16 weAreDone = false;
        StringParser headerParser(&fRequest);
        
        UInt16 lcount = 0;
		/* 当遇到eol时,fStartGet指针越过它 */
        while (headerParser.GetThruEOL(NULL))
        {
            lcount++;
			/* 当当前的fStartGet指针指向EOL时 */
            if (headerParser.ExpectEOL())
            {
                //The legal end-of-header sequences are \r\r, \r\n\r\n, & \n\n. NOT \r\n\r!
                //If the packets arrive just a certain way, we could get here with the latter
                //combo(组合,即\r\n\r), and not wait for a final \n.
				/* 假如查找到"\r\n\r",就继续查找,直至找到符合条件的末端 */
                if ((headerParser.GetDataParsedLen() > 2) &&
                    (memcmp(headerParser.GetCurrentPosition() - 3, "\r\n\r", 3) == 0))
                    continue;
				/* 标记找到了 */
                weAreDone = true;
                break;
            }
			/* 假如是"xxxxxx\r" */
            else if (lcount == 1) {
                // if this request is actually a ShoutCast password it will be 
                // in the form of "xxxxxx\r" where "xxxxx" is the password.
                // If we get a 1st request line ending in \r with no blanks we will
                // assume that this is the end of the request.
                UInt16 flag = 0;
                UInt16 i = 0;
				/* 检查"xxxxxx\r"中有无空格?没有就说明我们找到了 */
                for (i=0; i<fRequest.Len; i++)
                {
                    if (fRequest.Ptr[i] == ' ')
                        flag++;
                }
                if (flag == 0)
                {
                    weAreDone = true;
                    break;
                }
            }
        }
        
        //weAreDone means we have gotten a full request
		/* 我们找到了一个Full RTSP Request Header? */
        if (weAreDone)
        {
            //put back any data that is not part of the header
            fRequest.Len -= headerParser.GetDataRemaining();
            fRetreatBytes += headerParser.GetDataRemaining();
            
            fRequestPtr = &fRequest;
            return QTSS_RequestArrived;
        }
        
        //check for a full buffer
		/* 当到达Request buffer末端时,给出提示信息E2BIG */
        if (fCurOffset == kRequestBufferSizeInBytes - 1)
        {
            fRequestPtr = &fRequest;
            return E2BIG;
        }
    }
}