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); }
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; } } }
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; } } }