void PrintStatus(Bool16 printHeader) { char* thePrefStr = NULL; UInt32 theLen = 0; if ( printHeader ) { qtss_printf(" RTP-Conns RTSP-Conns HTTP-Conns kBits/Sec Pkts/Sec TotConn TotBytes TotPktsLost Time\n"); } (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurConn, 0, &thePrefStr); qtss_printf( "%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; (void)QTSS_GetValueAsString(sServer, qtssRTSPCurrentSessionCount, 0, &thePrefStr); qtss_printf( "%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; (void)QTSS_GetValueAsString(sServer, qtssRTSPHTTPCurrentSessionCount, 0, &thePrefStr); qtss_printf( "%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; UInt32 curBandwidth = 0; theLen = sizeof(curBandwidth); (void)QTSS_GetValue(sServer, qtssRTPSvrCurBandwidth, 0, &curBandwidth, &theLen); qtss_printf("%11"_U32BITARG_, curBandwidth/1024); (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurPackets, 0, &thePrefStr); qtss_printf( "%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; (void)QTSS_GetValueAsString(sServer, qtssRTPSvrTotalConn, 0, &thePrefStr); qtss_printf( "%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; UInt64 totalBytes = sServer->GetTotalRTPBytes(); char displayBuff[32] = ""; FormattedTotalBytesBuffer(displayBuff, sizeof(displayBuff),totalBytes); qtss_printf( "%17s", displayBuff); qtss_printf( "%11"_64BITARG_"u", sServer->GetTotalRTPPacketsLost()); char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes]; (void) QTSSRollingLog::FormatDate(theDateBuffer, false); qtss_printf( "%25s",theDateBuffer); qtss_printf( "\n"); }
char* EasyAdmin_GetMoviesFolder() { char* movieFolderString = NULL; (void) QTSS_GetValueAsString (sServerPrefs, qtssPrefsMovieFolder, 0, &movieFolderString); return movieFolderString; }
char* EasyAdmin_GetErrorLogFolder() { char* logFolderString = NULL; (void) QTSS_GetValueAsString (sServerPrefs, qtssPrefsErrorLogDir, 0, &logFolderString); return logFolderString; }
void DebugLevel_1(FILE* statusFile, FILE* stdOut, Bool16 printHeader ) { char* thePrefStr = NULL; static char numStr[12] =""; static char dateStr[25] =""; UInt32 theLen = 0; if ( printHeader ) { printf("****************************************"); } delete [] thePrefStr; thePrefStr = NULL; (void)QTSS_GetValueAsString(sServer, qtssCurrentSessionCount, 0, &thePrefStr); print_status(statusFile, stdOut,"%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; qtss_snprintf(numStr,sizeof(numStr) -1, "%" _U32BITARG_ "", (SInt32) sServer->GetNumThinned() ); print_status(statusFile, stdOut,"%11s", numStr); char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes]; (void) QTSSRollingLog::FormatDate(theDateBuffer, false); qtss_snprintf(dateStr,sizeof(dateStr) -1, "%s", theDateBuffer ); print_status(statusFile, stdOut,"%24s\n", dateStr); }
/** * This is called when a clients session ends - use this to update services */ static QTSS_Error ClientSessionClosing(QTSS_ClientSessionClosing_Params* inParams) { QTSS_ClientSessionObject theClientSession = inParams->inClientSession; printf("QTSSIcecastAuthModule::ClientSessionClosing called"); // QTSS_TimeVal clientSessCreateTime = NULL; // UInt32 createTimeLen = sizeof(clientSessCreateTime); // QTSS_GetValue(theClientSession, qtssCliSesCreateTimeInMsec, 0, (void*)&clientSessCreateTime, &createTimeLen); // printf("QTSSIcecastAuthModule::ClientSessionClosing: Client session start time (millis): %ld\n", (long)clientSessCreateTime); char* iceSessID = NULL; QTSS_Error getSessErr = QTSS_GetValueAsString(theClientSession, attrClientSessionFullSessionID, 0, &iceSessID); if (getSessErr == QTSS_ValueNotFound) { // this client session doesn't have a session ID, therefore probably came in via // the IP exclusion list. Ignore printf("QTSSIcecastAuthModule::ClientSessionClosing: session ID not found. probably in exclusion list.\n"); } else { // handle the session closing. printf("QTSSIcecastAuthModule::ClientSessionClosing: the full session ID: %s\n", iceSessID); CallEndSession(&theClientSession); } return QTSS_NoErr; }
void DoDescribeAddRequiredSDPLines2(QTSS_StandardRTSP_Params* inParams, ReflectorSession* theSession, QTSS_TimeVal modDate, ResizeableStringFormatter *editedSDP, StrPtrLen* theSDPPtr) { SDPContainer checkedSDPContainer; checkedSDPContainer.SetSDPBuffer( theSDPPtr ); if (!checkedSDPContainer.HasReqLines()) { if (!checkedSDPContainer.HasLineType('v')) { // add v line editedSDP->Put("v=0\r\n"); } if (!checkedSDPContainer.HasLineType('s')) { // add s line char* theSDPName = NULL; (void)QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFilePath, 0, &theSDPName); QTSSCharArrayDeleter thePathStrDeleter(theSDPName); editedSDP->Put("s="); editedSDP->Put(theSDPName); editedSDP->PutEOL(); } if (!checkedSDPContainer.HasLineType('t')) { // add t line editedSDP->Put("t=0 0\r\n"); } if (!checkedSDPContainer.HasLineType('o')) { // add o line editedSDP->Put("o=broadcast_sdp "); char tempBuff[256]= ""; tempBuff[255] = 0; qtss_snprintf(tempBuff,sizeof(tempBuff) - 1, "%lu", (UInt64) theSession); editedSDP->Put(tempBuff); editedSDP->Put(" "); // modified date is in milliseconds. Convert to NTP seconds as recommended by rfc 2327 qtss_snprintf(tempBuff, sizeof(tempBuff) - 1, "%"_64BITARG_"d", (SInt64) (modDate/1000) + 2208988800LU); editedSDP->Put(tempBuff); editedSDP->Put(" IN IP4 "); UInt32 buffLen = sizeof(tempBuff) -1; (void)QTSS_GetValue(inParams->inClientSession, qtssCliSesHostName, 0, &tempBuff, &buffLen); editedSDP->Put(tempBuff, buffLen); editedSDP->PutEOL(); } } editedSDP->Put(*theSDPPtr); }
void PrintStatus(Bool16 printHeader) { char* thePrefStr = NULL; UInt32 theLen = 0; (void)QTSS_GetValueAsString(sServer, qtssCurrentSessionCount, 0, &thePrefStr); qtss_printf( "%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; //获取当前时间 char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes]; (void) QTSSRollingLog::FormatDate(theDateBuffer, false); qtss_printf( "%25s",theDateBuffer); qtss_printf( "\n"); }
QTSS_Error DoDescribe(QTSS_StandardRTSP_Params* inParams) { char* theUriStr = NULL; QTSS_Error err = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileName, 0, &theUriStr); Assert(err == QTSS_NoErr); if(err != QTSS_NoErr) return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest, 0); QTSSCharArrayDeleter theUriStrDeleter(theUriStr); //从接口获取信息结构体 //信息存在rtsp://59.46.115.84:8554/h264/ch1/sub/av_stream RTSPRelaySession* clientSes = NULL; //首先查找Map里面是否已经有了对应的流 StrPtrLen streamName(theUriStr); OSRef* clientSesRef = sRelaySessionMap->Resolve(&streamName); if(clientSesRef != NULL) { clientSes = (RTSPRelaySession*)clientSesRef->GetObject(); } else { clientSes = NEW RTSPRelaySession("rtsp://*****:*****@192.168.66.189/", RTSPRelaySession::kRTSPTCPClientType, theUriStr); QTSS_Error theErr = clientSes->SendDescribe(); if(theErr == QTSS_NoErr) { OS_Error theErr = sRelaySessionMap->Register(clientSes->GetRef()); Assert(theErr == QTSS_NoErr); } else { clientSes->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientNotFound, 0); } //增加一次对RelaySession的无效引用,后面会统一释放 OSRef* debug = sRelaySessionMap->Resolve(&streamName); Assert(debug == clientSes->GetRef()); } return QTSS_NoErr; }
QTSS_Error RereadPrefs() { delete[] sDefaultLogDir; (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsErrorLogDir, 0, &sDefaultLogDir); QTSSModuleUtils::GetAttribute(sPrefs, "request_logging", qtssAttrDataTypeBool16, &sLogEnabled, &sDefaultLogEnabled, sizeof(sLogEnabled)); QTSSModuleUtils::GetAttribute(sPrefs, "request_logfile_size", qtssAttrDataTypeUInt32, &sMaxLogBytes, &sDefaultMaxLogBytes, sizeof(sMaxLogBytes)); QTSSModuleUtils::GetAttribute(sPrefs, "request_logfile_interval", qtssAttrDataTypeUInt32, &sRollInterval, &sDefaultRollInterval, sizeof(sRollInterval)); QTSSModuleUtils::GetAttribute(sPrefs, "request_logtime_in_gmt", qtssAttrDataTypeBool16, &sLogTimeInGMT, &sDefaultLogTimeInGMT, sizeof(sLogTimeInGMT)); CheckAccessLogState(false); return QTSS_NoErr; }
char* QTSSModuleUtils::GetStringAttribute(QTSS_Object inObject, char* inAttributeName, char* inDefaultValue) { UInt32 theDefaultValLen = 0; if (inDefaultValue != NULL) theDefaultValLen = ::strlen(inDefaultValue); // // Check to make sure this attribute is the right type. If it's not, this will coerce // it to be the right type QTSS_AttributeID theID = QTSSModuleUtils::CheckAttributeDataType(inObject, inAttributeName, qtssAttrDataTypeCharArray, inDefaultValue, theDefaultValLen); char* theString = NULL; (void)QTSS_GetValueAsString(inObject, theID, 0, &theString); if (theString != NULL) return theString; // // If we get here the attribute must be missing, so create it and log // an error. QTSSModuleUtils::CreateAttribute(inObject, inAttributeName, qtssAttrDataTypeCharArray, inDefaultValue, theDefaultValLen); // // Return the default if it was provided. Only log an error if the default value was provided if (theDefaultValLen > 0) { QTSSModuleUtils::LogError( sMissingPrefVerbosity, qtssServerPrefMissing, 0, inAttributeName, inDefaultValue); } if (inDefaultValue != NULL) { // // Whether to return the default value or not from this function is dependent // solely on whether the caller passed in a non-NULL pointer or not. // This ensures that if the caller wants an empty-string returned as a default // value, it can do that. theString = NEW char[theDefaultValLen + 1]; ::strcpy(theString, inDefaultValue); return theString; }
static void CallEndSession(QTSS_ClientSessionObject* theClientSession) { // action=listener_remove&server=myserver.com&port=8000&client=1&mount=/live&user=&pass=&duration=3600 // the duration SInt64* connectedTime = NULL; UInt32 connectedTimeLen = sizeof(connectedTime); (void)QTSS_GetValuePtr(*theClientSession, qtssCliSesTimeConnectedInMsec, 0, (void**)&connectedTime, &connectedTimeLen); qtss_printf("QTSSIcecastAuthModule::CallEndSession connected time in seconds %li\n", (*connectedTime / 1000)); long duration = (long)*connectedTime / 1000; // the mount point char mountPoint[128] = {0}; StrPtrLen mountPointStr(mountPoint,sizeof(mountPoint)); (void)QTSS_GetValue(*theClientSession, attrClientSessionMountPoint, 0, (void*)mountPointStr.Ptr, &mountPointStr.Len); printf("QTSSIcecastAuthModule::CallEndSession: mount point: %s\n", mountPoint); // TODO - we don't use this data on the remote end (yet), but implement - will probably need to copy // credentials into the client session from the RTSP session (annoying, but both aren't visible at all times) // // username and password // char* username = NULL; // (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedUsername, 0, &username); // printf("QTSSIcecastAuthModule::CallEndSession: Provided username extracted from client session: %s\n", username); // // char* password = NULL; // (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedPassword, 0, &password); // printf("QTSSIcecastAuthModule::CallEndSession: Provided password extracted from client session: %s\n", password); // ice session id char* iceSessID = NULL; QTSS_Error getSessErr = QTSS_GetValueAsString(*theClientSession, attrClientSessionFullSessionID, 0, &iceSessID); char postdata[512]; qtss_sprintf(postdata, "action=listener_remove&server=%s&port=554&client=%s&mount=%s&user=%s&pass=%s&duration=%li", hostname, iceSessID, mountPoint, "", "", duration); printf("QTSSIcecastAuthModule::CallAuthorizeSession: generated postdata: %s\n", postdata); printf("QTSSIcecastAuthModule::CallAuthorizeSession: i would post this to: %s\n", sEndSessionEndpoint); }
char* GetPrefAsString(QTSS_ModulePrefsObject inPrefsObject, char* inPrefName) { static StrPtrLen sEmpty(""); // // Get the attribute ID of this pref. QTSS_AttributeID theID = qtssIllegalAttrID; if(inPrefsObject != NULL) theID = QTSSModuleUtils::GetAttrID(inPrefsObject, inPrefName); char* theString = NULL; if(inPrefsObject != NULL) (void)QTSS_GetValueAsString(inPrefsObject, theID, 0, &theString); if (theString == NULL) theString = sEmpty.GetAsCString(); return theString; }
QTSS_Error RereadPrefs() { delete [] sRedis_IP; sRedis_IP = QTSSModuleUtils::GetStringAttribute(modulePrefs, "redis_ip", sDefaultRedis_IP_Addr); QTSSModuleUtils::GetAttribute(modulePrefs, "redis_port", qtssAttrDataTypeUInt16, &sRedisPort, &sDefaultRedisPort, sizeof(sRedisPort)); delete [] sRedisUser; sRedisUser = QTSSModuleUtils::GetStringAttribute(modulePrefs, "redis_user", sDefaultRedisUser); delete [] sRedisPassword; sRedisPassword = QTSSModuleUtils::GetStringAttribute(modulePrefs, "redis_password", sDefaultRedisPassword); //get EasyDarwin ip and port delete [] sEasyDarwinIP; (void)QTSS_GetValueAsString(sServerPrefs, qtssPrefsEasyDarWinIP, 0, &sEasyDarwinIP); UInt32 len = sizeof(SInt32); (void) QTSS_GetValue(sServerPrefs, qtssPrefsEasyDarWinPort, 0, (void*)&sEasyDarwinPort, &len); return QTSS_NoErr; }
static Bool16 CallAuthorizeSession(QTSS_ClientSessionObject* theClientSession, QTSS_RTSPSessionObject* theRTSPSession, QTSS_RTSPRequestObject* theRTSPRequest, char* username, char* password) { qtss_printf("QTSSIcecastAuthModule::CallAuthorizeSession called\n"); //{ :action => "listener_add", :server => "server", :port => "8000", :client => "sessionidone", // :mount => "somemount.sdp", :user => "lstoll", :pass => @working_hash, :ip => "127.0.0.1", :agent => "RSPEC"} // generate the client session id (and save in client) format <start time millis>-<rtsp session id> char ice_sessid[128]; QTSS_TimeVal clientSessCreateTime = NULL; UInt32 createTimeLen = sizeof (clientSessCreateTime); QTSS_GetValue(*theClientSession, qtssCliSesCreateTimeInMsec, 0, (void*) & clientSessCreateTime, &createTimeLen); char* qtssRTSPSesIDString = NULL; (void) QTSS_GetValueAsString(*theRTSPSession, qtssRTSPSesID, 0, &qtssRTSPSesIDString); sprintf(ice_sessid, "%lld-%s", clientSessCreateTime, qtssRTSPSesIDString); printf("QTSSIcecastAuthModule::CallAuthorizeSession generated session id: %s\n", ice_sessid); (void) QTSS_SetValue(*theClientSession, attrClientSessionFullSessionID, 0, &ice_sessid, sizeof (ice_sessid)); // get the user agent char* userAgentString = NULL; (void) QTSS_GetValueAsString(*theClientSession, qtssCliSesFirstUserAgent, 0, &userAgentString); printf("QTSSIcecastAuthModule::CallAuthorizeSession: request user agent: %s\n", userAgentString); // get the client IP address char remoteAddress[20] = {0}; StrPtrLen theClientIPAddressStr(remoteAddress,sizeof(remoteAddress)); (void)QTSS_GetValue(*theRTSPSession, qtssRTSPSesRemoteAddrStr, 0, (void*)theClientIPAddressStr.Ptr, &theClientIPAddressStr.Len); // get the mount point char mountPoint[128] = {0}; StrPtrLen mountPointStr(mountPoint,sizeof(mountPoint)); (void)QTSS_GetValue(*theRTSPRequest, qtssRTSPReqURI, 0, (void*)mountPointStr.Ptr, &mountPointStr.Len); printf("QTSSIcecastAuthModule::CallAuthorizeSession: mount point: %s\n", mountPoint); // and set it in the client for use on session end (void) QTSS_SetValue(*theClientSession, attrClientSessionMountPoint, 0, mountPointStr.Ptr, mountPointStr.Len); char postdata[512]; qtss_sprintf(postdata, "action=listener_add&server=%s&port=554&client=%s&mount=%s&user=%s&pass=%s&ip=%s&agent%s", hostname, ice_sessid, mountPoint, username, password, remoteAddress, userAgentString); printf("QTSSIcecastAuthModule::CallAuthorizeSession: generated postdata: %s\n", postdata); printf("QTSSIcecastAuthModule::CallAuthorizeSession: i would post this to: %s\n", sStartSessionEndpoint); return true; // // CURL *easyhandle = NULL; // easyhandle = curl_easy_init(); // CURLcode curl_code; // // // curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, postdata); // curl_easy_setopt(easyhandle, CURLOPT_URL, "http://posthere.com/"); // curl_easy_perform(easyhandle); /* post away! */ // // long http_code = 0; // curl_easy_getinfo(easyhandle, CURLINFO_HTTP_CODE, &http_code); // if (http_code == 200 && curl_code != CURLE_ABORTED_BY_CALLBACK) { // // the call to the remote server was OK. pass. // return true; // } else { // return false; // } // return false; }
QTSS_Error AuthenticateRTSPRequest(QTSS_RTSPAuth_Params* inParams) { OSMutexLocker locker(sAuthMutex); QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; QTSS_AuthScheme authScheme = qtssAuthNone; debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest start\n"); if ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) ) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest inParams NULL\n"); return QTSS_RequestFailed; } // Get the user profile object from the request object QTSS_UserProfileObject theUserProfile = NULL; UInt32 len = sizeof(QTSS_UserProfileObject); QTSS_Error theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqUserProfile, 0, (void*)&theUserProfile, &len); Assert(len == sizeof(QTSS_UserProfileObject)); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username error is %"_S32BITARG_"\n", theErr); return theErr; } char* nameBuff = NULL; theErr = QTSS_GetValueAsString(theUserProfile, qtssUserName, 0, &nameBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username is %s\n", nameBuff); OSCharArrayDeleter usernameBufDeleter(nameBuff); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - theUserProfile nameBuff error is %"_S32BITARG_"\n", theErr); } len = sizeof(authScheme); theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqAuthScheme, 0, (void*)&authScheme, &len); if (theErr != QTSS_NoErr) return theErr; DSAccessChecker accessChecker; Bool16 allowed = true; Bool16 foundUser = true; Bool16 authHandled = true; if ( authScheme == qtssAuthDigest) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - authScheme = qtssAuthDigest\n"); char* challengeBuff = NULL; (void) QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqDigestChallenge, 0, &challengeBuff); OSCharArrayDeleter challengeDeleter(challengeBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - Server Challenge =%s\n",challengeBuff); char* responseBuff = NULL; (void) QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqDigestResponse, 0, &responseBuff); OSCharArrayDeleter responseDeleter(responseBuff); char* methodBuff = NULL; (void) QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqMethodStr, 0, &methodBuff); OSCharArrayDeleter methodDeleter(methodBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - Server Method =%s\n",methodBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username is %s challenge=%s response=%s method=%s\n", nameBuff, challengeBuff, responseBuff, methodBuff); if ( false == accessChecker.CheckDigest(nameBuff, challengeBuff, responseBuff, methodBuff) ) { debug_printf("QTSSDSAuthModule CheckDigest returned false\n"); } else { debug_printf("QTSSDSAuthModule CheckDigest returned true\n"); (void) QTSSModuleUtils::AuthorizeRequest(theRTSPRequest,&allowed,&foundUser,&authHandled); } } if ( authScheme == qtssAuthBasic) { debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - authScheme = qtssAuthBasic\n"); char passwordBuff[kBuffLen]; StrPtrLen passwordStr(passwordBuff, kBuffLen -1); char nameBuff[kBuffLen]; StrPtrLen nameStr(nameBuff, kBuffLen -1); theErr = QTSS_GetValue (inParams->inRTSPRequest,qtssRTSPReqUserName,0, (void *) nameStr.Ptr, &nameStr.Len); if ( (QTSS_NoErr != theErr) || (nameStr.Len >= kBuffLen) ) { debug_printf("QTSSDSAuthModule:AuthenticateRequest() Username Error - %"_S32BITARG_"\n", theErr); return false; } theErr = QTSS_GetValue (inParams->inRTSPRequest,qtssRTSPReqUserPassword,0, (void *) passwordStr.Ptr, &passwordStr.Len); if ( (QTSS_NoErr != theErr) || (passwordStr.Len >= kBuffLen) ) { debug_printf("QTSSDSAuthModule:AuthenticateRequest() Password Error - %"_S32BITARG_"\n", theErr); } nameBuff[nameStr.Len] = '\0'; passwordBuff[passwordStr.Len] = '\0'; debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - username is %s\n", nameBuff); debug_printf("QTSSDSAuthModule:AuthenticateRTSPRequest - password is %s\n", passwordBuff); if ( !accessChecker.CheckPassword(nameBuff, passwordBuff) ) { debug_printf("QTSSDSAuthModule CheckPassword returned false\n"); } else { debug_printf("QTSSDSAuthModule CheckPassword returned true\n"); (void) QTSSModuleUtils::AuthorizeRequest(theRTSPRequest,&allowed,&foundUser,&authHandled); } } return QTSS_NoErr; }
/* * This method is used to capture the full session ID details, and to reject the session. * The username and password from the query string can't be grabbed here, we need to * do that in the Filter. This is called AFTER Filter */ QTSS_Error RTSPPreProcess(QTSS_StandardRTSP_Params* inParams) { QTSS_Error theErr = QTSS_NoErr; QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; QTSS_RTSPSessionObject theRTSPSession = inParams->inRTSPSession; QTSS_RTSPHeaderObject theRTSPHeader = inParams->inRTSPHeaders; QTSS_ClientSessionObject theClientSession = inParams->inClientSession; Bool16 sessionValid = false; // see if the method is bypassable. if it is, skip processing qtss_printf("QTSSIcecastAuthModule::RTSPPreProcess: about to check if the method is bypassable\n"); if (IsRequestMethodBypassable(&theRTSPRequest)) return QTSS_NoErr; // see if the client is in the bypass list. if they are, skip all processing if (IsClientInBypassList(&theRTSPSession)) return QTSS_NoErr; // check to see if the session is already auth'd. If it is, skip processing if (IsRTSPSessionAuthenticated(&theRTSPSession)) { printf("QTSSIcecastAuthModule::RTSPPreProcess RTSP session is authenticated, do nothing.\n"); return QTSS_NoErr; // we are authenticated, don't do anything } char* providedUsername = NULL; (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedUsername, 0, &providedUsername); printf("QTSSIcecastAuthModule::RTSPPreProcess: Provided username extracted from session: %s\n", providedUsername); char* providedPassword = NULL; (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedPassword, 0, &providedPassword); printf("QTSSIcecastAuthModule::RTSPPreProcess: Provided password extracted from session: %s\n", providedPassword); // check to see if the username and password have been provided. If they are, process. if not // do nothing, we will default to an invalid session if (providedUsername != NULL && providedPassword != NULL) { printf("QTSSIcecastAuthModule::RTSPPreProcess: about to call authorize session\n"); // if we get to this point we have credentials that need to be validated, so validate them. sessionValid = CallAuthorizeSession(&theClientSession, &theRTSPSession, &theRTSPRequest, providedUsername, providedPassword); // request, qtssRTSPReqFilePath - the mount point (?) // request, qtssRTSPReqURI - the request URI (query params parsed from here?) // request, qtssRTSPReqAbsoluteURL - the request url with RTSP. // request, qtssRTSPReqFullRequest - the full request // session, qtssRTSPSesID - the session id // note - QTSS_GetValueAsString is the least efficent method - should move to one of the more efficent methods. // // char* qtssRTSPReqFilePathString = NULL; // (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqFilePath, 0, &qtssRTSPReqFilePathString); // printf("QTSSIcecastAuthModule::RTSPPreProcess: request qtssRTSPReqFilePath: %s\n", qtssRTSPReqFilePathString); // // char* qtssRTSPReqURIString = NULL; // (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqURI, 0, &qtssRTSPReqURIString); // printf("QTSSIcecastAuthModule::RTSPPreProcess: request qtssRTSPReqURI: %s\n", qtssRTSPReqURIString); // // char* qtssRTSPReqAbsoluteURLString = NULL; // (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqAbsoluteURL, 0, &qtssRTSPReqAbsoluteURLString); // printf("QTSSIcecastAuthModule::RTSPPreProcess: request qtssRTSPReqAbsoluteURL: %s\n", qtssRTSPReqAbsoluteURLString); // //QTSS_Delete(qtssRTSPReqFilePathString); // QTSS_Delete(qtssRTSPReqURIString); // //QTSS_Delete(qtssRTSPReqAbsoluteURLString); // QTSS_Delete(qtssRTSPSesIDString); } else { printf("QTSSIcecastAuthModule::RTSPPreProcess: username and/or password are NULL\n"); } // set the auth status on the RTSP session (void)QTSS_SetValue(theRTSPSession, attrRtspSessionAuthenticated, 0, &sessionValid, sizeof(sessionValid)); if (sessionValid) { // valid session, return return QTSS_NoErr; } else { // not a valid session, error char* accessDeniedMessage = "Access DENIED"; StrPtrLen accessDeniedMessageStr(accessDeniedMessage,sizeof(accessDeniedMessage)); (void)QTSSModuleUtils::SendErrorResponseWithMessage(theRTSPRequest, qtssClientForbidden, &accessDeniedMessageStr); return QTSS_NoErr; } }
/* * This method is called because it is the only one that gets the full URL params, to capture * the username and password. We don't have access to the client session here, so save * the user and pass in the session for later. This is called BEFORE PostProcess */ QTSS_Error RTSPFilter(QTSS_StandardRTSP_Params* inParams) { QTSS_Error theErr = QTSS_NoErr; QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; QTSS_RTSPSessionObject theRTSPSession = inParams->inRTSPSession; // FAIL - can't do this here. need to finally move the auth to preprocess, and use this // just for param capture. // On the flip site, it seems that everything is really early here - if query params // don't work, can embed them in the URL path, extract here, and rewrite the URL in the request // and it should work fine. this could be handy if proxy's become an issue, because each request // would have a unique path. // // see if the method is bypassable. if it is, skip processing // qtss_printf("QTSSIcecastAuthModule::RTSPFilter: about to check if the method is bypassable\n"); // if (IsRequestMethodBypassable(&theRTSPRequest)) return QTSS_NoErr; // see if the client is in the bypass list. if they are, skip all processing if (IsClientInBypassList(&theRTSPSession)) return QTSS_NoErr; // check to see if the session is already auth'd. If it is, skip processing if (IsRTSPSessionAuthenticated(&theRTSPSession)) { printf("QTSSIcecastAuthModule::RTSPFilter RTSP session is authenticated, do nothing.\n"); return QTSS_NoErr; // we are authenticated, don't do anything } char* qtssRTSPSesIDString = NULL; (void) QTSS_GetValueAsString(theRTSPSession, qtssRTSPSesID, 0, &qtssRTSPSesIDString); printf("QTSSIcecastAuthModule::RTSPFilter session qtssRTSPSesID: %s\n", qtssRTSPSesIDString); char* qtssRTSPReqFullRequestString = NULL; (void)QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqFullRequest, 0, &qtssRTSPReqFullRequestString); qtss_printf("QTSSIcecastAuthModule::RTSPFilter: request qtssRTSPReqFullRequest: %s\n", qtssRTSPReqFullRequestString); /* will want to modify this for proper tokenization, but it works for now */ char username[255]; bool usernameset = false; char password[255]; bool passwordset = false; Bool16 requiredAuthParametersProvided = false; if(index(qtssRTSPReqFullRequestString, '?')){ char buf[512]; snprintf(buf, 512, qtssRTSPReqFullRequestString); char* queryString; char* progress1; // split off everything after the first line, we don't need it. queryString = ::strtok_r(buf, "\n", &progress1); // split around the ?, ignore the first part ::strtok_r(buf, "?", &progress1); // get the second part of the previous split queryString = ::strtok_r(NULL, "?", &progress1); // split working around the space queryString = ::strtok_r(queryString, " ", &progress1); //printf("queryString: %s\n", queryString); // we should now have our url char* tmp = strtok(queryString, "=&"); int iters; for (iters=0; (tmp != NULL); iters++) { char name[255]; // I'm asking for a buffer overflow, aren't I? TODO - check this. if ((iters % 2) != 1) { // even - its a name. this will always be 'first' strcpy(name, tmp); //printf("name: %s\n", tmp); } else { // non-even, its a value. this will always come second //printf("value: %s\n", tmp); if (strcmp(name, "u") == 0) { // this value is the username //printf("name is currently: %s. username being set to %s\n", name, tmp); strcpy(username, tmp); usernameset = true; } else if (strcmp(name, "p") == 0) { // this value is the username //printf("name is currently: %s. password being set to %s\n", name, tmp); strcpy(password, tmp); passwordset = true; } } tmp = strtok(NULL, "=&"); } //printf("username: %s, password: %s\n\n", username, password); if (usernameset && passwordset) { printf("QTSSIcecastAuthModule::RTSPFilter username and password have been provided.\n"); requiredAuthParametersProvided = true; } } if (requiredAuthParametersProvided) { // we have a username and password. set them on the RTSP session, so they can be validated later. QTSS_Error setErr = QTSS_SetValue(theRTSPSession, attrRtspSessionProvidedUsername, 0, &username, sizeof(username)); QTSS_SetValue(theRTSPSession, attrRtspSessionProvidedPassword, 0, &password, sizeof(password)); PrintQTSSError("QTSSIcecastAuthModule::RTSPFilter", "after username set", setErr); char* providedUsername = NULL; (void)QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedUsername, 0, &providedUsername); printf("QTSSIcecastAuthModule::RTSPFilter: Provided username extracted from session right after set: %s\n", providedUsername); char* providedPassword = NULL; (void) QTSS_GetValueAsString(theRTSPSession, attrRtspSessionProvidedPassword, 0, &providedPassword); printf("QTSSIcecastAuthModule::RTSPFilter: Provided password extracted from session right after set: %s\n", providedPassword); } else { // WRONG. username and password weren't provided, do nothing - we will handle later. } // TODO - we should be cleaning up more things here, I think. QTSS_Delete(qtssRTSPReqFullRequestString); return QTSS_NoErr; }
QTSS_Error Authorize(QTSS_StandardRTSP_Params* inParams) { OSMutexLocker locker(sAuthMutex); QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; if ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) ) { debug_printf("QTSSDSAuthModule - Authorize inParams: Error"); return QTSS_RequestFailed; } //get the local file path char* pathBuffStr = NULL; QTSS_Error theErr = QTSS_GetValueAsString(theRTSPRequest, qtssRTSPReqLocalPath, 0, &pathBuffStr); QTSSCharArrayDeleter pathBuffDeleter(pathBuffStr); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule - Authorize [QTSS_GetValueAsString]: Error %"_S32BITARG_"", theErr); return QTSS_RequestFailed; } //get the root movie directory char* movieRootDirStr = NULL; theErr = QTSS_GetValueAsString(theRTSPRequest,qtssRTSPReqRootDir, 0, &movieRootDirStr); OSCharArrayDeleter movieRootDeleter(movieRootDirStr); if (theErr != QTSS_NoErr) { debug_printf("QTSSDSAuthModule - Authorize[QTSS_GetValueAsString]: Error %"_S32BITARG_"", theErr); return false; } //check if this user is allowed to see this movie DSAccessFile accessFile; Bool16 allowNoAccessFiles = sAllowGuestDefaultEnabled; //no access files allowed means allowing guest access (unknown users) Bool16 allowAnyUser = false; QTSS_ActionFlags noAction = ~qtssActionFlagsRead; //only handle read QTSS_ActionFlags authorizeAction = QTSSModuleUtils::GetRequestActions(theRTSPRequest); Bool16 authorized =false; Bool16 saclUser = false; char *name = NULL; (void) QTSS_GetValueAsString (theRTSPRequest,qtssRTSPReqUserName,0, &name); OSCharArrayDeleter nameDeleter(name); if (sAllowGuestDefaultEnabled) // if guest access is on, sacls are ignored. { authorized = true; } else { int result = check_sacl(name); switch (result) { case kSACLAuthorized: authorized = true; break; case kSACLUnknownUser: authorized = false; //set this to true to allow file based and other non-directory service users access, when SACLs are enabled in the system for QTSS. break; case kSACLNotAuthorized: authorized = false; break; case kSACLAnyUser: authorized = true; break; default: authorized = false; } debug_printf("QTSSDSAuthModule:Authorize sacl_check result=%d for %s authorized = %d\n",result, name, authorized); if (false == authorized) saclUser = true; } Bool16 foundUser = false; Bool16 passwordOK = false; //::AuthenticateRequest(inParams, pathBuffStr, movieRootDirStr, &sRealmNameStr, &foundUser); if (authorized) //have to be authorized by sacls or guest first before qtaccess file checks can allow or disallow. { theErr = accessFile.AuthorizeRequest(inParams,allowNoAccessFiles, noAction, authorizeAction,&authorized, &allowAnyUser); debug_printf("QTSSDSAuthModule:Authorize AuthorizeRequest() returned authorized=%d allowAnyUser=%d\n", authorized, allowAnyUser); } debug_printf("QTSSDSAuthModule:Authorize AuthenticateRequest() returned passwordOK=%d foundUser=%d authorized=%d allowAnyUser=%d\n", passwordOK ,foundUser, authorized,allowAnyUser); Bool16 allowRequest = authorized; Bool16 authHandled = true; if(!(authorizeAction & qtssActionFlagsRead)) //not for us { debug_printf("QTSSDSAuthModule:Authorize(qtssActionFlagsRead) not handled do nothing.\n"); } else if (allowRequest) { debug_printf("QTSSDSAuthModule:Authorize() succeeded.\n"); theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &foundUser, &authHandled); debug_printf("QTSSDSAuthModule:Authorize allowRequest=%d founduser=%d authHandled=%d\n", allowRequest, foundUser, authHandled); } else //request denied { debug_printf("QTSSDSAuthModule:Authorize() failed.\n"); foundUser = saclUser; authHandled = true; theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &foundUser, &authHandled); debug_printf("QTSSDSAuthModule:Authorize allowRequest=%d founduser=%d authHandled=%d saclUser=%d\n", allowRequest, foundUser, authHandled,saclUser); } return theErr; }
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; }
void LogStatus(QTSS_ServerState theServerState) { static QTSS_ServerState lastServerState = 0; static char *sPLISTHeader[] = { "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", #if __MacOSX__ "<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">", #else "<!ENTITY % plistObject \"(array | data | date | dict | real | integer | string | true | false )\">", "<!ELEMENT plist %plistObject;>", "<!ATTLIST plist version CDATA \"0.9\">", "", "<!-- Collections -->", "<!ELEMENT array (%plistObject;)*>", "<!ELEMENT dict (key, %plistObject;)*>", "<!ELEMENT key (#PCDATA)>", "", "<!--- Primitive types -->", "<!ELEMENT string (#PCDATA)>", "<!ELEMENT data (#PCDATA)> <!-- Contents interpreted as Base-64 encoded -->", "<!ELEMENT date (#PCDATA)> <!-- Contents should conform to a subset of ISO 8601 (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'. Smaller units may be omitted with a loss of precision) -->", "", "<!-- Numerical primitives -->", "<!ELEMENT true EMPTY> <!-- Boolean constant true -->", "<!ELEMENT false EMPTY> <!-- Boolean constant false -->", "<!ELEMENT real (#PCDATA)> <!-- Contents should represent a floating point number matching (\"+\" | \"-\")? d+ (\".\"d*)? (\"E\" (\"+\" | \"-\") d+)? where d is a digit 0-9. -->", "<!ELEMENT integer (#PCDATA)> <!-- Contents should represent a (possibly signed) integer number in base 10 -->", "]>", #endif }; static int numHeaderLines = sizeof(sPLISTHeader) / sizeof(char*); static char* sPlistStart = "<plist version=\"0.9\">"; static char* sPlistEnd = "</plist>"; static char* sDictStart = "<dict>"; static char* sDictEnd = "</dict>"; static char* sKey = " <key>%s</key>\n"; static char* sValue = " <string>%s</string>\n"; static char *sAttributes[] = { "qtssSvrServerName", "qtssSvrServerVersion", "qtssSvrServerBuild", "qtssSvrServerPlatform", "qtssSvrRTSPServerComment", "qtssSvrServerBuildDate", "qtssSvrStartupTime", "qtssSvrCurrentTimeMilliseconds", "qtssSvrCPULoadPercent", "qtssSvrState", "qtssRTPSvrCurConn", "qtssRTSPCurrentSessionCount", "qtssRTSPHTTPCurrentSessionCount", "qtssRTPSvrCurBandwidth", "qtssRTPSvrCurPackets", "qtssRTPSvrTotalConn", "qtssRTPSvrTotalBytes", "qtssMP3SvrCurConn", "qtssMP3SvrTotalConn", "qtssMP3SvrCurBandwidth", "qtssMP3SvrTotalBytes" }; static int numAttributes = sizeof(sAttributes) / sizeof(char*); static StrPtrLen statsFileNameStr("server_status"); if (false == sServer->GetPrefs()->ServerStatFileEnabled()) return; UInt32 interval = sServer->GetPrefs()->GetStatFileIntervalSec(); if (interval == 0 || (OS::UnixTime_Secs() % interval) > 0 ) return; // If the total number of RTSP sessions is 0 then we // might not need to update the "server_status" file. char* thePrefStr = NULL; // We start lastRTSPSessionCount off with an impossible value so that // we force the "server_status" file to be written at least once. static int lastRTSPSessionCount = -1; // Get the RTSP session count from the server. (void)QTSS_GetValueAsString(sServer, qtssRTSPCurrentSessionCount, 0, &thePrefStr); int currentRTSPSessionCount = ::atoi(thePrefStr); delete [] thePrefStr; thePrefStr = NULL; if (currentRTSPSessionCount == 0 && currentRTSPSessionCount == lastRTSPSessionCount) { // we don't need to update the "server_status" file except the // first time we are in the idle state. if (theServerState == qtssIdleState && lastServerState == qtssIdleState) { lastRTSPSessionCount = currentRTSPSessionCount; lastServerState = theServerState; return; } } else { // save the RTSP session count for the next time we execute. lastRTSPSessionCount = currentRTSPSessionCount; } StrPtrLenDel pathStr(sServer->GetPrefs()->GetErrorLogDir()); StrPtrLenDel fileNameStr(sServer->GetPrefs()->GetStatsMonitorFileName()); ResizeableStringFormatter pathBuffer(NULL,0); pathBuffer.PutFilePath(&pathStr,&fileNameStr); pathBuffer.PutTerminator(); char* filePath = pathBuffer.GetBufPtr(); FILE* statusFile = ::fopen(filePath, "w"); char* theAttributeValue = NULL; int i; if (statusFile != NULL) { ::chmod(filePath, 0640); for ( i = 0; i < numHeaderLines; i++) { qtss_fprintf(statusFile, "%s\n",sPLISTHeader[i]); } qtss_fprintf(statusFile, "%s\n", sPlistStart); qtss_fprintf(statusFile, "%s\n", sDictStart); // show each element value for ( i = 0; i < numAttributes; i++) { (void)QTSS_GetValueAsString(sServer, QTSSModuleUtils::GetAttrID(sServer,sAttributes[i]), 0, &theAttributeValue); if (theAttributeValue != NULL) { qtss_fprintf(statusFile, sKey, sAttributes[i]); qtss_fprintf(statusFile, sValue, theAttributeValue); delete [] theAttributeValue; theAttributeValue = NULL; } } qtss_fprintf(statusFile, "%s\n", sDictEnd); qtss_fprintf(statusFile, "%s\n\n", sPlistEnd); ::fclose(statusFile); } lastServerState = theServerState; }
QTSS_Error Preprocess(QTSS_StandardRTSP_Params* inParams) { static UInt32 sFileBufSize = 32768; static UInt32 sInitialState = kReadingBufferState; static UInt32 sZero = 0; UInt32 theLen = 0; UInt32* theStateP = NULL; QTSS_Error theErr = QTSS_NoErr; QTSS_Object theFile = NULL; (void)QTSS_GetValuePtr(inParams->inRTSPSession, sStateAttr, 0, (void**)&theStateP, &theLen); if ((theStateP == NULL) || (theLen != sizeof(UInt32))) { // Initial state. We haven't started sending the file yet, so // check to see if this is our request, and if it is, set everything up. // Only operate if this is a DESCRIBE QTSS_RTSPMethod* theMethod = NULL; UInt32 theLen = 0; if ((QTSS_GetValuePtr(inParams->inRTSPRequest, qtssRTSPReqMethod, 0, (void**)&theMethod, &theLen) != QTSS_NoErr) || (theLen != sizeof(QTSS_RTSPMethod))) { Assert(0); return QTSS_RequestFailed; } if (*theMethod != qtssDescribeMethod) return QTSS_RequestFailed; // Check to see if this is a raw file request char* theFilePath = NULL; (void)QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqLocalPath, 0, &theFilePath); QTSSCharArrayDeleter theFilePathDeleter(theFilePath); theLen = ::strlen(theFilePath); // Copy the full path, and append a ".raw" OSCharArrayDeleter rawPath(NEW char[theLen + sRawSuffix.Len + 4]); ::memcpy(rawPath.GetObject(), theFilePath, theLen); ::strcpy(rawPath.GetObject() + theLen, sRawSuffix.Ptr); #if RAWFILE_FILE_ASYNC theErr = QTSS_OpenFileObject(rawPath.GetObject(), qtssOpenFileAsync, &theFile); #else theErr = QTSS_OpenFileObject(rawPath.GetObject(), qtssOpenFileAsync, &theFile); #endif // If the file doesn't exist, and if this is a path with a '.raw' at the end, // check to see if the path without the extra .raw exists if (theErr != QTSS_NoErr) { theFile = NULL; rawPath.GetObject()[theLen] = '\0'; if (theLen > sRawSuffix.Len) { StrPtrLen comparer((theFilePath + theLen) - sRawSuffix.Len, sRawSuffix.Len); if (comparer.Equal(sRawSuffix)) { #if RAWFILE_FILE_ASYNC theErr = QTSS_OpenFileObject(rawPath.GetObject(), qtssOpenFileAsync, &theFile); #else theErr = QTSS_OpenFileObject(rawPath.GetObject(), kOpenFileNoFlags, &theFile); #endif } } } // If the file doesn't exist, we should probably return a 404 not found. if (theErr != QTSS_NoErr) return QTSS_RequestFailed; // 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 static Bool16 sFalse = false; (void)QTSS_SetValue(inParams->inRTSPRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse)); // We have a real file. Setup all the dictionary values we need (void)QTSS_SetValue(inParams->inRTSPSession, sFileAttr, 0, &theFile, sizeof(theFile)); // Create a buffer to store data. char* theFileBuffer = NEW char[sFileBufSize]; (void)QTSS_SetValue(inParams->inRTSPSession, sFileBufferAttr, 0, &theFileBuffer, sizeof(theFileBuffer)); // Store our initial state (void)QTSS_SetValue(inParams->inRTSPSession, sStateAttr, 0, &sInitialState, sizeof(sInitialState)); theStateP = &sInitialState; // so we can proceed normally (void)QTSS_SetValue(inParams->inRTSPSession, sReadOffsetAttr, 0, &sZero, sizeof(sZero)); (void)QTSS_SetValue(inParams->inRTSPSession, sWriteOffsetAttr, 0, &sZero, sizeof(sZero)); }
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); }
Bool16 Authenticate(QTSS_RTSPRequestObject request, StrPtrLen* namePtr, StrPtrLen* passwordPtr) { Bool16 authenticated = true; char* authName = namePtr->GetAsCString(); OSCharArrayDeleter authNameDeleter(authName); QTSS_ActionFlags authAction = qtssActionFlagsAdmin; // authenticate callback to retrieve the password QTSS_Error err = QTSS_Authenticate(authName, sAuthResourceLocalPath, sAuthResourceLocalPath, authAction, qtssAuthBasic, request); if (err != QTSS_NoErr) { return false; // Couldn't even call QTSS_Authenticate...abandon! } // Get the user profile object from the request object that was created in the authenticate callback QTSS_UserProfileObject theUserProfile = NULL; UInt32 len = sizeof(QTSS_UserProfileObject); err = QTSS_GetValue(request, qtssRTSPReqUserProfile, 0, (void*)&theUserProfile, &len); Assert(len == sizeof(QTSS_UserProfileObject)); if (err != QTSS_NoErr) authenticated = false; if(err == QTSS_NoErr) { char* reqPassword = passwordPtr->GetAsCString(); OSCharArrayDeleter reqPasswordDeleter(reqPassword); char* userPassword = NULL; (void) QTSS_GetValueAsString(theUserProfile, qtssUserPassword, 0, &userPassword); OSCharArrayDeleter userPasswordDeleter(userPassword); if(userPassword == NULL) { authenticated = false; } else { #ifdef __Win32__ // The password is md5 encoded for win32 char md5EncodeResult[120]; MD5Encode(reqPassword, userPassword, md5EncodeResult, sizeof(md5EncodeResult)); if(::strcmp(userPassword, md5EncodeResult) != 0) authenticated = false; #else if(::strcmp(userPassword, (char*)crypt(reqPassword, userPassword)) != 0) authenticated = false; #endif } } char* realm = NULL; Bool16 allowed = true; //authorize callback to check authorization // allocates memory for realm err = QTSS_Authorize(request, &realm, &allowed); // QTSS_Authorize allocates memory for the realm string // we don't use the realm returned by the callback, but instead // use our own. // delete the memory allocated for realm because we don't need it! OSCharArrayDeleter realmDeleter(realm); if(err != QTSS_NoErr) { qtss_printf("QTSSAdminModule::Authenticate: QTSS_Authorize failed\n"); return false; // Couldn't even call QTSS_Authorize...abandon! } if(authenticated && allowed) return true; return false; }
QTSS_Error DoDescribe(QTSS_StandardRTSP_Params* inParams) { //解析命令 char* theFullPathStr = NULL; QTSS_Error theErr = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileName, 0, &theFullPathStr); Assert(theErr == QTSS_NoErr); QTSSCharArrayDeleter theFullPathStrDeleter(theFullPathStr); if (theErr != QTSS_NoErr) return NULL; StrPtrLen theFullPath(theFullPathStr); if (theFullPath.Len != sRelaySuffix.Len ) return NULL; StrPtrLen endOfPath2(&theFullPath.Ptr[theFullPath.Len - sRelaySuffix.Len], sRelaySuffix.Len); if (!endOfPath2.Equal(sRelaySuffix)) { return NULL; } //解析查询字符串 char* theQueryStr = NULL; theErr = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqQueryString, 0, &theQueryStr); Assert(theErr == QTSS_NoErr); QTSSCharArrayDeleter theQueryStringDeleter(theQueryStr); if (theErr != QTSS_NoErr) return NULL; StrPtrLen theQueryString(theQueryStr); QueryParamList parList(theQueryStr); const char* sName = parList.DoFindCGIValueForParam(QUERY_STREAM_NAME); const char* sChannel = parList.DoFindCGIValueForParam(QUERY_STREAM_CHANNEL); if(sName == NULL && sChannel == NULL) { return NULL; } char szChannelURL[256] = {0,}; char szUsername[32] = {0,}; char szPassword[32] = {0,}; const char* sURL = NULL; char sPushServerAddr[256] = {0,}; if (NULL != sChannel) { //find channel info GetChannelInfoById( (char*)sChannel, szChannelURL, sizeof(szChannelURL), szUsername, sizeof(szUsername), szPassword, sizeof(szPassword), sPushServerAddr, sizeof(sPushServerAddr)); if ( (int)strlen(szChannelURL) < 1 ) return NULL; //not found the channel //sURL = "rtsp://192.168.1.186:8557"; sURL = szChannelURL; } else { sURL = parList.DoFindCGIValueForParam(QUERY_STREAM_URL); } //if(sURL == NULL) return NULL; const char* sCMD = parList.DoFindCGIValueForParam(QUERY_STREAM_CMD); bool bStop = false; if(sCMD) { if(::strcmp(sCMD,QUERY_STREAM_CMD_STOP) == 0) bStop = true; } StrPtrLen streamName(NULL!=sName?(char*)sName:(char*)sChannel); //从接口获取信息结构体 EasyRelaySession* session = NULL; //首先查找Map里面是否已经有了对应的流 OSRef* sessionRef = sRelaySessionMap->Resolve(&streamName); if(sessionRef != NULL) { session = (EasyRelaySession*)sessionRef->GetObject(); } else { if(bStop) return NULL; if(sURL == NULL) return NULL; session = NEW EasyRelaySession((char*)sURL, EasyRelaySession::kRTSPTCPClientType, NULL!=sName?(char*)sName:(char*)sChannel, sPushServerAddr); QTSS_Error theErr = session->RelaySessionStart(); if(theErr == QTSS_NoErr) { OS_Error theErr = sRelaySessionMap->Register(session->GetRef()); Assert(theErr == QTSS_NoErr); } else { session->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientNotFound, 0); } //增加一次对RelaySession的无效引用,后面会统一释放 OSRef* debug = sRelaySessionMap->Resolve(&streamName); Assert(debug == session->GetRef()); } sRelaySessionMap->Release(session->GetRef()); if(bStop) { sRelaySessionMap->UnRegister(session->GetRef()); session->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssSuccessOK, 0); } QTSS_RTSPStatusCode statusCode = qtssRedirectPermMoved; QTSS_SetValue(inParams->inRTSPRequest, qtssRTSPReqStatusCode, 0, &statusCode, sizeof(statusCode)); // Get the ip addr out of the prefs dictionary UInt16 thePort = 554; UInt32 theLen = sizeof(UInt16); theErr = QTSServerInterface::GetServer()->GetPrefs()->GetValue(qtssPrefsRTSPPorts, 0, &thePort, &theLen); Assert(theErr == QTSS_NoErr); //构造本地URL char url[QTSS_MAX_URL_LENGTH] = { 0 }; qtss_sprintf(url,"rtsp://%s:%d/%s.sdp", sLocal_IP_Addr, thePort, NULL!=sName?(char*)sName:(char*)sChannel); StrPtrLen locationRedirect(url); Bool16 sFalse = false; (void)QTSS_SetValue(inParams->inRTSPRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse)); QTSS_AppendRTSPHeader(inParams->inRTSPRequest, qtssLocationHeader, locationRedirect.Ptr, locationRedirect.Len); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssRedirectPermMoved, 0); }
QTSS_Error QTAccessFile::AuthorizeRequest(QTSS_StandardRTSP_Params* inParams, Bool16 allowNoAccessFiles, QTSS_ActionFlags noAction, QTSS_ActionFlags authorizeAction, Bool16 *outAuthorizedPtr, Bool16 *outAllowAnyUserPtr) { if ( (NULL == inParams) || (NULL == inParams->inRTSPRequest) || (NULL == outAllowAnyUserPtr) || (NULL == outAuthorizedPtr) ) return QTSS_RequestFailed; *outAllowAnyUserPtr = false; *outAuthorizedPtr = false; QTSS_RTSPRequestObject theRTSPRequest = inParams->inRTSPRequest; // get the type of request // Don't touch write requests QTSS_ActionFlags action = QTSSModuleUtils::GetRequestActions(theRTSPRequest); if(action == qtssActionFlagsNoFlags) return QTSS_RequestFailed; if( (action & noAction) != 0) return QTSS_NoErr; // we don't handle //get the local file path char* pathBuffStr = QTSSModuleUtils::GetLocalPath_Copy(theRTSPRequest); OSCharArrayDeleter pathBuffDeleter(pathBuffStr); if (NULL == pathBuffStr) return QTSS_RequestFailed; //get the root movie directory char* movieRootDirStr = QTSSModuleUtils::GetMoviesRootDir_Copy(theRTSPRequest); OSCharArrayDeleter movieRootDeleter(movieRootDirStr); if (NULL == movieRootDirStr) return QTSS_RequestFailed; QTSS_UserProfileObject theUserProfile = QTSSModuleUtils::GetUserProfileObject(theRTSPRequest); if (NULL == theUserProfile) return QTSS_RequestFailed; char* accessFilePath = QTAccessFile::GetAccessFile_Copy(movieRootDirStr, pathBuffStr); OSCharArrayDeleter accessFilePathDeleter(accessFilePath); char* username = QTSSModuleUtils::GetUserName_Copy(theUserProfile); OSCharArrayDeleter usernameDeleter(username); UInt32 numGroups = 0; char** groupCharPtrArray = QTSSModuleUtils::GetGroupsArray_Copy(theUserProfile, &numGroups); OSCharPointerArrayDeleter groupCharPtrArrayDeleter(groupCharPtrArray); StrPtrLen accessFileBuf; (void)QTSSModuleUtils::ReadEntireFile(accessFilePath, &accessFileBuf); OSCharArrayDeleter accessFileBufDeleter(accessFileBuf.Ptr); if (accessFileBuf.Len == 0 && !allowNoAccessFiles) { accessFileBuf.Set(sAccessValidUser); if (DEBUG_QTACCESS) qtss_printf("QTAccessFile::AuthorizeRequest SET Accessfile valid user for no accessfile %s\n", sAccessValidUser); } if (accessFileBuf.Len == 0 && allowNoAccessFiles) { accessFileBuf.Set(sAccessAnyUser); if (DEBUG_QTACCESS) qtss_printf("QTAccessFile::AuthorizeRequest SET Accessfile any user for no access file %s\n", sAccessAnyUser); } char realmName[kBuffLen] = { 0 }; StrPtrLen realmNameStr(realmName,kBuffLen -1); //check if this user is allowed to see this movie Bool16 allowRequest = this->AccessAllowed(username, groupCharPtrArray, numGroups, &accessFileBuf, authorizeAction,&realmNameStr, outAllowAnyUserPtr ); debug_printf("accessFile.AccessAllowed for user=%s returned %d\n", username, allowRequest); // Get the auth scheme QTSS_AuthScheme theAuthScheme = qtssAuthNone; UInt32 len = sizeof(theAuthScheme); QTSS_Error theErr = QTSS_GetValue(theRTSPRequest, qtssRTSPReqAuthScheme, 0, (void*)&theAuthScheme, &len); Assert(len == sizeof(theAuthScheme)); if(theErr != QTSS_NoErr) return theErr; // If auth scheme is basic and the realm is present in the access file, use it if((theAuthScheme == qtssAuthBasic) && (realmNameStr.Ptr[0] != '\0')) //set the realm if we have one (void) QTSS_SetValue(theRTSPRequest,qtssRTSPReqURLRealm, 0, realmNameStr.Ptr, ::strlen(realmNameStr.Ptr)); else // if auth scheme is basic and no realm is present, or if the auth scheme is digest, use the realm from the users file { char* userRealm = NULL; (void) QTSS_GetValueAsString(theUserProfile, qtssUserRealm, 0, &userRealm); if(userRealm != NULL) { OSCharArrayDeleter userRealmDeleter(userRealm); (void) QTSS_SetValue(theRTSPRequest,qtssRTSPReqURLRealm, 0, userRealm, ::strlen(userRealm)); } } *outAuthorizedPtr = allowRequest; Bool16 founduser = this->HaveUser(username, NULL); Bool16 authContinue = true; char nameBuff[256]; StrPtrLen reqNameStr(nameBuff, kBuffLen); StrPtrLen profileNameStr(username); theErr = QTSS_GetValue (theRTSPRequest,qtssRTSPReqUserName,0, (void *) reqNameStr.Ptr, &reqNameStr.Len); if (DEBUG_QTACCESS) { qtss_printf("QTAccessFile::AuthorizeRequest qtaccess profile user =%s ", username); reqNameStr.PrintStr("request user="******"\n"); qtss_printf("QTAccessFile::AuthorizeRequest allowRequest=%d founduser=%d authContinue=%d\n", allowRequest, founduser, authContinue); } if (allowRequest && founduser) theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &founduser,&authContinue); if (!allowRequest && !founduser) theErr = QTSSModuleUtils::AuthorizeRequest(theRTSPRequest, &allowRequest, &founduser,&authContinue); if (DEBUG_QTACCESS) { qtss_printf("QTAccessFile::AuthorizeRequest QTSSModuleUtils::AuthorizeRequest qtaccess profile user =%s ", username); reqNameStr.PrintStr("request user="******"\n"); qtss_printf("QTAccessFile::AuthorizeRequest allowRequest=%d founduser=%d authContinue=%d\n", allowRequest, founduser, authContinue); } return theErr; }
QTSS_Error DoDescribe(QTSS_StandardRTSP_Params* inParams) { char* theUriStr = NULL; QTSS_Error err = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileName, 0, &theUriStr); Assert(err == QTSS_NoErr); if(err != QTSS_NoErr) return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest, 0); QTSSCharArrayDeleter theUriStrDeleter(theUriStr); //从接口获取信息结构体 //TODO: DeviceInfo* pDeviceInfo = parseDevice->GetDeviceInfoByIdName(theUriStr); if(pDeviceInfo == NULL) { qtss_printf("ID:%s Not Found\n",theUriStr); return QTSS_RequestFailed; } //信息存在rtsp://59.46.115.84:8554/h264/ch1/sub/av_stream RTSPRelaySession* clientSes = NULL; //首先查找Map里面是否已经有了对应的流 StrPtrLen streamName(theUriStr); OSRef* clientSesRef = sClientSessionMap->Resolve(&streamName); if(clientSesRef != NULL) { clientSes = (RTSPRelaySession*)clientSesRef->GetObject(); } else { clientSes = NEW RTSPRelaySession( SocketUtils::ConvertStringToAddr(pDeviceInfo->m_szIP), pDeviceInfo->m_nPort, pDeviceInfo->m_szSourceUrl, 1, rtcpInterval, 0, theReadInterval, sockRcvBuf, speed, packetPlayHeader, overbufferwindowInK, sendOptions, pDeviceInfo->m_szUser, pDeviceInfo->m_szPassword, theUriStr); OS_Error theErr = clientSes->SendDescribe(); if(theErr == QTSS_NoErr) { OS_Error theErr = sClientSessionMap->Register(clientSes->GetRef()); Assert(theErr == QTSS_NoErr); } else { clientSes->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientNotFound, 0); } //增加一次对RelaySession的无效引用,后面会统一释放 OSRef* debug = sClientSessionMap->Resolve(&streamName); Assert(debug == clientSes->GetRef()); } ReflectorSession* theSession = SetupProxySession(inParams, clientSes); if (theSession == NULL) { sClientSessionMap->Release(clientSes->GetRef()); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssServerNotImplemented, 0); } QTSS_Error Err = QTSS_SetValue(inParams->inRTSPSession, sRTSPBroadcastSessionAttr, 0, &theSession, sizeof(theSession)); Assert(Err == QTSS_NoErr); clientSes->SetReflectorSession(theSession); theSession->SetRTSPRelaySession((void*)clientSes); sClientSessionMap->Release(clientSes->GetRef()); iovec theDescribeVec[3] = { {0 }}; Assert(theSession->GetLocalSDP()->Ptr != NULL); StrPtrLen theFileData; QTSS_TimeVal outModDate = 0; QTSS_TimeVal inModDate = -1; theFileData.Ptr = theSession->GetLocalSDP()->Ptr; theFileData.Len = theSession->GetLocalSDP()->Len; // -------------- process SDP to remove connection info and add track IDs, port info, and default c= line StrPtrLen theSDPData; SDPSourceInfo tempSDPSourceInfo(theFileData.Ptr, theFileData.Len); // will make a copy and delete in destructor theSDPData.Ptr = tempSDPSourceInfo.GetLocalSDP(&theSDPData.Len); // returns a new buffer with processed sdp OSCharArrayDeleter sdpDeleter(theSDPData.Ptr); // delete the temp sdp source info buffer returned by GetLocalSDP if (theSDPData.Len <= 0) // can't find it on disk or it failed to parse just use the one in the session. { theSDPData.Ptr = theSession->GetLocalSDP()->Ptr; // this sdp isn't ours it must not be deleted theSDPData.Len = theSession->GetLocalSDP()->Len; } // ------------ Clean up missing required SDP lines ResizeableStringFormatter editedSDP(NULL,0); DoDescribeAddRequiredSDPLines2(inParams, theSession, outModDate, &editedSDP, &theSDPData); StrPtrLen editedSDPSPL(editedSDP.GetBufPtr(),editedSDP.GetBytesWritten()); // ------------ Check the headers SDPContainer checkedSDPContainer; checkedSDPContainer.SetSDPBuffer( &editedSDPSPL ); if (!checkedSDPContainer.IsSDPBufferValid()) { return QTSSModuleUtils::SendErrorResponseWithMessage(inParams->inRTSPRequest, qtssUnsupportedMediaType, &sSDPNotValidMessage); } // ------------ Put SDP header lines in correct order Float32 adjustMediaBandwidthPercent = 1.0; Bool16 adjustMediaBandwidth = false; SDPLineSorter sortedSDP(&checkedSDPContainer,adjustMediaBandwidthPercent); // ------------ Write the SDP UInt32 sessLen = sortedSDP.GetSessionHeaders()->Len; UInt32 mediaLen = sortedSDP.GetMediaHeaders()->Len; theDescribeVec[1].iov_base = sortedSDP.GetSessionHeaders()->Ptr; theDescribeVec[1].iov_len = sortedSDP.GetSessionHeaders()->Len; theDescribeVec[2].iov_base = sortedSDP.GetMediaHeaders()->Ptr; theDescribeVec[2].iov_len = sortedSDP.GetMediaHeaders()->Len; (void)QTSS_AppendRTSPHeader(inParams->inRTSPRequest, qtssCacheControlHeader, kCacheControlHeader.Ptr, kCacheControlHeader.Len); QTSSModuleUtils::SendDescribeResponse(inParams->inRTSPRequest, inParams->inClientSession, &theDescribeVec[0], 3, sessLen + mediaLen ); return QTSS_NoErr; }
void DebugLevel_1(FILE* statusFile, FILE* stdOut, Bool16 printHeader ) { char* thePrefStr = NULL; static char numStr[12] =""; static char dateStr[25] =""; UInt32 theLen = 0; if ( printHeader ) { print_status(statusFile,stdOut,"%s", " RTP-Conns RTSP-Conns HTTP-Conns kBits/Sec Pkts/Sec RTP-Playing AvgDelay CurMaxDelay MaxDelay AvgQuality NumThinned Time\n"); } (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurConn, 0, &thePrefStr); print_status(statusFile, stdOut,"%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; (void)QTSS_GetValueAsString(sServer, qtssRTSPCurrentSessionCount, 0, &thePrefStr); print_status(statusFile, stdOut,"%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; (void)QTSS_GetValueAsString(sServer, qtssRTSPHTTPCurrentSessionCount, 0, &thePrefStr); print_status(statusFile, stdOut,"%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; UInt32 curBandwidth = 0; theLen = sizeof(curBandwidth); (void)QTSS_GetValue(sServer, qtssRTPSvrCurBandwidth, 0, &curBandwidth, &theLen); qtss_snprintf(numStr, 11, "%"_U32BITARG_"", curBandwidth/1024); print_status(statusFile, stdOut,"%11s", numStr); (void)QTSS_GetValueAsString(sServer, qtssRTPSvrCurPackets, 0, &thePrefStr); print_status(statusFile, stdOut,"%11s", thePrefStr); delete [] thePrefStr; thePrefStr = NULL; UInt32 currentPlaying = sServer->GetNumRTPPlayingSessions(); qtss_snprintf( numStr, sizeof(numStr) -1, "%"_U32BITARG_"", currentPlaying); print_status(statusFile, stdOut,"%14s", numStr); //is the server keeping up with the streams? //what quality are the streams? SInt64 totalRTPPaackets = sServer->GetTotalRTPPackets(); SInt64 deltaPackets = totalRTPPaackets - sLastDebugPackets; sLastDebugPackets = totalRTPPaackets; SInt64 totalQuality = sServer->GetTotalQuality(); SInt64 deltaQuality = totalQuality - sLastDebugTotalQuality; sLastDebugTotalQuality = totalQuality; SInt64 currentMaxLate = sServer->GetCurrentMaxLate(); SInt64 totalLate = sServer->GetTotalLate(); sServer->ClearTotalLate(); sServer->ClearCurrentMaxLate(); sServer->ClearTotalQuality(); ::qtss_snprintf(numStr, sizeof(numStr) -1, "%s", "0"); if (deltaPackets > 0) qtss_snprintf(numStr, sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) ((SInt64)totalLate / (SInt64) deltaPackets )); print_status(statusFile, stdOut,"%11s", numStr); qtss_snprintf(numStr,sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) currentMaxLate); print_status(statusFile, stdOut,"%11s", numStr); qtss_snprintf(numStr,sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) sServer->GetMaxLate() ); print_status(statusFile, stdOut,"%11s", numStr); ::qtss_snprintf(numStr, sizeof(numStr) -1, "%s", "0"); if (deltaPackets > 0) qtss_snprintf(numStr, sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) ((SInt64) deltaQuality / (SInt64) deltaPackets)); print_status(statusFile, stdOut,"%11s", numStr); qtss_snprintf(numStr,sizeof(numStr) -1, "%"_S32BITARG_"", (SInt32) sServer->GetNumThinned() ); print_status(statusFile, stdOut,"%11s", numStr); char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes]; (void) QTSSRollingLog::FormatDate(theDateBuffer, false); qtss_snprintf(dateStr,sizeof(dateStr) -1, "%s", theDateBuffer ); print_status(statusFile, stdOut,"%24s\n", dateStr); }
QTSS_Error DoSetup(QTSS_StandardRTSP_Params* inParams) { ReflectorSession* theSession = NULL; UInt32 len = sizeof(theSession); QTSS_GetValue(inParams->inRTSPSession, sRTSPBroadcastSessionAttr, 0, &theSession, &len); if(theSession == NULL) return QTSS_RequestFailed; Bool16 foundSession = false; UInt32 theLen = 0; RTPSessionOutput** theOutput = NULL; QTSS_Error theErr = QTSS_GetValuePtr(inParams->inClientSession, sOutputAttr, 0, (void**)&theOutput, &theLen); if (theLen != sizeof(RTPSessionOutput*)) { if (theErr != QTSS_NoErr) { RTPSessionOutput* theNewOutput = NEW RTPSessionOutput(inParams->inClientSession, theSession, sServerPrefs, sStreamCookieAttr ); theSession->AddOutput(theNewOutput,true); (void)QTSS_SetValue(inParams->inClientSession, sOutputAttr, 0, &theNewOutput, sizeof(theNewOutput)); } } //unless there is a digit at the end of this path (representing trackID), don't //even bother with the request char* theDigitStr = NULL; (void)QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileDigit, 0, &theDigitStr); QTSSCharArrayDeleter theDigitStrDeleter(theDigitStr); if (theDigitStr == NULL) { return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest,sExpectedDigitFilenameErr); } UInt32 theTrackID = ::strtol(theDigitStr, NULL, 10); // Get info about this trackID SourceInfo::StreamInfo* theStreamInfo = theSession->GetSourceInfo()->GetStreamInfoByTrackID(theTrackID); // If theStreamInfo is NULL, we don't have a legit track, so return an error if (theStreamInfo == NULL) return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest, sReflectorBadTrackIDErr); StrPtrLen* thePayloadName = &theStreamInfo->fPayloadName; QTSS_RTPPayloadType thePayloadType = theStreamInfo->fPayloadType; StringParser parser(thePayloadName); parser.GetThru(NULL, '/'); theStreamInfo->fTimeScale = parser.ConsumeInteger(NULL); if (theStreamInfo->fTimeScale == 0) theStreamInfo->fTimeScale = 90000; QTSS_RTPStreamObject newStream = NULL; { // Ok, this is completely crazy but I can't think of a better way to do this that's // safe so we'll do it this way for now. Because the ReflectorStreams use this session's // stream queue, we need to make sure that each ReflectorStream is not reflecting to this // session while we call QTSS_AddRTPStream. One brutal way to do this is to grab each // ReflectorStream's mutex, which will stop every reflector stream from running. for (UInt32 x = 0; x < theSession->GetNumStreams(); x++) theSession->GetStreamByIndex(x)->GetMutex()->Lock(); theErr = QTSS_AddRTPStream(inParams->inClientSession, inParams->inRTSPRequest, &newStream, 0); for (UInt32 y = 0; y < theSession->GetNumStreams(); y++) theSession->GetStreamByIndex(y)->GetMutex()->Unlock(); if (theErr != QTSS_NoErr) return theErr; } // Set up dictionary items for this stream theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadName, 0, thePayloadName->Ptr, thePayloadName->Len); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadType, 0, &thePayloadType, sizeof(thePayloadType)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTrackID, 0, &theTrackID, sizeof(theTrackID)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTimescale, 0, &theStreamInfo->fTimeScale, sizeof(theStreamInfo->fTimeScale)); Assert(theErr == QTSS_NoErr); // We only want to allow over buffering to dynamic rate clients SInt32 canDynamicRate = -1; theLen = sizeof(canDynamicRate); (void) QTSS_GetValue(inParams->inRTSPRequest, qtssRTSPReqDynamicRateState, 0, (void*) &canDynamicRate, &theLen); if (canDynamicRate < 1) // -1 no rate field, 0 off (void)QTSS_SetValue(inParams->inClientSession, qtssCliSesOverBufferEnabled, 0, &sFalse, sizeof(sFalse)); // Place the stream cookie in this stream for future reference void* theStreamCookie = theSession->GetStreamCookie(theTrackID); Assert(theStreamCookie != NULL); theErr = QTSS_SetValue(newStream, sStreamCookieAttr, 0, &theStreamCookie, sizeof(theStreamCookie)); Assert(theErr == QTSS_NoErr); // Set the number of quality levels. static UInt32 sNumQualityLevels = ReflectorSession::kNumQualityLevels; theErr = QTSS_SetValue(newStream, qtssRTPStrNumQualityLevels, 0, &sNumQualityLevels, sizeof(sNumQualityLevels)); Assert(theErr == QTSS_NoErr); //send the setup response (void)QTSS_AppendRTSPHeader(inParams->inRTSPRequest, qtssCacheControlHeader, kCacheControlHeader.Ptr, kCacheControlHeader.Len); (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, newStream, qtssSetupRespDontWriteSSRC); return QTSS_NoErr; }
// Handle the QTSS_RTSPFilter_Role role call back. QTSS_Error Filter(QTSS_Filter_Params* inParams) { QTSS_Error err = QTSS_NoErr; QTSS_RTSPRequestObject theRequest = inParams->inRTSPRequest; QTSS_RTSPSessionObject theSession = inParams->inRTSPSession; char theURL[512]; // If this module is disabled do nothing but return. if (!sRefMovieXferEnabled) return QTSS_NoErr; // Get the full RTSP request from the server's attribute. StrPtrLen theFullRequest; err = QTSS_GetValuePtr(theRequest, qtssRTSPReqFullRequest, 0, (void**)&theFullRequest.Ptr, &theFullRequest.Len); if (err != QTSS_NoErr) { return QTSS_NoErr; } // if this is not an HTTP GET then ignore it. if (!IsHTTPGet(theFullRequest)) return QTSS_NoErr; // If this is a tunneled RTSP request we ignore it. if (IsTunneledRTSP(theFullRequest)) { return QTSS_NoErr; } // if we can't parse out the URL then we just ignore this request. if (!ParseURL(theFullRequest, theURL, 512)) { return QTSS_NoErr; } // Make sure that this is not an admin request before // we go any further. StrPtrLen movie(theURL); if (IsAdminURL(movie)) { // The file path in the URL is actually an admin request. // Just ignore it and let the admin module handle it. return QTSS_NoErr; } Bool16 isHomeDir = IsHomeDirURL(movie); // Get the server's movie folder location. char* movieFolderString = NULL; err = QTSS_GetValueAsString (sServerPrefs, qtssPrefsMovieFolder, 0, &movieFolderString); if (err != QTSS_NoErr) return QTSS_NoErr; OSCharArrayDeleter movieFolder(movieFolderString); StrPtrLen theMovieFolder(movieFolderString); if (!isHomeDir && !FileExists(theMovieFolder, movie)) { // we couldn't find a file at the specified location // so we will ignore this HTTP request and let some other module // deal with the issue. return QTSS_NoErr; } else { // Eureka!!! We found a file at the specified location. // We assume that it is a valid movie file and we send // the client an RTSP text reference movie in the HTTP reply. err = SendTheResponse(theSession,theRequest, movie); } return QTSS_NoErr; }
QTSS_Error DoSetup(QTSS_StandardRTSP_Params* inParamBlock) { //setup this track in the file object FileSession* theFile = NULL; UInt32 theLen = sizeof(FileSession*); QTSS_Error theErr = QTSS_GetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, (void*)&theFile, &theLen); if ((theErr != QTSS_NoErr) || (theLen != sizeof(FileSession*))) { // This is possible, as clients are not required to send a DESCRIBE. If we haven't set // anything up yet, set everything up char* theFullPathStr = NULL; theErr = QTSS_GetValueAsString(inParamBlock->inRTSPRequest, qtssRTSPReqLocalPath, 0, &theFullPathStr); Assert(theErr == QTSS_NoErr); QTSSCharArrayDeleter theFullPathDeleter(theFullPathStr); StrPtrLen theFullPath(theFullPathStr); if ((theFullPath.Len <= sRTPSuffix.Len) || (!sRTPSuffix.NumEqualIgnoreCase(&theFullPath.Ptr[theFullPath.Len - sRTPSuffix.Len], sRTPSuffix.Len))) return QTSS_RequestFailed; theErr = CreateRTPFileSession(inParamBlock, theFullPath, &theFile); if (theErr != QTSS_NoErr) return theErr; // Store this newly created file object in the RTP session. theErr = QTSS_SetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, &theFile, sizeof(theFile)); } //unless there is a digit at the end of this path (representing trackID), don't //even bother with the request char* theDigitStr = NULL; (void)QTSS_GetValueAsString(inParamBlock->inRTSPRequest, qtssRTSPReqFileDigit, 0, &theDigitStr); QTSSCharArrayDeleter theDigitStrDeleter(theDigitStr); if (theDigitStr == NULL) return QTSSModuleUtils::SendErrorResponse(inParamBlock->inRTSPRequest, qtssClientBadRequest, sExpectedDigitFilenameErr); UInt32 theTrackID = ::strtol(theDigitStr, NULL, 10); RTPFileSession::ErrorCode qtfileErr = theFile->fFile.AddTrack(theTrackID); //if we get an error back, forward that error to the client if (qtfileErr == RTPFileSession::errTrackDoesntExist) return QTSSModuleUtils::SendErrorResponse(inParamBlock->inRTSPRequest, qtssClientNotFound, sTrackDoesntExistErr); else if (qtfileErr != RTPFileSession::errNoError) return QTSSModuleUtils::SendErrorResponse(inParamBlock->inRTSPRequest, qtssUnsupportedMediaType, sBadQTFileErr); //find the payload for this track ID (if applicable) StrPtrLen* thePayload = NULL; UInt32 thePayloadType = qtssUnknownPayloadType; Float32 bufferDelay = (Float32) 3.0; // FIXME need a constant defined for 3.0 value. It is used multiple places for (UInt32 x = 0; x < theFile->fFile.GetSourceInfo()->GetNumStreams(); x++) { SourceInfo::StreamInfo* theStreamInfo = theFile->fFile.GetSourceInfo()->GetStreamInfo(x); if (theStreamInfo->fTrackID == theTrackID) { thePayload = &theStreamInfo->fPayloadName; thePayloadType = theStreamInfo->fPayloadType; bufferDelay = theStreamInfo->fBufferDelay; break; } } //Create a new RTP stream QTSS_RTPStreamObject newStream = NULL; theErr = QTSS_AddRTPStream(inParamBlock->inClientSession, inParamBlock->inRTSPRequest, &newStream, 0); if (theErr != QTSS_NoErr) return theErr; // Set the payload type, payload name & timescale of this track SInt32 theTimescale = theFile->fFile.GetTrackTimeScale(theTrackID); theErr = QTSS_SetValue(newStream, qtssRTPStrBufferDelayInSecs, 0, &bufferDelay, sizeof(bufferDelay)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadName, 0, thePayload->Ptr, thePayload->Len); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadType, 0, &thePayloadType, sizeof(thePayloadType)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTimescale, 0, &theTimescale, sizeof(theTimescale)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTrackID, 0, &theTrackID, sizeof(theTrackID)); Assert(theErr == QTSS_NoErr); // Set the number of quality levels. Allow up to 6 static UInt32 sNumQualityLevels = 0; theErr = QTSS_SetValue(newStream, qtssRTPStrNumQualityLevels, 0, &sNumQualityLevels, sizeof(sNumQualityLevels)); Assert(theErr == QTSS_NoErr); // Get the SSRC of this track UInt32* theTrackSSRC = NULL; UInt32 theTrackSSRCSize = 0; (void)QTSS_GetValuePtr(newStream, qtssRTPStrSSRC, 0, (void**)&theTrackSSRC, &theTrackSSRCSize); // The RTP stream should ALWAYS have an SSRC assuming QTSS_AddStream succeeded. Assert((theTrackSSRC != NULL) && (theTrackSSRCSize == sizeof(UInt32))); //give the file some info it needs. theFile->fFile.SetTrackSSRC(theTrackID, *theTrackSSRC); theFile->fFile.SetTrackCookie(theTrackID, newStream); // // Our array has now been updated to reflect the fields requested by the client. //send the setup response //(void)QTSS_AppendRTSPHeader(inParamBlock->inRTSPRequest, qtssLastModifiedHeader, // theFile->fFile.GetQTFile()->GetModDateStr(), DateBuffer::kDateBufferLen); (void)QTSS_AppendRTSPHeader(inParamBlock->inRTSPRequest, qtssCacheControlHeader, kCacheControlHeader.Ptr, kCacheControlHeader.Len); //send the setup response (void)QTSS_SendStandardRTSPResponse(inParamBlock->inRTSPRequest, newStream, 0); return QTSS_NoErr; }