void QueryParamList::BulidList( StrPtrLen* querySPL ) { // parse the string and build the name/value list from the tokens. // the string is a 'form' encoded query string ( see rfc - 1808 ) StringParser queryParser( querySPL ); while ( queryParser.GetDataRemaining() > 0 ) { StrPtrLen theCGIParamName; StrPtrLen theCGIParamValue; queryParser.ConsumeUntil(&theCGIParamName, '='); // leaves "=..." in cgiParser, puts item keywd in theCGIParamName if ( queryParser.GetDataRemaining() > 1 ) { queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '=' queryParser.ConsumeUntil(&theCGIParamValue, '&'); // our value will end by here... AddNameValuePairToList( theCGIParamName.GetAsCString(), theCGIParamValue.GetAsCString() ); queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '=' } } }
void QueryParamList::BulidList( StrPtrLen* querySPL ) { // parse the string and build the name/value list from the tokens. // the string is a 'form' encoded query string ( see rfc - 1808 ) StringParser queryParser( querySPL ); char *stopCharPtr = NULL; while ( queryParser.GetDataRemaining() > 0 ) { StrPtrLen theCGIParamName; StrPtrLen theCGIParamValue; queryParser.ConsumeUntil(&theCGIParamName, '='); // leaves "=..." in cgiParser, puts item keywd in theCGIParamName if ( queryParser.GetDataRemaining() > 1 ) { queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '=' stopCharPtr = queryParser.GetCurrentPosition(); if (*stopCharPtr == '"') // if quote read to next quote { queryParser.ConsumeLength(NULL, 1); queryParser.ConsumeUntil(&theCGIParamValue, '"'); queryParser.ConsumeLength(NULL, 1); queryParser.ConsumeUntil(NULL, '&'); // our value will end by here... } else queryParser.ConsumeUntil(&theCGIParamValue, '&'); // our value will end by here... AddNameValuePairToList( theCGIParamName.GetAsCString(), theCGIParamValue.GetAsCString() ); queryParser.ConsumeLength(&theCGIParamValue, 1 ); // the '=' } } }
void RTConnectionManager::GenericSessionId(std::string& strId) { SInt64 curTime = OS::Microseconds(); MD5_CTX context; StrPtrLen hashStr; OSMutexLocker locker(&s_mutex); memset(s_curMicroSecStr, 0, 128); memset(s_digest, 0, 16); qtss_sprintf(s_curMicroSecStr, "%lld", curTime); MD5_Init(&context); MD5_Update(&context, (unsigned char*)s_curMicroSecStr, (unsigned int)strlen((const char*)s_curMicroSecStr)); MD5_Update(&context, (unsigned char*)m_lastUpdateTime.c_str(), (unsigned int)m_lastUpdateTime.length()); MD5_Final(s_digest, &context); HashToString(s_digest, &hashStr); strId = hashStr.GetAsCString(); m_lastUpdateTime = s_curMicroSecStr; }
QTSS_Error RTSPRequest::ParseBasicHeader(StringParser *inParsedAuthLinePtr) { QTSS_Error theErr = QTSS_NoErr; fAuthScheme = qtssAuthBasic; StrPtrLen authWord; inParsedAuthLinePtr->ConsumeWhitespace(); inParsedAuthLinePtr->ConsumeUntilWhitespace(&authWord); if (0 == authWord.Len ) return theErr; char* encodedStr = authWord.GetAsCString(); OSCharArrayDeleter encodedStrDeleter(encodedStr); char *decodedAuthWord = NEW char[Base64decode_len(encodedStr) + 1]; OSCharArrayDeleter decodedAuthWordDeleter(decodedAuthWord); (void) Base64decode(decodedAuthWord, encodedStr); StrPtrLen nameAndPassword; nameAndPassword.Set(decodedAuthWord, ::strlen(decodedAuthWord)); StrPtrLen name(""); StrPtrLen password(""); StringParser parsedNameAndPassword(&nameAndPassword); parsedNameAndPassword.ConsumeUntil(&name,':'); parsedNameAndPassword.ConsumeLength(NULL, 1); parsedNameAndPassword.GetThruEOL(&password); // Set the qtssRTSPReqUserName and qtssRTSPReqUserPassword attributes in the Request object (void) this->SetValue(qtssRTSPReqUserName, 0, name.Ptr , name.Len, QTSSDictionary::kDontObeyReadOnly); (void) this->SetValue(qtssRTSPReqUserPassword, 0, password.Ptr , password.Len, QTSSDictionary::kDontObeyReadOnly); // Also set the qtssUserName attribute in the qtssRTSPReqUserProfile object attribute of the Request Object (void) fUserProfile.SetValue(qtssUserName, 0, name.Ptr, name.Len, QTSSDictionary::kDontObeyReadOnly); return theErr; }
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; }
bool AccessChecker::CheckUserAccess(const char* inUsername) { ::qtss_printf("In QTSSDemoODAuthModule: Check User Access - start\n"); const int kBufLen = 2048; char buf[kBufLen]; StrPtrLen bufLine; if ( fAccessFile == NULL ) return false; std::rewind(fAccessFile); while ( std::fgets(buf, kBufLen, fAccessFile) != NULL ) { bufLine.Set(buf, strlen(buf)); StringParser bufParser(&bufLine); //skip over leading whitespace bufParser.ConsumeUntil(NULL, StringParser::sWhitespaceMask); //skip over comments and blank lines... if ((bufParser.GetDataRemaining() == 0) || (bufParser[0] == '#') || (bufParser[0] == '\0') ) continue; StrPtrLen word; bufParser.ConsumeWord(&word); if ( word.Equal("require") ) { bufParser.ConsumeWhitespace(); bufParser.ConsumeWord(&word); if ( word.Equal("user") ) { while (word.Len != 0) { bufParser.ConsumeWhitespace(); bufParser.ConsumeWord(&word); if (word.Equal(inUsername)) { ::qtss_printf("QTSSDemoODAuthModule in CheckUserAccess() : user %s found\n", inUsername); return true; } } } else if (word.Equal("valid-user")) { ::qtss_printf("QTSSDemoODAuthModule in CheckUserAccess(): valid-user\n"); return true; } else if ( word.Equal("group") ) { while (word.Len != 0) { bufParser.ConsumeWhitespace(); bufParser.ConsumeWord(&word); if ( this->CheckGroupMembership(inUsername, word.GetAsCString()) ) { ::qtss_printf("QTSSDemoODAuthModule in CheckUserAccess(): user is part of %s group\n", word.GetAsCString()); return true; } } } } } return false; }
QTSS_Error QTSSCallbacks::QTSS_Authorize(QTSS_RTSPRequestObject inAuthRequestObject, char** outAuthRealm, Bool16* outAuthUserAllowed) { RTSPRequestInterface* request = (RTSPRequestInterface *) inAuthRequestObject; if (request == NULL) return QTSS_BadArgument; // Because this is a role being executed from inside a callback, we need to // make sure that QTSS_RequestEvent will not work. Task* curTask = NULL; QTSS_ModuleState* theState = (QTSS_ModuleState*)OSThread::GetMainThreadData(); if (OSThread::GetCurrent() != NULL) theState = (QTSS_ModuleState*)OSThread::GetCurrent()->GetThreadData(); if (theState != NULL) curTask = theState->curTask; QTSS_RoleParams theParams; theParams.rtspRequestParams.inRTSPSession = NULL; theParams.rtspRequestParams.inRTSPRequest = request; theParams.rtspRequestParams.inClientSession = NULL; QTSS_Error theErr = QTSS_RequestFailed; UInt32 x = 0; UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPAuthRole); QTSSModule* theModulePtr = NULL; Bool16 allowedDefault = QTSServerInterface::GetServer()->GetPrefs()->GetAllowGuestDefault(); *outAuthUserAllowed = allowedDefault; Bool16 allowed = allowedDefault; //server pref? Bool16 hasUser = false; Bool16 handled = false; // Call all the modules that are registered for the RTSP Authorize Role for ( ; x < numModules; x++) { request->SetAllowed(true); request->SetHasUser(false); request->SetAuthHandled(false); debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu\n", x,numModules); theModulePtr = QTSServerInterface::GetModule(QTSSModule::kRTSPAuthRole, x); theErr = QTSS_NoErr; if (theModulePtr) { if (__QTSSCALLBACKS_DEBUG__) theModulePtr->GetValue(qtssModName)->PrintStr("QTSSModule::CallDispatch ENTER module=", "\n"); theErr = theModulePtr->CallDispatch(QTSS_RTSPAuthorize_Role, &theParams); debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu numModules=%lu ModuleError=%ld\n", x,numModules, theErr); } else { debug_printf(" QTSSCallbacks::QTSS_Authorize calling module module = %lu is NULL! numModules=%lu\n", x,numModules); continue; } allowed = request->GetAllowed(); hasUser = request->GetHasUser(); handled = request->GetAuthHandled(); debug_printf("QTSSCallbacks::QTSS_Authorize allowedDefault =%d allowed= %d hasUser = %d handled=%d \n",allowedDefault, allowed,hasUser, handled); *outAuthUserAllowed = allowed; //notes: //if (allowed && !handled) break; //old module //if (!allowed && handled) /new module handled the request but not authorized keep trying //if (allowed && handled) //new module allowed but keep trying in case someone denies. if (!allowed && !handled) //old module break on !allowed { debug_printf("RTSPSession.cpp::Run(kAuthorizingRequest) skipping other modules fCurrentModule = %lu numModules=%lu\n", x,numModules); break; } } // outAuthRealm is set to the realm that is given by the module that has denied authentication StrPtrLen* realm = request->GetValue(qtssRTSPReqURLRealm); *outAuthRealm = realm->GetAsCString(); return theErr; }
QTSS_Error ProcessRTSPRequest(QTSS_StandardRTSP_Params* inParams) { ProxyClientInfo* theClient = NULL; UInt32 theLen = sizeof(theClient); QTSS_Error theErr = QTSS_GetValue(inParams->inClientSession, sProxyClientInfoAttr, 0, &theClient, &theLen); // // If there is no client yet, this is the first request made on this session. // Create an RTSPClient if (theErr != QTSS_NoErr) { theClient = NEW ProxyClientInfo(); // // Parse out the DNS name of the origin server and the port StrPtrLen theDNSNameAndPort; theErr = QTSS_GetValuePtr(inParams->inRTSPHeaders, qtssHostHeader, 0, (void**)&theDNSNameAndPort.Ptr, &theDNSNameAndPort.Len); Assert(theErr == QTSS_NoErr); StringParser extractPortNumber(&theDNSNameAndPort); StrPtrLen theDNSNamePtr; extractPortNumber.GetThru(&theDNSNamePtr, ':'); UInt32 thePort = extractPortNumber.ConsumeInteger(NULL); // // For now, if there was no port specified, use 554 if (thePort == 0) thePort = 554; // // Make sure the port is in the range of a 2-byte integer if (thePort > 65536) return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest, sPortNumberTooBigErr); // // gethostbyname takes a NULL terminated C-string OSCharArrayDeleter theDNSName(theDNSNamePtr.GetAsCString()); // // Do a DNS lookup on the host to find its IP address struct hostent* theHostent = ::gethostbyname(theDNSName); UInt32 theIPAddr = 0; if (theHostent != NULL) theIPAddr = ntohl(*(UInt32*)(theHostent->h_addr_list[0])); else theIPAddr = SocketUtils::ConvertStringToAddr(theDNSName); // // Give this information to the ClientSocket object theClient->GetRTSPClient()->GetSocket()->Set(theIPAddr, (UInt16)thePort); theErr = QTSS_SetValue(inParams->inClientSession, sProxyClientInfoAttr, 0, &theClient, sizeof(theClient)); Assert(theErr == QTSS_NoErr); // // Start the process of connecting to the origin server, first // just by telling the ClientSocket to send an empty message theErr = theClient->GetRTSPClient()->GetSocket()->Send(NULL, 0); if (theErr != QTSS_NoErr) // // we are connecting. This function will be called when connection is set up return HandleRTSPClientErr(inParams->inRTSPRequest, theClient, theErr); } // // If we aren't in the middle of sending a request, we have to set it up if (!theClient->GetRTSPClient()->IsTransactionInProgress()) theErr = DoRequestPreProcessing(theClient, inParams->inRTSPRequest, inParams->inClientSession); else // // Continue our attempt to send this request theErr = theClient->GetRTSPClient()->DoTransaction(); if (theErr != QTSS_NoErr) HandleRTSPClientErr(inParams->inRTSPRequest, theClient, theErr); else // // The response has come back from the origin server. Do whatever // processing we need on it, and send the response to the proxy client. theErr = DoRequestPostProcessing(theClient, inParams->inRTSPRequest, inParams->inClientSession); return theErr; }
// allocates memory for outUsersFilePath and outGroupsFilePath - remember to delete // returns the auth scheme QTSS_AuthScheme QTAccessFile::FindUsersAndGroupsFilesAndAuthScheme(char* inAccessFilePath, QTSS_ActionFlags inAction, char** outUsersFilePath, char** outGroupsFilePath) { QTSS_AuthScheme authScheme = qtssAuthNone; QTSS_ActionFlags currentFlags = qtssActionFlagsRead; if (inAccessFilePath == NULL) return authScheme; *outUsersFilePath = NULL; *outGroupsFilePath = NULL; //Assert(outUsersFilePath == NULL); //Assert(outGroupsFilePath == NULL); StrPtrLen accessFileBuf; (void)QTSSModuleUtils::ReadEntireFile(inAccessFilePath, &accessFileBuf); OSCharArrayDeleter accessFileBufDeleter(accessFileBuf.Ptr); StringParser accessFileParser(&accessFileBuf); StrPtrLen line; StrPtrLen word; while( accessFileParser.GetDataRemaining() != 0 ) { accessFileParser.GetThruEOL(&line); // Read each line StringParser lineParser(&line); lineParser.ConsumeWhitespace(); //skip over leading whitespace if (lineParser.GetDataRemaining() == 0) // must be an empty line continue; char firstChar = lineParser.PeekFast(); if ( (firstChar == '#') || (firstChar == '\0') ) continue; //skip over comments and blank lines... lineParser.ConsumeUntilWhitespace(&word); if ( word.Equal("<Limit") ) // a limit line { currentFlags = qtssActionFlagsNoFlags; // clear to no access lineParser.ConsumeWhitespace(); lineParser.ConsumeUntil( &word, sWhitespaceAndGreaterThanMask); // the flag <limit Read> or <limit Read > while (word.Len != 0) // compare each word in the line { if (word.Equal("WRITE") ) { currentFlags |= inAction & qtssActionFlagsWrite; // accept following lines if inFlags has write } if (word.Equal("READ") ) { currentFlags |= inAction & qtssActionFlagsRead; // accept following lines if inFlags has read } lineParser.ConsumeWhitespace(); lineParser.ConsumeUntil(&word, sWhitespaceAndGreaterThanMask); } continue; //done with limit line } if ( word.Equal("</Limit>") ) currentFlags = qtssActionFlagsRead; // set the current access state to the default of read access if (0 == (currentFlags & inAction)) continue; // ignore lines because inFlags doesn't match the current access state if (word.Equal("AuthUserFile") ) { lineParser.ConsumeWhitespace(); lineParser.GetThruEOL(&word); StringParser::UnQuote(&word);// if the parsed string is surrounded by quotes then remove them. if(*outUsersFilePath != NULL) // we are encountering the AuthUserFile keyword twice! delete[] *outUsersFilePath; // The last one found takes precedence...delete the previous path *outUsersFilePath = word.GetAsCString(); continue; } if (word.Equal("AuthGroupFile") ) { lineParser.ConsumeWhitespace(); lineParser.GetThruEOL(&word); StringParser::UnQuote(&word);// if the parsed string is surrounded by quotes then remove them. if(*outGroupsFilePath != NULL) // we are encountering the AuthGroupFile keyword twice! delete[] *outGroupsFilePath; // The last one found takes precedence...delete the previous path *outGroupsFilePath = word.GetAsCString(); continue; } if (word.Equal("AuthScheme") ) { lineParser.ConsumeWhitespace(); lineParser.GetThruEOL(&word); StringParser::UnQuote(&word);// if the parsed string is surrounded by quotes then remove them. if (word.Equal("basic")) authScheme = qtssAuthBasic; else if (word.Equal("digest")) authScheme = qtssAuthDigest; continue; } } return authScheme; }
bool XMLTag::ParseTag(StringParser* parser, DTDVerifier* verifier, char* errorBuffer, int errorBufferSize) { while (true) { if (!parser->GetThru(NULL, '<')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Couldn't find a valid tag"); return false; // couldn't find beginning of tag } char c = parser->PeekFast(); if (c == '/') { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "End tag with no begin tag on line %d", parser->GetCurrentLineNumber()); return false; // we shouldn't be seeing a close tag here } if ((c != '!') && (c != '?')) break; // this should be the beginning of a regular tag ConsumeIfComment(parser); // otherwise this is a processing instruction or a c-data, so look for the next tag } int tagStartLine = parser->GetCurrentLineNumber(); StrPtrLen temp; parser->ConsumeUntil(&temp, sNonNameMask); if (temp.Len == 0) { if (errorBuffer != NULL) { if (parser->GetDataRemaining() == 0) qtss_snprintf(errorBuffer, errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber()); else qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber()); } return false; // bad file } fTag = temp.GetAsCString(); parser->ConsumeWhitespace(); while ((parser->PeekFast() != '>') && (parser->PeekFast() != '/')) { // we must have an attribute value for this tag XMLAttribute* attr = new XMLAttribute; fAttributes.EnQueue(&attr->fElem); parser->ConsumeUntil(&temp, sNonNameMask); if (temp.Len == 0) { if (errorBuffer != NULL) { if (parser->GetDataRemaining() == 0) qtss_snprintf(errorBuffer, errorBufferSize, "Unexpected end of file on line %d", parser->GetCurrentLineNumber()); else qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected character (%c) on line %d", parser->PeekFast(), parser->GetCurrentLineNumber()); } return false; // bad file } attr->fAttrName = temp.GetAsCString(); if (!parser->Expect('=')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Missing '=' after attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } if (!parser->Expect('"')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } parser->ConsumeUntil(&temp, '"'); attr->fAttrValue = temp.GetAsCString(); if (!parser->Expect('"')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s value not in quotes on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } if (verifier && !verifier->IsValidAttributeName(fTag, attr->fAttrName)) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Attribute %s not allowed in tag %s on line %d", attr->fAttrName, fTag, parser->GetCurrentLineNumber()); return false; // bad attribute specification } if (verifier && !verifier->IsValidAttributeValue(fTag, attr->fAttrName, attr->fAttrValue)) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Bad value for attribute %s on line %d", attr->fAttrName, parser->GetCurrentLineNumber()); return false; // bad attribute specification } parser->ConsumeWhitespace(); } if (parser->PeekFast() == '/') { // this is an empty element tag, i.e. no contents or end tag (e.g <TAG attr="value" /> parser->Expect('/'); if (!parser->Expect('>')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"'>' must follow '/' on line %d", parser->GetCurrentLineNumber()); return false; // bad attribute specification } return true; // we're done with this tag } if (!parser->Expect('>')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Bad format for tag <%s> on line %d", fTag, parser->GetCurrentLineNumber()); return false; // bad attribute specification } while(true) { parser->ConsumeUntil(&temp, '<'); // this is either value or whitespace if (parser->GetDataRemaining() < 4) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Reached end of file without end for tag <%s> declared on line %d", fTag, tagStartLine); return false; } if ((*parser)[1] == '/') { // we'll only assign a value if there were no embedded tags if (fEmbeddedTags.GetLength() == 0 && (!verifier || verifier->CanHaveValue(fTag))) fValue = temp.GetAsCString(); else { // otherwise this needs to have been just whitespace StringParser tempParser(&temp); tempParser.ConsumeWhitespace(); if (tempParser.GetDataRemaining() > 0) { if (errorBuffer) { if (fEmbeddedTags.GetLength() > 0) qtss_snprintf(errorBuffer, errorBufferSize,"Unexpected text outside of tag on line %d", tagStartLine); else qtss_snprintf(errorBuffer, errorBufferSize, "Tag <%s> on line %d not allowed to have data", fTag, tagStartLine); } } } break; // we're all done with this tag } if (((*parser)[1] != '!') && ((*parser)[1] != '?')) { // this must be the beginning of an embedded tag XMLTag* tag = NEW XMLTag(); fEmbeddedTags.EnQueue(&tag->fElem); if (!tag->ParseTag(parser, verifier, errorBuffer, errorBufferSize)) return false; if (verifier && !verifier->IsValidSubtag(fTag, tag->GetTagName())) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize, "Tag %s not allowed in tag %s on line %d", tag->GetTagName(), fTag, parser->GetCurrentLineNumber()); return false; // bad attribute specification } } else { parser->ConsumeLength(NULL, 1); // skip '<' ConsumeIfComment(parser); } } parser->ConsumeLength(NULL, 2); // skip '</' parser->ConsumeUntil(&temp, sNonNameMask); if (!temp.Equal(fTag)) { char* newTag = temp.GetAsCString(); if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"End tag </%s> on line %d doesn't match tag <%s> declared on line %d", newTag, parser->GetCurrentLineNumber(),fTag, tagStartLine); delete newTag; return false; // bad attribute specification } if (!parser->GetThru(NULL, '>')) { if (errorBuffer != NULL) qtss_snprintf(errorBuffer, errorBufferSize,"Couldn't find end of tag <%s> declared on line %d", fTag, tagStartLine); return false; // bad attribute specification } return true; }
//returns: SyntaxError if there was an error in the uri. Or InternalServerError QTSS_Error RTSPRequest::ParseURI(StringParser &parser) { //read in the complete URL, set it to be the qtssAbsoluteURLParam StrPtrLen theAbsURL; // RTSPRequestInterface::sPathURLStopConditions stop on ? as well as sURLStopConditions parser.ConsumeUntil(&theAbsURL, sURLStopConditions ); // set qtssRTSPReqAbsoluteURL to the URL throught the path component; will be : <protocol>://<host-addr>/<path> this->SetVal(qtssRTSPReqAbsoluteURL, &theAbsURL); StringParser urlParser(&theAbsURL); //we always should have a slash before the uri. //If not, that indicates this is a full URI. Also, this could be a '*' OPTIONS request if ((*theAbsURL.Ptr != '/') && (*theAbsURL.Ptr != '*')) { //if it is a full URL, store the host name off in a separate parameter StrPtrLen theRTSPString; urlParser.ConsumeLength(&theRTSPString, 7); //consume "rtsp://" //assign the host field here to the proper QTSS param StrPtrLen theHost; urlParser.ConsumeUntil(&theHost, '/'); fHeaderDictionary.SetVal(qtssHostHeader, &theHost); } // don't allow non-aggregate operations indicated by a url/media track=id // might need this for rate adapt if (qtssSetupMethod != fMethod && qtssOptionsMethod != fMethod && qtssSetParameterMethod != fMethod) // any method not a setup, options, or setparameter is not allowed to have a "/trackID=" in the url. if (qtssSetupMethod != fMethod) // any method not a setup is not allowed to have a "/trackID=" in the url. { StrPtrLenDel tempCStr(theAbsURL.GetAsCString()); StrPtrLen nonaggregate(tempCStr.FindString("/trackID=")); if (nonaggregate.Len > 0) // check for non-aggregate method and return error return QTSSModuleUtils::SendErrorResponse(this, qtssClientAggregateOptionAllowed, qtssMsgBadRTSPMethod, &theAbsURL); } // don't allow non-aggregate operations like a setup on a playing session if (qtssSetupMethod == fMethod) // if it is a setup but we are playing don't allow it { RTSPSession* theSession = (RTSPSession*)this->GetSession(); if (theSession != NULL && theSession->IsPlaying()) return QTSSModuleUtils::SendErrorResponse(this, qtssClientAggregateOptionAllowed, qtssMsgBadRTSPMethod, &theAbsURL); } // // In case there is no URI at all... we have to fake it. static char* sSlashURI = "/"; //whatever is in this position in the URL must be the URI. Store that //in the qtssURLParam. Confused? UInt32 uriLen = urlParser.GetDataReceivedLen() - urlParser.GetDataParsedLen(); if (uriLen > 0) this->SetVal(qtssRTSPReqURI, urlParser.GetCurrentPosition(), urlParser.GetDataReceivedLen() - urlParser.GetDataParsedLen()); else // // This might happen if there is nothing after the host at all, not even // a '/'. This is legal (RFC 2326, Sec 3.2). If so, just pretend that there // is a '/' this->SetVal(qtssRTSPReqURI, sSlashURI, 1); // parse the query string from the url if present. // init qtssRTSPReqQueryString dictionary to an empty string StrPtrLen queryString; this->SetVal(qtssRTSPReqQueryString, queryString.Ptr, queryString.Len); if ( parser.GetDataRemaining() > 0 ) { if ( parser.PeekFast() == '?' ) { // we've got some CGI param parser.ConsumeLength(&queryString, 1); // toss '?' // consume the rest of the line.. parser.ConsumeUntilWhitespace(&queryString); this->SetVal(qtssRTSPReqQueryString, queryString.Ptr, queryString.Len); } } // // If the is a '*', return right now because '*' is not a path // so the below functions don't make any sense. if ((*theAbsURL.Ptr == '*') && (theAbsURL.Len == 1)) { this->SetValue(qtssRTSPReqFilePath, 0, theAbsURL.Ptr, theAbsURL.Len, QTSSDictionary::kDontObeyReadOnly); return QTSS_NoErr; } //path strings are statically allocated. Therefore, if they are longer than //this length we won't be able to handle the request. StrPtrLen* theURLParam = this->GetValue(qtssRTSPReqURI); if (theURLParam->Len > RTSPRequestInterface::kMaxFilePathSizeInBytes) return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgURLTooLong, theURLParam); //decode the URL, put the result in the separate buffer for the file path, //set the file path StrPtrLen to the proper value SInt32 theBytesWritten = StringTranslator::DecodeURL(theURLParam->Ptr, theURLParam->Len, fFilePath, RTSPRequestInterface::kMaxFilePathSizeInBytes); //if negative, an error occurred, reported as an QTSS_Error //we also need to leave room for a terminator. if ((theBytesWritten < 0) || (theBytesWritten == RTSPRequestInterface::kMaxFilePathSizeInBytes)) { return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgURLInBadFormat, theURLParam); } // Convert from a / delimited path to a local file system path StringTranslator::DecodePath(fFilePath, theBytesWritten); //setup the proper QTSS param fFilePath[theBytesWritten] = '\0'; //this->SetVal(qtssRTSPReqFilePath, fFilePath, theBytesWritten); this->SetValue(qtssRTSPReqFilePath, 0, fFilePath, theBytesWritten, QTSSDictionary::kDontObeyReadOnly); return QTSS_NoErr; }
void SDPSourceInfo::Parse(char* sdpData, UInt32 sdpLen) { // // There are some situations in which Parse can be called twice. // If that happens, just return and don't do anything the second time. if (fSDPData.Ptr != NULL) return; Assert(fStreamArray == NULL); char *sdpDataCopy = new char[sdpLen]; Assert(sdpDataCopy != NULL); memcpy(sdpDataCopy,sdpData, sdpLen); fSDPData.Set(sdpDataCopy, sdpLen); // If there is no trackID information in this SDP, we make the track IDs start // at 1 -> N UInt32 currentTrack = 1; bool hasGlobalStreamInfo = false; StreamInfo theGlobalStreamInfo; //needed if there is one c= header independent of //individual streams StrPtrLen sdpLine; StringParser trackCounter(&fSDPData); StringParser sdpParser(&fSDPData); UInt32 theStreamIndex = 0; //walk through the SDP, counting up the number of tracks // Repeat until there's no more data in the SDP while (trackCounter.GetDataRemaining() > 0) { //each 'm' line in the SDP file corresponds to another track. trackCounter.GetThruEOL(&sdpLine); if ((sdpLine.Len > 0) && (sdpLine.Ptr[0] == 'm')) fNumStreams++; } //We should scale the # of StreamInfos to the # of trax, but we can't because //of an annoying compiler bug... fStreamArray = new StreamInfo[fNumStreams]; ::memset(fStreamArray, 0, sizeof(StreamInfo) * fNumStreams); // set the default destination as our default IP address and set the default ttl theGlobalStreamInfo.fDestIPAddr = INADDR_ANY; theGlobalStreamInfo.fTimeToLive = kDefaultTTL; //Set bufferdelay to default of 3 theGlobalStreamInfo.fBufferDelay = (Float32) eDefaultBufferDelay; //Now actually get all the data on all the streams while (sdpParser.GetDataRemaining() > 0) { sdpParser.GetThruEOL(&sdpLine); if (sdpLine.Len == 0) continue;//skip over any blank lines switch (*sdpLine.Ptr) { case 't': { StringParser mParser(&sdpLine); mParser.ConsumeUntil(NULL, StringParser::sDigitMask); UInt32 ntpStart = mParser.ConsumeInteger(NULL); mParser.ConsumeUntil(NULL, StringParser::sDigitMask); UInt32 ntpEnd = mParser.ConsumeInteger(NULL); SetActiveNTPTimes(ntpStart,ntpEnd); } break; case 'm': { if (hasGlobalStreamInfo) { fStreamArray[theStreamIndex].fDestIPAddr = theGlobalStreamInfo.fDestIPAddr; fStreamArray[theStreamIndex].fTimeToLive = theGlobalStreamInfo.fTimeToLive; } fStreamArray[theStreamIndex].fTrackID = currentTrack; currentTrack++; StringParser mParser(&sdpLine); //find out what type of track this is mParser.ConsumeLength(NULL, 2);//go past 'm=' StrPtrLen theStreamType; mParser.ConsumeWord(&theStreamType); if (theStreamType.Equal(sVideoStr)) fStreamArray[theStreamIndex].fPayloadType = qtssVideoPayloadType; else if (theStreamType.Equal(sAudioStr)) fStreamArray[theStreamIndex].fPayloadType = qtssAudioPayloadType; //find the port for this stream mParser.ConsumeUntil(NULL, StringParser::sDigitMask); SInt32 tempPort = mParser.ConsumeInteger(NULL); if ((tempPort > 0) && (tempPort < 65536)) fStreamArray[theStreamIndex].fPort = (UInt16) tempPort; // find out whether this is TCP or UDP mParser.ConsumeWhitespace(); StrPtrLen transportID; mParser.ConsumeWord(&transportID); static const StrPtrLen kTCPTransportStr("RTP/AVP/TCP"); if (transportID.Equal(kTCPTransportStr)) fStreamArray[theStreamIndex].fIsTCP = true; theStreamIndex++; } break; case 'a': { StringParser aParser(&sdpLine); aParser.ConsumeLength(NULL, 2);//go past 'a=' StrPtrLen aLineType; aParser.ConsumeWord(&aLineType); if (aLineType.Equal(sBroadcastControlStr)) { // found a control line for the broadcast (delete at time or delete at end of broadcast/server startup) // qtss_printf("found =%s\n",sBroadcastControlStr); aParser.ConsumeUntil(NULL,StringParser::sWordMask); StrPtrLen sessionControlType; aParser.ConsumeWord(&sessionControlType); if (sessionControlType.Equal(sAutoDisconnect)) { fSessionControlType = kRTSPSessionControl; } else if (sessionControlType.Equal(sAutoDisconnectTime)) { fSessionControlType = kSDPTimeControl; } } //if we haven't even hit an 'm' line yet, just ignore all 'a' lines if (theStreamIndex == 0) break; if (aLineType.Equal(sRtpMapStr)) { //mark the codec type if this line has a codec name on it. If we already //have a codec type for this track, just ignore this line if ((fStreamArray[theStreamIndex - 1].fPayloadName.Len == 0) && (aParser.GetThru(NULL, ' '))) { StrPtrLen payloadNameFromParser; (void)aParser.GetThruEOL(&payloadNameFromParser); char* temp = payloadNameFromParser.GetAsCString(); // qtss_printf("payloadNameFromParser (%x) = %s\n", temp, temp); (fStreamArray[theStreamIndex - 1].fPayloadName).Set(temp, payloadNameFromParser.Len); // qtss_printf("%s\n", fStreamArray[theStreamIndex - 1].fPayloadName.Ptr); } } else if (aLineType.Equal(sControlStr)) { // Modify By EasyDarwin //if ((fStreamArray[theStreamIndex - 1].fTrackName.Len == 0) && // (aParser.GetThru(NULL, ' '))) { StrPtrLen trackNameFromParser; aParser.ConsumeUntil(NULL,':'); aParser.ConsumeLength(NULL,1); aParser.GetThruEOL(&trackNameFromParser); char* temp = trackNameFromParser.GetAsCString(); // qtss_printf("trackNameFromParser (%x) = %s\n", temp, temp); (fStreamArray[theStreamIndex - 1].fTrackName).Set(temp, trackNameFromParser.Len); // qtss_printf("%s\n", fStreamArray[theStreamIndex - 1].fTrackName.Ptr); StringParser tParser(&trackNameFromParser); tParser.ConsumeUntil(NULL, '='); tParser.ConsumeUntil(NULL, StringParser::sDigitMask); fStreamArray[theStreamIndex - 1].fTrackID = tParser.ConsumeInteger(NULL); } } else if (aLineType.Equal(sBufferDelayStr)) { // if a BufferDelay is found then set all of the streams to the same buffer delay (it's global) aParser.ConsumeUntil(NULL, StringParser::sDigitMask); theGlobalStreamInfo.fBufferDelay = aParser.ConsumeFloat(); } } break; case 'c': { //get the IP address off this header StringParser cParser(&sdpLine); cParser.ConsumeLength(NULL, 9);//strip off "c=in ip4 " UInt32 tempIPAddr = SDPSourceInfo::GetIPAddr(&cParser, '/'); //grab the ttl SInt32 tempTtl = kDefaultTTL; if (cParser.GetThru(NULL, '/')) { tempTtl = cParser.ConsumeInteger(NULL); Assert(tempTtl >= 0); Assert(tempTtl < 65536); } if (theStreamIndex > 0) { //if this c= line is part of a stream, it overrides the //global stream information fStreamArray[theStreamIndex - 1].fDestIPAddr = tempIPAddr; fStreamArray[theStreamIndex - 1].fTimeToLive = (UInt16) tempTtl; } else { theGlobalStreamInfo.fDestIPAddr = tempIPAddr; theGlobalStreamInfo.fTimeToLive = (UInt16) tempTtl; hasGlobalStreamInfo = true; } } } } // Add the default buffer delay Float32 bufferDelay = (Float32) eDefaultBufferDelay; if (theGlobalStreamInfo.fBufferDelay != (Float32) eDefaultBufferDelay) bufferDelay = theGlobalStreamInfo.fBufferDelay; UInt32 count = 0; while (count < fNumStreams) { fStreamArray[count].fBufferDelay = bufferDelay; count ++; } }