// This sends the HTTP response to the server that contains the RTSPtext Ref movie QTSS_Error SendTheResponse(QTSS_RTSPSessionObject theSession, QTSS_StreamRef stream, StrPtrLen& movie) { QTSS_Error err = QTSS_NoErr; char theMovieFile[512]; theMovieFile[sizeof(theMovieFile) -1] = 0; char tmp[600]; tmp[sizeof(tmp) -1] = 0; char tmp2[80]; tmp2[sizeof(tmp2) -1] = 0; UInt8 x1, x2, x3, x4; // send the HTTP reply header to the client err= QTSS_Write(stream, sResponseHeader, ::strlen(sResponseHeader), NULL, qtssWriteFlagsBufferData); if (err != QTSS_NoErr) return QTSS_NoErr; UInt32 ip4address = 0; UInt32 len = sizeof(ip4address); err = QTSS_GetValue(theSession, qtssRTSPSesLocalAddr, 0, &ip4address, &len); // Format the server IP address for building the RTSP address in the reply. x1 = (UInt8)((ip4address >> 24) & 0xff); x2 = (UInt8)((ip4address >> 16) & 0xff); x3 = (UInt8)((ip4address >> 8) & 0xff); x4 = (UInt8)((ip4address) & 0xff); if (movie.Len > sizeof(theMovieFile) -1 ) movie.Len = sizeof(theMovieFile) -1; ::memcpy(theMovieFile, movie.Ptr, movie.Len); theMovieFile[movie.Len] = '\0'; UInt16 port = sRTSPReplyPort; if (0 == port) { len = sizeof(port); err = QTSS_GetValue(theSession, qtssRTSPSesLocalPort, 0, &port, &len); } // construct the RTSP address reply string for the client. qtss_snprintf(tmp,sizeof(tmp) -1, "rtsptext\r\nrtsp://%d.%d.%d.%d:%d%s\r\n", x1,x2,x3,x4, port, theMovieFile); // send the 'Content-Length:' part of the HTTP reply qtss_snprintf(tmp2, sizeof(tmp2) -1, "Content-Length: %d\r\n\r\n", (int) ::strlen(tmp)); err = QTSS_Write(stream, tmp2, ::strlen(tmp2), NULL, qtssWriteFlagsBufferData); if (err != QTSS_NoErr) return QTSS_NoErr; // send the formatted RTSP reference part of the reply err = QTSS_Write(stream, tmp, ::strlen(tmp), NULL, qtssWriteFlagsBufferData); if (err != QTSS_NoErr) return QTSS_NoErr; // flush the pending write to the client. err = QTSS_Flush(stream); return err; }
QTSS_Error QTSSModuleUtils::SendErrorResponseWithMessage( QTSS_RTSPRequestObject inRequest, QTSS_RTSPStatusCode inStatusCode, StrPtrLen* inErrorMessagePtr) { static Bool16 sFalse = false; //set RTSP headers necessary for this error response message (void)QTSS_SetValue(inRequest, qtssRTSPReqStatusCode, 0, &inStatusCode, sizeof(inStatusCode)); (void)QTSS_SetValue(inRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse)); StrPtrLen theErrorMessage(NULL, 0); if (sEnableRTSPErrorMsg) { Assert(inErrorMessagePtr != NULL); //Assert(inErrorMessagePtr->Ptr != NULL); //Assert(inErrorMessagePtr->Len != 0); theErrorMessage.Set(inErrorMessagePtr->Ptr, inErrorMessagePtr->Len); char buff[32]; qtss_sprintf(buff,"%"_U32BITARG_"",inErrorMessagePtr->Len); (void)QTSS_AppendRTSPHeader(inRequest, qtssContentLengthHeader, buff, ::strlen(buff)); } //send the response header. In all situations where errors could happen, we //don't really care, cause there's nothing we can do anyway! (void)QTSS_SendRTSPHeaders(inRequest); // // 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.Ptr, theErrorMessage.Len, NULL, 0); (void)QTSS_SetValue(inRequest, qtssRTSPReqRespMsg, 0, theErrorMessage.Ptr, theErrorMessage.Len); return QTSS_RequestFailed; }
void QTSSModuleUtils::SendDescribeResponse(QTSS_RTSPRequestObject inRequest, QTSS_ClientSessionObject inSession, iovec* describeData, UInt32 inNumVectors, UInt32 inTotalLength) { //write content size header char buf[32]; qtss_sprintf(buf, "%"_S32BITARG_"", inTotalLength); (void)QTSS_AppendRTSPHeader(inRequest, qtssContentLengthHeader, &buf[0], ::strlen(&buf[0])); (void)QTSS_SendStandardRTSPResponse(inRequest, inSession, 0); // On solaris, the maximum # of vectors is very low (= 16) so to ensure that we are still able to // send the SDP if we have a number greater than the maximum allowed, we coalesce the vectors into // a single big buffer #ifdef __solaris__ if (inNumVectors > IOV_MAX ) { char* describeDataBuffer = QTSSModuleUtils::CoalesceVectors(describeData, inNumVectors, inTotalLength); (void)QTSS_Write(inRequest, (void *)describeDataBuffer, inTotalLength, NULL, qtssWriteFlagsNoFlags); // deleting memory allocated by the CoalesceVectors call delete [] describeDataBuffer; } else (void)QTSS_WriteV(inRequest, describeData, inNumVectors, inTotalLength, NULL); #else (void)QTSS_WriteV(inRequest, describeData, inNumVectors, inTotalLength, NULL); #endif }
SInt64 ProxyTask::Run() { const UInt32 kMaxRTCPPacketSize = 2048; char thePacketBuffer[kMaxRTCPPacketSize]; QTSS_PacketStruct thePacketStruct; thePacketStruct.packetTransmitTime = QTSS_Milliseconds(); thePacketStruct.packetData = thePacketBuffer; (void)this->GetEvents(); OSMutexLocker locker(sSocketPool->GetMutex()); for (OSQueueIter iter(sSocketPool->GetSocketQueue()); !iter.IsDone(); iter.Next()) { UInt32 theRemoteAddr = 0; UInt16 theRemotePort = 0; UDPSocketPair* thePair = (UDPSocketPair*)iter.GetCurrent()->GetEnclosingObject(); Assert(thePair != NULL); for (UInt32 x = 0; x < 2; x++) { QTSS_WriteFlags theFlags = qtssWriteFlagsNoFlags; UDPSocket* theSocket = NULL; if (x == 0) { theFlags = qtssWriteFlagsIsRTP; theSocket = thePair->GetSocketA(); } else { theFlags = qtssWriteFlagsIsRTCP; theSocket = thePair->GetSocketB(); } Assert(theSocket->GetDemuxer() != NULL); OSMutexLocker locker(theSocket->GetDemuxer()->GetMutex()); //get all the outstanding packets for this socket while (true) { UInt32 thePacketLen = 0; theSocket->RecvFrom(&theRemoteAddr, &theRemotePort, thePacketStruct.packetData, kMaxRTCPPacketSize, &thePacketLen); if (thePacketLen == 0) break;//no more packets on this socket! ProxyDemuxerTask* theDemuxerTask = (ProxyDemuxerTask*)theSocket->GetDemuxer()->GetTask(theRemoteAddr, 0); if (theDemuxerTask != NULL) { QTSS_RTPStreamObject theStream = theDemuxerTask->GetStream(); (void)QTSS_Write(theStream, &thePacketStruct, thePacketLen, NULL, theFlags); } } } } return kProxyTaskPollIntervalMsec; }
inline void SendHeader(QTSS_StreamRef inStream) { (void)QTSS_Write(inStream, sResponseHeader, ::strlen(sResponseHeader), NULL, 0); (void)QTSS_Write(inStream, sEOL, ::strlen(sEOL), NULL, 0); (void)QTSS_Write(inStream, sVersionHeader, ::strlen(sVersionHeader), NULL, 0); (void)QTSS_Write(inStream, sEOL, ::strlen(sEOL), NULL, 0); (void)QTSS_Write(inStream, sConnectionHeader, ::strlen(sConnectionHeader), NULL, 0); (void)QTSS_Write(inStream, sEOL, ::strlen(sEOL), NULL, 0); (void)QTSS_Write(inStream, sContentType, ::strlen(sContentType), NULL, 0); (void)QTSS_Write(inStream, sEOM, ::strlen(sEOM), NULL, 0); }
void QTSSModuleUtils::LogPrefErrorStr( QTSS_ErrorVerbosity inVerbosity, char* preference, char* inMessage) { if (inMessage == NULL || preference == NULL) { Assert(0); return; } char buffer[1024]; qtss_snprintf(buffer,sizeof(buffer), "Server preference %s %s", preference, inMessage); (void)QTSS_Write(sErrorLog, buffer, ::strlen(buffer), NULL, inVerbosity); }
void QTSSModuleUtils::LogError( QTSS_ErrorVerbosity inVerbosity, QTSS_AttributeID inTextMessage, UInt32 /*inErrNumber*/, char* inArgument, char* inArg2) { static char* sEmptyArg = ""; if (sMessages == NULL) return; // Retrieve the specified text message from the text messages dictionary. StrPtrLen theMessage; (void)QTSS_GetValuePtr(sMessages, inTextMessage, 0, (void**)(void*)&theMessage.Ptr, &theMessage.Len); if ((theMessage.Ptr == NULL) || (theMessage.Len == 0)) (void)QTSS_GetValuePtr(sMessages, qtssMsgNoMessage, 0, (void**)(void*)&theMessage.Ptr, &theMessage.Len); if ((theMessage.Ptr == NULL) || (theMessage.Len == 0)) return; // qtss_sprintf and ::strlen will crash if inArgument is NULL if (inArgument == NULL) inArgument = sEmptyArg; if (inArg2 == NULL) inArg2 = sEmptyArg; // Create a new string, and put the argument into the new string. UInt32 theMessageLen = theMessage.Len + ::strlen(inArgument) + ::strlen(inArg2); OSCharArrayDeleter theLogString(NEW char[theMessageLen + 1]); qtss_sprintf(theLogString.GetObject(), theMessage.Ptr, inArgument, inArg2); Assert(theMessageLen >= ::strlen(theLogString.GetObject())); (void)QTSS_Write(sErrorLog, theLogString.GetObject(), ::strlen(theLogString.GetObject()), NULL, inVerbosity); }
void ReportErr(QTSS_Filter_Params* inParams, UInt32 err) { StrPtrLen* urlPtr = sQueryPtr->GetURL(); StrPtrLen* evalMessagePtr = sQueryPtr->GetEvalMsg(); char temp[32]; if (urlPtr && evalMessagePtr) { qtss_sprintf(temp,"(%"_U32BITARG_")",err); (void)QTSS_Write(inParams->inRTSPRequest, "error:", strlen("error:"), NULL, 0); (void)QTSS_Write(inParams->inRTSPRequest, temp, strlen(temp), NULL, 0); if (sQueryPtr->VerboseParam()) { (void)QTSS_Write(inParams->inRTSPRequest, ";URL=", strlen(";URL="), NULL, 0); if (urlPtr) (void)QTSS_Write(inParams->inRTSPRequest, urlPtr->Ptr, urlPtr->Len, NULL, 0); } if (sQueryPtr->DebugParam()) { (void)QTSS_Write(inParams->inRTSPRequest, ";", strlen(";"), NULL, 0); (void)QTSS_Write(inParams->inRTSPRequest, evalMessagePtr->Ptr, evalMessagePtr->Len, NULL, 0); } (void)QTSS_Write(inParams->inRTSPRequest, "\r\n\r\n", 4, NULL, 0); } }
QTSS_Error SendPackets(QTSS_RTPSendPackets_Params* inParams) { FileSession** theFile = NULL; UInt32 theLen = 0; QTSS_Error theErr = QTSS_GetValuePtr(inParams->inClientSession, sFileSessionAttr, 0, (void**)&theFile, &theLen); if ((theErr != QTSS_NoErr) || (theLen != sizeof(FileSession*))) { Assert( 0 ); return QTSS_RequestFailed; } while (true) { if ((*theFile)->fPacketStruct.packetData == NULL) { void* theCookie = NULL; Float64 theTransmitTime = (*theFile)->fFile.GetNextPacket((UInt8**)&(*theFile)->fPacketStruct.packetData, &(*theFile)->fNextPacketLen, &theCookie); // // Check to see if we should stop playing based on a client specified stop time if (((*theFile)->fStopTime != -1) && (theTransmitTime > (*theFile)->fStopTime)) { // We should indeed stop playing (void)QTSS_Pause(inParams->inClientSession); inParams->outNextPacketTime = qtssDontCallSendPacketsAgain; return QTSS_NoErr; } // // Adjust transmit time based on speed Float64 theOffsetFromStartTime = theTransmitTime - (*theFile)->fStartTime; theTransmitTime = (*theFile)->fStartTime + (theOffsetFromStartTime / (*theFile)->fSpeed); (*theFile)->fStream = (QTSS_RTPStreamObject)theCookie; (*theFile)->fPacketStruct.packetTransmitTime = (*theFile)->fAdjustedPlayTime + ((SInt64)(theTransmitTime * 1000)); #if RTP_FILE_MODULE_DEBUGGING >= 8 UInt16* theSeqNumPtr = (UInt16*)(*theFile)->fNextPacket; UInt32* theTimestampP = (UInt32*)(*theFile)->fNextPacket; UInt32* theTrackID = NULL; (void)QTSS_GetValuePtr((*theFile)->fStream, qtssRTPStrTrackID, 0, (void**)&theTrackID, &theLen); qtss_printf("Got packet. Seq num: %d. Timestamp: %d. TrackID: %d. Transmittime: %f\n",theSeqNumPtr[1], theTimestampP[1], *theTrackID, theTransmitTime); #endif } //We are done playing all streams! if ((*theFile)->fPacketStruct.packetData == NULL) { #if RTP_FILE_MODULE_DEBUGGING >= 8 qtss_printf("done w all packets\n"); #endif inParams->outNextPacketTime = qtssDontCallSendPacketsAgain; return QTSS_NoErr; } //we have a packet that needs to be sent now Assert((*theFile)->fStream != NULL); // Send the packet! theErr = QTSS_Write((*theFile)->fStream, &(*theFile)->fPacketStruct, (*theFile)->fNextPacketLen, NULL, qtssWriteFlagsIsRTP); if ( theErr == QTSS_WouldBlock ) { if ((*theFile)->fPacketStruct.packetTransmitTime == -1) inParams->outNextPacketTime = sFlowControlProbeInterval; // for buffering, try me again in # MSec else { Assert((*theFile)->fPacketStruct.packetTransmitTime > inParams->inCurrentTime); inParams->outNextPacketTime = (*theFile)->fPacketStruct.packetTransmitTime - inParams->inCurrentTime; } return QTSS_NoErr; } (*theFile)->fPacketStruct.packetData = NULL; } Assert(0); return QTSS_NoErr; }
QTSS_Error RTPSessionOutput::WritePacket(StrPtrLen* inPacket, void* inStreamCookie, UInt32 inFlags, SInt64 packetLatenessInMSec, SInt64* timeToSendThisPacketAgain, UInt64* packetIDPtr, SInt64* arrivalTimeMSecPtr, Bool16 firstPacket) { QTSS_RTPSessionState* theState = NULL; UInt32 theLen = 0; QTSS_Error writeErr = QTSS_NoErr; SInt64 currentTime = OS::Milliseconds(); if (inPacket == NULL || inPacket->Len == 0) return QTSS_NoErr; (void)QTSS_GetValuePtr(fClientSession, qtssCliSesState, 0, (void**)&theState, &theLen); if (theLen == 0 || theState == NULL || *theState != qtssPlayingState) { //qtss_printf("QTSS_WouldBlock *theState=%d qtssPlayingState=%d\n", *theState , qtssPlayingState); return QTSS_WouldBlock; } //make sure all RTP streams with this ID see this packet QTSS_RTPStreamObject *theStreamPtr = NULL; for (UInt32 z = 0; QTSS_GetValuePtr(fClientSession, qtssCliSesStreamObjects, z, (void**)&theStreamPtr, &theLen) == QTSS_NoErr; z++) { if (this->PacketMatchesStream(inStreamCookie, theStreamPtr)) { if ( (inFlags & qtssWriteFlagsIsRTP) && this->FilterPacket(theStreamPtr, inPacket) ) return QTSS_NoErr; // keep looking at packets if (this->PacketAlreadySent(theStreamPtr,inFlags, packetIDPtr)) return QTSS_NoErr; // keep looking at packets if (!this->PacketReadyToSend(theStreamPtr,¤tTime, inFlags, packetIDPtr, timeToSendThisPacketAgain)) { //qtss_printf("QTSS_WouldBlock\n"); return QTSS_WouldBlock; // stop not ready to send packets now } // TrackPackets below is for re-writing the rtcps we don't use it right now-- shouldn't need to // (void) this->TrackPackets(theStreamPtr, inPacket, ¤tTime,inFlags, &packetLatenessInMSec, timeToSendThisPacketAgain, packetIDPtr,arrivalTimeMSecPtr); QTSS_PacketStruct thePacket; thePacket.packetData = inPacket->Ptr; SInt64 delayMSecs = fBufferDelayMSecs - (currentTime - *arrivalTimeMSecPtr); thePacket.packetTransmitTime = (currentTime - packetLatenessInMSec); if (fBufferDelayMSecs > 0 ) thePacket.packetTransmitTime += delayMSecs; // add buffer time where oldest buffered packet as now == 0 and newest is entire buffer time in the future. writeErr = QTSS_Write(*theStreamPtr, &thePacket, inPacket->Len, NULL, inFlags | qtssWriteFlagsWriteBurstBegin); if (writeErr == QTSS_WouldBlock) { //qtss_printf("QTSS_Write == QTSS_WouldBlock\n"); // // We are flow controlled. See if we know when flow control will be lifted and report that *timeToSendThisPacketAgain = thePacket.suggestedWakeupTime; if (firstPacket) { fBufferDelayMSecs = (currentTime - *arrivalTimeMSecPtr); //qtss_printf("firstPacket fBufferDelayMSecs =%lu \n", fBufferDelayMSecs); } } else { fLastIntervalMilliSec = currentTime - fLastPacketTransmitTime; if (fLastIntervalMilliSec > 100) //reset interval maybe first packet or it has been blocked for awhile fLastIntervalMilliSec = 5; fLastPacketTransmitTime = currentTime; if (inFlags & qtssWriteFlagsIsRTP) { (void) QTSS_SetValue (*theStreamPtr, sLastRTPPacketIDAttr, 0, packetIDPtr, sizeof(UInt64)); } else if (inFlags & qtssWriteFlagsIsRTCP) { (void) QTSS_SetValue (*theStreamPtr, sLastRTCPPacketIDAttr, 0, packetIDPtr, sizeof(UInt64)); (void) QTSS_SetValue (*theStreamPtr, sLastRTCPTransmitAttr, 0, ¤tTime, sizeof(UInt64)); } { // increment packet counts UInt32* packetCountPtr = NULL; UInt32 theLen = 0; (void) QTSS_GetValuePtr(*theStreamPtr, sStreamPacketCountAttr, 0,(void**) &packetCountPtr,&theLen); if (theLen > 0) { *packetCountPtr += 1; //printf("SET sStreamPacketCountAttr =%lu\n", *packetCountPtr); } } } } if ( writeErr != QTSS_NoErr ) break; } return writeErr; }
QTSS_Error FilterRequest(QTSS_Filter_Params* inParams) { if (NULL == inParams || NULL == inParams->inRTSPSession || NULL == inParams->inRTSPRequest) { Assert(0); return QTSS_NoErr; } OSMutexLocker locker(sAdminMutex); //check to see if we should handle this request. Invokation is triggered //by a "GET /" request QTSS_Error err = QTSS_NoErr; QTSS_RTSPRequestObject theRequest = inParams->inRTSPRequest; UInt32 paramLen = sizeof(sSessID); err = QTSS_GetValue(inParams->inRTSPSession, qtssRTSPSesID, 0, (void*)&sSessID, ¶mLen); if (err != QTSS_NoErr) return QTSS_NoErr; StrPtrLen theFullRequest; err = QTSS_GetValuePtr(theRequest, qtssRTSPReqFullRequest, 0, (void**)&theFullRequest.Ptr, &theFullRequest.Len); if (err != QTSS_NoErr) return QTSS_NoErr; StringParser fullRequest(&theFullRequest); if ( !IsAdminRequest(&fullRequest) ) return QTSS_NoErr; if ( !AcceptSession(inParams->inRTSPSession) ) { (void)QTSS_Write(inParams->inRTSPRequest, sPermissionDeniedHeader, ::strlen(sPermissionDeniedHeader), NULL, 0); (void)QTSS_Write(inParams->inRTSPRequest, sHTMLBody, ::strlen(sHTMLBody), NULL, 0); KeepSession(theRequest,false); return QTSS_NoErr; } if(!GetRequestAuthenticatedState(inParams)) // must authenticate before handling { if(QTSS_IsGlobalLocked()) // must NOT be global locked return QTSS_RequestFailed; if (!IsAuthentic(inParams,&fullRequest)) { (void)QTSS_Write(inParams->inRTSPRequest, sUnauthorizedResponseHeader, ::strlen(sUnauthorizedResponseHeader), NULL, 0); (void)QTSS_Write(inParams->inRTSPRequest, sHTMLBody, ::strlen(sHTMLBody), NULL, 0); KeepSession(theRequest,false); return QTSS_NoErr; } } if (GetRequestFlushState(inParams)) { StillFlushing(inParams,true); return QTSS_NoErr; } if (!QTSS_IsGlobalLocked()) { if (InWaitInterval(inParams)) return QTSS_NoErr; //qtss_printf("New Request Wait for GlobalLock session=%"_U32BITARG_"\n",sSessID); (void)QTSS_RequestGlobalLock(); KeepSession(theRequest,true); return QTSS_NoErr; } //qtss_printf("Handle request session=%"_U32BITARG_"\n",sSessID); APITests_DEBUG(); if (sQueryPtr != NULL) { delete sQueryPtr; sQueryPtr = NULL; } sQueryPtr = NEW QueryURI(&theFullRequest); if (sQueryPtr == NULL) return QTSS_NoErr; ShowQuery_DEBUG(); if (sAdminPtr != NULL) { delete sAdminPtr; sAdminPtr = NULL; } UInt32 result = sQueryPtr->EvalQuery(NULL, NULL); if (result == 0) do { if( ElementNode_CountPtrs() > 0) { ElementNode_ShowPtrs(); Assert(0); } GetQueryData(theRequest); SendResult(theRequest); delete sAdminPtr; sAdminPtr = NULL; if (sQueryPtr && !sQueryPtr->QueryHasReponse()) { UInt32 err = 404; (void) sQueryPtr->EvalQuery(&err,NULL); ReportErr(inParams, err); break; } if (sQueryPtr && sQueryPtr->QueryHasReponse()) { ReportErr(inParams, sQueryPtr->GetEvaluResult()); } if (sQueryPtr->fIsPref && sQueryPtr->GetEvaluResult() == 0) { QTSS_ServiceID id; (void) QTSS_IDForService(QTSS_REREAD_PREFS_SERVICE, &id); (void) QTSS_DoService(id, NULL); } } while(false); else { SendHeader(theRequest); ReportErr(inParams, sQueryPtr->GetEvaluResult()); } if (sQueryPtr != NULL) { delete sQueryPtr; sQueryPtr = NULL; } (void) StillFlushing(inParams,true); return QTSS_NoErr; }
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; }
QTSS_Error Authenticate(QTSS_StandardRTSP_Params* inParams) { if ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) ) { return QTSS_RequestFailed; } QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; QTSS_Error theErr = QTSS_NoErr; char *movieUrlTrunc = NULL; theErr = QTSS_GetValueAsString(theRTSPRequest,qtssRTSPReqTruncAbsoluteURL, 0, &movieUrlTrunc); QTSSCharArrayDeleter movieUrlTruncDeleter(movieUrlTrunc); if (theErr != QTSS_NoErr) return QTSS_RequestFailed; char *movieUrlFilename = NULL; theErr = QTSS_GetValueAsString(theRTSPRequest,qtssRTSPReqFileName, 0, &movieUrlFilename); QTSSCharArrayDeleter movieUrlFilenameDeleter(movieUrlFilename); if (theErr != QTSS_NoErr) return QTSS_RequestFailed; // Return unless the requested filename matches the redirect URL if (::strncmp(movieUrlFilename, sRedirectUrl, (::strlen(movieUrlFilename) <= ::strlen(sRedirectUrl)) ? ::strlen(sRedirectUrl) : ::strlen(movieUrlFilename))) return QTSS_NoErr; // Get the client's bandwidth header UInt32 bandwidthBits = 0; UInt32 len = sizeof(bandwidthBits); (void)QTSS_GetValue(theRTSPRequest, qtssRTSPReqBandwidthBits, 0, (void *)&bandwidthBits, &len); // Prepare a filename extension to use for redirection. // These numbers match the "Streaming Speed" options in the QuickTime Player 7 settings. // The extension will be appended to the requested URL. char theNewFilename[kBuffSize]; ::memset(theNewFilename, 0, kBuffSize); if (bandwidthBits <= 0) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_50kbit.3gp", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 28000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_50kbit.3gp", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 56000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_50kbit.3gp", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 112000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_100kbit.mov", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 256000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_100kbit.mov", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 384000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_300kbit.mov", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 512000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_300kbit.mov", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 768000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_300kbit.mov", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 1000000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_h264_1mbit.mp4", movieUrlTrunc, movieUrlFilename); } else if (bandwidthBits <= 1500000) { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_h264_1mbit.mp4", movieUrlTrunc, movieUrlFilename); } else { qtss_snprintf(theNewFilename, sizeof(theNewFilename), "%s/%s_h264_1mbit.mp4", movieUrlTrunc, movieUrlFilename); } // In order to send the redirect, we need to get a QTSS_StreamRef // so we can send data to the client. Get the QTSS_StreamRef out of the request. QTSS_StreamRef* theStreamRef = NULL; UInt32 strRefLen = 0; theErr = QTSS_GetValuePtr(theRTSPRequest, qtssRTSPReqStreamRef, 0, (void**)&theStreamRef, &strRefLen); if (( QTSS_NoErr != theErr ) || ( sizeof(QTSS_StreamRef) != strRefLen) ) { return QTSS_RequestFailed; } // Send the redirect UInt32 theLenWritten = 0; (void)QTSS_Write(*theStreamRef, sRedirect.Ptr, sRedirect.Len, &theLenWritten, 0); (void)QTSS_Write(*theStreamRef, sLocation.Ptr, sLocation.Len, &theLenWritten, 0); (void)QTSS_Write(*theStreamRef, theNewFilename, ::strlen(theNewFilename), &theLenWritten, 0); (void)QTSS_Write(*theStreamRef, sRedirectEnd.Ptr, sRedirectEnd.Len, &theLenWritten, 0); (void)QTSS_Flush(*theStreamRef); return QTSS_NoErr; }
QTSS_Error QTSSModuleUtils::SendErrorResponse( QTSS_RTSPRequestObject inRequest, QTSS_RTSPStatusCode inStatusCode, QTSS_AttributeID inTextMessage, StrPtrLen* inStringArg) { static Bool16 sFalse = false; //set RTSP headers necessary for this error response message (void)QTSS_SetValue(inRequest, qtssRTSPReqStatusCode, 0, &inStatusCode, sizeof(inStatusCode)); (void)QTSS_SetValue(inRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse)); StringFormatter theErrorMsgFormatter(NULL, 0); char *messageBuffPtr = NULL; if (sEnableRTSPErrorMsg) { // Retrieve the specified message out of the text messages dictionary. StrPtrLen theMessage; (void)QTSS_GetValuePtr(sMessages, inTextMessage, 0, (void**)(void*)&theMessage.Ptr, &theMessage.Len); if ((theMessage.Ptr == NULL) || (theMessage.Len == 0)) { // If we couldn't find the specified message, get the default // "No Message" message, and return that to the client instead. (void)QTSS_GetValuePtr(sMessages, qtssMsgNoMessage, 0, (void**)(void*)&theMessage.Ptr, &theMessage.Len); } Assert(theMessage.Ptr != NULL); Assert(theMessage.Len > 0); // Allocate a temporary buffer for the error message, and format the error message // into that buffer UInt32 theMsgLen = 256; if (inStringArg != NULL) theMsgLen += inStringArg->Len; messageBuffPtr = NEW char[theMsgLen]; messageBuffPtr[0] = 0; theErrorMsgFormatter.Set(messageBuffPtr, theMsgLen); // // Look for a %s in the string, and if one exists, replace it with the // argument passed into this function. //we can safely assume that message is in fact NULL terminated char* stringLocation = ::strstr(theMessage.Ptr, "%s"); if (stringLocation != NULL) { //write first chunk theErrorMsgFormatter.Put(theMessage.Ptr, stringLocation - theMessage.Ptr); if (inStringArg != NULL && inStringArg->Len > 0) { //write string arg if it exists theErrorMsgFormatter.Put(inStringArg->Ptr, inStringArg->Len); stringLocation += 2; } //write last chunk theErrorMsgFormatter.Put(stringLocation, (theMessage.Ptr + theMessage.Len) - stringLocation); } else theErrorMsgFormatter.Put(theMessage); char buff[32]; qtss_sprintf(buff,"%"_U32BITARG_"",theErrorMsgFormatter.GetBytesWritten()); (void)QTSS_AppendRTSPHeader(inRequest, qtssContentLengthHeader, buff, ::strlen(buff)); } //send the response header. In all situations where errors could happen, we //don't really care, cause there's nothing we can do anyway! (void)QTSS_SendRTSPHeaders(inRequest); // // 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, theErrorMsgFormatter.GetBufPtr(), theErrorMsgFormatter.GetBytesWritten(), NULL, 0); (void)QTSS_SetValue(inRequest, qtssRTSPReqRespMsg, 0, theErrorMsgFormatter.GetBufPtr(), theErrorMsgFormatter.GetBytesWritten()); delete [] messageBuffPtr; return QTSS_RequestFailed; }
void QTSSModuleUtils::LogErrorStr( QTSS_ErrorVerbosity inVerbosity, char* inMessage) { if (inMessage == NULL) return; (void)QTSS_Write(sErrorLog, inMessage, ::strlen(inMessage), NULL, inVerbosity); }
void SendStats(QTSS_StreamRef inStream, UInt32 refreshInterval, Bool16 displayHelp, StrPtrLen* fieldList) { struct FieldIndex { char* fieldName; int fieldIndex; }; const FieldIndex kFieldIndexes[] = { {"title", 1}, {"dnsname", 2}, {"curtime", 3}, {"", 4}, {"serververs", 5}, {"serverbornon", 6}, {"serverstatus", 7}, {"", 8}, {"", 9}, {"", 10}, {"", 11}, {"", 12}, {"", 13}, {"currtp", 14}, {"currtsp", 15}, {"currtsphttp", 16}, {"curthru", 17}, {"curpkts", 18}, {"totbytes", 19}, {"totconns", 20}, {"", 21}, {"connlimit", 22}, {"thrulimit", 23}, {"moviedir", 24}, {"rtspip", 25}, {"rtspport", 26}, {"rtsptimeout", 27}, {"rtptimeout", 28}, {"secstobuffer", 29}, {"", 30}, {"accesslog", 31}, {"accesslogdir",32}, {"accesslogname", 33}, {"accessrollsize", 34}, {"accessrollinterval", 35}, {"", 36}, {"errorlog", 37}, {"errorlogdir", 38}, {"errorlogname", 39}, {"errorrollsize", 40}, {"errorrollinterval", 41}, {"errorloglevel", 42}, {"", 43}, {"assertbreak", 44}, {"autostart", 45}, {"totbytesupdateinterval", 46}, {"reflectordelay", 47}, {"reflectorbucketsize", 48}, {"historyinterval", 49}, {"outoffiledesc", 50}, {"numudpsockets", 51}, {"apiversion", 52}, {"numreliableudpbuffers", 53}, {"reliableudpwastedbytes", 54}, {"numtaskthreads", 55} }; const int kMaxFieldNum = 55; static char* kEmptyStr = "?"; char* thePrefStr = kEmptyStr; char buffer[1024]; (void)QTSS_Write(inStream, sResponseHeader, ::strlen(sResponseHeader), NULL, 0); if (refreshInterval > 0) { qtss_sprintf(buffer, "<META HTTP-EQUIV=Refresh CONTENT=%"_U32BITARG_">\n", refreshInterval); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } //qtss_sprintf(buffer, "<body text=\"#000000\" bgcolor=\"#C0C0C0\" link=\"#0000FF\" vlink=\"#551A8B\" alink=\"#0000FF\">\n"); //(void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); char *theHTML = "<HTML><BODY>\n"; (void)QTSS_Write(inStream, theHTML, ::strlen(theHTML), NULL, 0); if (displayHelp) { #ifndef __MacOSX__ static StrPtrLen sHelpLine1("<P><b>Streaming Server Statistics Help</b></P>\n"); #else static StrPtrLen sHelpLine1("<P><b>QuickTime Streaming Server Statistics Help</b></P>\n"); #endif static StrPtrLen sHelpLine2("<P>Example:</P>\n"); static StrPtrLen sHelpLine3("<BLOCKQUOTE><P>http://server/statsURL?help&refresh=15&fields=curtime,cpuload </P>\n"); static StrPtrLen sHelpLine4("\"?\" means that there are options being attached to the stats request.<BR>\n"); static StrPtrLen sHelpLine5("\"&\" separates multiple stats options<BR>\n<BR>\n"); static StrPtrLen sHelpLine6("<P>The three possible parameters to stats are:</P>\n"); static StrPtrLen sHelpLine7("<P>\"help\" -- shows the help information you're reading right now.</P>\n"); static StrPtrLen sHelpLine8("<P>\"refresh=[n]\" -- tells the browser to automatically update the page every [n] seconds.</P>\n"); static StrPtrLen sHelpLine9("<P>\"fields=[fieldList]\" -- show only the fields specified in comma delimited [fieldList]</P>\n"); static StrPtrLen sHelpLine10("<BLOCKQUOTE>The following fields are available for use with the \"fields\" option:</P><BLOCKQUOTE><DL>\n"); (void)QTSS_Write(inStream, sHelpLine1.Ptr, sHelpLine1.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine2.Ptr, sHelpLine2.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine3.Ptr, sHelpLine3.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine4.Ptr, sHelpLine4.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine5.Ptr, sHelpLine5.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine6.Ptr, sHelpLine6.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine7.Ptr, sHelpLine7.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine8.Ptr, sHelpLine8.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine9.Ptr, sHelpLine9.Len, NULL, 0); (void)QTSS_Write(inStream, sHelpLine10.Ptr, sHelpLine10.Len, NULL, 0); for (short i = 0; i < kMaxFieldNum; i++) { qtss_sprintf(buffer, "<DT><I>%s</I></DT>\n", kFieldIndexes[i].fieldName); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } static StrPtrLen sHelpLine11("</DL></BLOCKQUOTE></BLOCKQUOTE></BLOCKQUOTE><BR><P><HR>"); (void)QTSS_Write(inStream, sHelpLine11.Ptr, sHelpLine11.Len, NULL, 0); } StringParser fieldNamesParser(fieldList); StrPtrLen fieldName; int fieldNum = 0; do { if (fieldList != NULL) { fieldNum = 0; fieldNamesParser.ConsumeWord(&fieldName); for (short i = 0; i < kMaxFieldNum; i++) { if ( fieldName.Equal(StrPtrLen(kFieldIndexes[i].fieldName, ::strlen(kFieldIndexes[i].fieldName))) ) { fieldNum = kFieldIndexes[i].fieldIndex; break; } } } else { fieldNum++; if ( fieldNum > kMaxFieldNum ) fieldNum = 0; } UInt32 theLen = 0; switch (fieldNum) { case 1: { #if __MacOSX__ static StrPtrLen sStatsLine1("<TITLE>QuickTime Streaming Server Stats</TITLE><BR>\n"); (void)QTSS_Write(inStream, sStatsLine1.Ptr, sStatsLine1.Len, NULL, 0); #else static StrPtrLen sStatsLine1("<TITLE>Streaming Server Stats</TITLE><BR>\n"); (void)QTSS_Write(inStream, sStatsLine1.Ptr, sStatsLine1.Len, NULL, 0); #endif #if __MacOSX__ static StrPtrLen sStatsLine2("<center><h1>QuickTime Streaming Server Statistics</h1></center>\n"); (void)QTSS_Write(inStream, sStatsLine2.Ptr, sStatsLine2.Len, NULL, 0); #else static StrPtrLen sStatsLine2("<center><h1>Streaming Server Statistics</h1></center>\n"); (void)QTSS_Write(inStream, sStatsLine2.Ptr, sStatsLine2.Len, NULL, 0); #endif } break; case 2: { StrPtrLen theDNS; (void)QTSS_GetValuePtr(sServer, qtssSvrDefaultDNSName, 0, (void**)&theDNS.Ptr, &theDNS.Len); if ( theDNS.Ptr == NULL ) { // no DNS, try for the IP address only. (void)QTSS_GetValuePtr(sServer, qtssSvrDefaultIPAddr, 0, (void**)&theDNS.Ptr, &theDNS.Len); } if ( theDNS.Ptr != NULL ) { qtss_sprintf(buffer, "<b>DNS Name (default): </b> %s<BR>\n", theDNS.Ptr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 3: { char uptimebuffer[1024]; time_t curTime = ::time(NULL); qtss_sprintf(uptimebuffer, "<b>Current Time: </b> %s<BR>\n", qtss_ctime(&curTime, buffer, sizeof(buffer))); (void)QTSS_Write(inStream, uptimebuffer, ::strlen(uptimebuffer), NULL, 0); time_t upTime = curTime - sStartupTime; #define kDaySeconds (24 * 60 * 60) #define kHourSeconds (60 * 60) #define kMinuteSeconds 60 UInt32 upTimeDays = upTime / kDaySeconds; UInt32 upTimeHours = (upTime % kDaySeconds) / kHourSeconds; UInt32 upTimeMinutes = (upTime % kHourSeconds) / kMinuteSeconds; UInt32 upTimeSeconds = (upTime % kMinuteSeconds); qtss_snprintf(uptimebuffer,sizeof(uptimebuffer), "<b>Up Time Total Seconds: </b> %"_U32BITARG_"<BR>\n", upTime); uptimebuffer[sizeof(uptimebuffer) -1] = 0; (void)QTSS_Write(inStream, uptimebuffer, ::strlen(uptimebuffer), NULL, 0); qtss_snprintf(uptimebuffer,sizeof(uptimebuffer), "<b>Up Time: </b> %"_U32BITARG_" days %"_U32BITARG_" hours %"_U32BITARG_" minutes %"_U32BITARG_" seconds <BR>\n", upTimeDays, upTimeHours,upTimeMinutes, upTimeSeconds); uptimebuffer[sizeof(uptimebuffer) -1] = 0; (void)QTSS_Write(inStream, uptimebuffer, ::strlen(uptimebuffer), NULL, 0); } break; case 4: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; case 5: { StrPtrLen theVersion; (void)QTSS_GetValuePtr(sServer, qtssSvrRTSPServerHeader, 0, (void**)&theVersion.Ptr, &theVersion.Len); Assert(theVersion.Ptr != NULL); if (theVersion.Len > 7) //Skip the "Server:" text theVersion.Ptr += 7; qtss_sprintf(buffer, "<b>Server Version: </b>%s<BR>\n", theVersion.Ptr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 6: { StrPtrLen theBuildDate; (void)QTSS_GetValuePtr(sServer, qtssSvrServerBuildDate, 0, (void**)&theBuildDate.Ptr, &theBuildDate.Len); Assert(theBuildDate.Ptr != NULL); qtss_sprintf(buffer, "<b>Server Build Date: </b> %s<BR>\n", theBuildDate.Ptr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 7: { char statusBuffer[1024]; const char* states[] = { "Starting Up", "Running", "Refusing Connections", "Fatal Error", "Shutting Down" }; QTSS_ServerState theState = qtssRunningState; theLen = sizeof(theState); (void)QTSS_GetValue(sServer, qtssSvrState, 0, &theState, &theLen); if (theState == qtssRunningState) { qtss_snprintf(statusBuffer, sizeof(statusBuffer), "<b>Status: </b> %s since %s<BR>", states[theState], qtss_ctime(&sStartupTime,buffer,sizeof(buffer))); } else qtss_snprintf(statusBuffer,sizeof(statusBuffer), "<b>Status: </b> %s<BR>", states[theState]); (void)QTSS_Write(inStream, statusBuffer, ::strlen(statusBuffer), NULL, 0); } break; case 8: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; case 9: { //NOOP } break; case 10: { //NOOP } break; case 11: { //NOOP } break; case 12: { /* struct vm_statistics vmStats = {}; if (vm_statistics (current_task (), &vmStats) != KERN_SUCCESS) memset (&stats, '\0', sizeof (vmStats)) ; */ (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; case 13: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; //********************************** case 14: { (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurConn, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Current RTP Connections: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 15: { (void)QTSS_GetValueAsString(sServer, qtssRTSPCurrentSessionCount, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Current RTSP Connections: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 16: { (void)QTSS_GetValueAsString(sServer, qtssRTSPHTTPCurrentSessionCount, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Current RTSP over HTTP Connections: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 17: { UInt32 curBandwidth = 0; theLen = sizeof(curBandwidth); (void)QTSS_GetValue(sServer, qtssRTPSvrCurBandwidth, 0, &curBandwidth, &theLen); qtss_sprintf(buffer, "<b>Current Throughput: </b> %"_U32BITARG_" kbits<BR>\n", curBandwidth/1024); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 18: { (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurPackets, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Current Packets Per Second: </b> %s <BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 19: { (void)QTSS_GetValueAsString(sServer, qtssRTPSvrTotalBytes, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Total Bytes Served: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 20: { (void)QTSS_GetValueAsString(sServer, qtssRTPSvrTotalConn, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Total Connections: </b> %s<BR>", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 21: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; //************************************** case 22: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMaximumConnections, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Maximum Connections: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 23: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMaximumBandwidth, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Maximum Throughput: </b> %s Kbits<BR>\n",thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 24: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMovieFolder, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Movie Folder Path: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 25: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsRTSPIPAddr, 0, &thePrefStr); qtss_sprintf(buffer, "<b>RTSP IP Address: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 26: { static StrPtrLen sRTSPPortsStart("<b>RTSP Ports: </b> "); (void)QTSS_Write(inStream, sRTSPPortsStart.Ptr, sRTSPPortsStart.Len, NULL, 0); StrPtrLen thePort; for (UInt32 theIndex = 0; true; theIndex++) { QTSS_Error theErr = QTSS_GetValuePtr(sServer, qtssSvrRTSPPorts, theIndex, (void**)&thePort.Ptr, &thePort.Len); if (theErr != QTSS_NoErr) break; Assert(thePort.Ptr != NULL); char temp[20]; qtss_sprintf(temp, "%u ", *(UInt16*)thePort.Ptr); (void)QTSS_Write(inStream, temp, ::strlen(temp), NULL, 0); } static StrPtrLen sRTSPPortsEnd("<BR>\n"); (void)QTSS_Write(inStream, sRTSPPortsEnd.Ptr, sRTSPPortsEnd.Len, NULL, 0); } break; case 27: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsRTSPTimeout, 0, &thePrefStr); qtss_sprintf(buffer, "<b>RTP Timeout: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 28: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsRTPTimeout, 0, &thePrefStr); qtss_sprintf(buffer, "<b>RTP Timeout: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 29: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; case 30: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; case 31: { if ( sAccessLogPrefs != NULL ) { thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logging"); qtss_sprintf(buffer, "<b>Access Logging: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 32: { if ( sAccessLogPrefs != NULL ) { thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_dir"); qtss_sprintf(buffer, "<b>Access Log Directory: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 33: { if ( sAccessLogPrefs != NULL ) { thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_name"); qtss_sprintf(buffer, "<b>Access Log Name: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 34: { if ( sAccessLogPrefs != NULL ) { thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_size"); qtss_sprintf(buffer, "<b>Access Log Roll Size: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 35: { if ( sAccessLogPrefs != NULL ) { thePrefStr = GetPrefAsString(sAccessLogPrefs, "request_logfile_interval"); qtss_sprintf(buffer, "<b>Access Log Roll Interval (days): </b> %s<BR>", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 36: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; case 37: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogEnabled, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Error Logging: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 38: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogDir, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Error Log Directory: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 39: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogName, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Error Log Name: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 40: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsMaxErrorLogSize, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Error Log Roll Size: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 41: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorRollInterval, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Error Log Roll Interval (days): </b> %s<BR>\n",thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 42: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogVerbosity, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Error Log Verbosity: </b> %s<BR>", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 43: { (void)QTSS_Write(inStream, "<P><HR>", ::strlen("<P><HR>"), NULL, 0); } break; case 44: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsBreakOnAssert, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Break On Assert: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 45: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsAutoRestart, 0, &thePrefStr); qtss_sprintf(buffer, "<b>AutoStart: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 46: { (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsTotalBytesUpdate, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Total Bytes Update Interval: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 47: { if (sReflectorPrefs != NULL) { thePrefStr = GetPrefAsString(sReflectorPrefs, "reflector_delay"); qtss_sprintf(buffer, "<b>Reflector Delay Time: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 48: { if (sReflectorPrefs != NULL) { thePrefStr = GetPrefAsString(sReflectorPrefs, "reflector_bucket_size"); qtss_sprintf(buffer, "<b>Reflector Bucket Size: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 49: { if ( sSvrControlPrefs != NULL) { thePrefStr = GetPrefAsString(sSvrControlPrefs, "history_update_interval"); qtss_sprintf(buffer, "<b>History Update Interval: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } } break; case 50: { Bool16 isOutOfDescriptors = false; theLen = sizeof(isOutOfDescriptors); (void)QTSS_GetValue(sServer, qtssSvrIsOutOfDescriptors, 0, &isOutOfDescriptors, &theLen); qtss_sprintf(buffer, "<b>Out of file descriptors: </b> %d<BR>\n", isOutOfDescriptors); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 51: { (void)QTSS_GetValueAsString(sServer, qtssRTPSvrNumUDPSockets, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Number of UDP sockets: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 52: { UInt32 apiVersion = 0; UInt32 size = sizeof(UInt32); (void)QTSS_GetValue(sServer, qtssServerAPIVersion, 0, &apiVersion, &size); qtss_sprintf(buffer, "<b>API version: </b> %d.%d<BR>\n", (int)( (UInt32) (apiVersion & (UInt32) 0xFFFF0000L) >> 16), (int)(apiVersion &(UInt32) 0x0000FFFFL)); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 53: { UInt32 reliableUDPBuffers = 0; UInt32 blahSize = sizeof(reliableUDPBuffers); (void)QTSS_GetValue(sServer, qtssSvrNumReliableUDPBuffers, 0, &reliableUDPBuffers, &blahSize); qtss_sprintf(buffer, "<b>Num Reliable UDP Retransmit Buffers: </b> %"_U32BITARG_"<BR>\n", reliableUDPBuffers); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 54: { UInt32 wastedBufSpace = 0; UInt32 blahSize2 = sizeof(wastedBufSpace); (void)QTSS_GetValue(sServer, qtssSvrReliableUDPWastageInBytes, 0, &wastedBufSpace, &blahSize2); qtss_sprintf(buffer, "<b>Amount of buffer space being wasted in UDP Retrans buffers: </b> %"_U32BITARG_"<BR>\n", wastedBufSpace); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; case 55: { (void)QTSS_GetValueAsString(sServer, qtssSvrNumThreads, 0, &thePrefStr); qtss_sprintf(buffer, "<b>Number of Task Threads: </b> %s<BR>\n", thePrefStr); (void)QTSS_Write(inStream, buffer, ::strlen(buffer), NULL, 0); } break; default: break; } //switch fieldNum if (fieldList != NULL && !fieldNamesParser.Expect(',')) fieldNum = 0; if (thePrefStr != kEmptyStr) delete [] thePrefStr; thePrefStr = kEmptyStr; } while (fieldNum != 0); theHTML = "</BODY></HTML>\n"; (void)QTSS_Write(inStream, theHTML, ::strlen(theHTML), NULL, 0); }
QTSS_Error FilterRequest(QTSS_Filter_Params* inParams) { #if HTTP_FILE_DEBUGGING qtss_printf("FilterRequest\n"); #endif static Bool16 sFalse = false; QTSS_RTSPRequestObject theRequest = inParams->inRTSPRequest; // Initial state. StrPtrLen theFullRequest; StrPtrLen reqMethod; StrPtrLen reqStr; StrPtrLen httpVersion; (void)QTSS_GetValuePtr(theRequest, qtssRTSPReqFullRequest, 0, (void**)&theFullRequest.Ptr, &theFullRequest.Len); StringParser fullRequest(&theFullRequest); // Parsing the HTTP request fullRequest.ConsumeWord(&reqMethod); if ( !(reqMethod.Equal(StrPtrLen("GET")) || reqMethod.Equal(StrPtrLen("HEAD"))) ) // It's not a "Get" or a "Head" request return QTSS_NoErr; fullRequest.ConsumeWhitespace(); if ( !fullRequest.Expect('/') ) // Improperly formed request return QTSS_NoErr; fullRequest.ConsumeUntil(&reqStr, StringParser::sEOLWhitespaceMask); if( reqStr.Len == 0 ) //if a file or directory name is not given, return return QTSS_NoErr; if ( !reqStr.Equal(StrPtrLen("Popular.smil")) ) return QTSS_NoErr; // If it's a "Head" request send the Head response header back and just return if ( reqMethod.Equal(StrPtrLen("HEAD")) ) { QTSS_Write(theRequest, sResponseHeader, ::strlen(sResponseHeader), NULL, 0); return QTSS_NoErr; } // Create a buffer to store data. char theFileBuffer[8192]; char contentLength[256]; // Before sending any response, set keep alive to off for this connection // Regardless of what the client sends, the server always closes the connection after sending the file (void)QTSS_SetValue(theRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse)); #if HTTP_FILE_DEBUGGING qtss_printf("Creating a smil file\n"); #endif // Create a ref movie buffer for the single file. It is of the form: // rtsptext\r // rtsp://servername/filepath char smilFileBuf[8192] = {0}; GenerateHotHitSMIL(smilFileBuf); qtss_sprintf(contentLength, "%lu", strlen(smilFileBuf)); // Allocate memory for theFileBuffer // Write the HTTP header prefix into the buffer ::strcpy(theFileBuffer, sRespHeaderPrefix.Ptr); ::strcat(theFileBuffer, sContentLengthHeaderTag.Ptr); // Write the remaining part of the HTTP header into the file buffer ::strcat(theFileBuffer, contentLength); ::strcat(theFileBuffer, sContentTypeHeaderTag.Ptr); ::strcat(theFileBuffer, sSmilMimeType.Ptr); ::strcat(theFileBuffer, "\r\n\r\n"); // Write the smil file created above to the file buffer ::strcat(theFileBuffer, smilFileBuf); // Write the contents of the file buffer to the request stream and return QTSS_Write(theRequest, theFileBuffer, strlen(theFileBuffer), NULL, 0); #if HTTP_FILE_DEBUGGING qtss_printf("Wrote the smil file to the request stream. Successful!\n"); #endif return QTSS_NoErr; }