void RTSPRequest::ParseModeSubHeader(StrPtrLen* inModeSubHeader) { static StrPtrLen sModeSubHeader("mode"); static StrPtrLen sReceiveMode("receive"); static StrPtrLen sRecordMode("record"); StringParser theSubHeaderParser(inModeSubHeader); // Skip over to the first port StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // Make sure this is the client port subheader if (theFirstBit.EqualIgnoreCase(sModeSubHeader)) do { theSubHeaderParser.ConsumeWhitespace(); StrPtrLen theMode; theSubHeaderParser.ConsumeWord(&theMode); if ( theMode.EqualIgnoreCase(sReceiveMode) || theMode.EqualIgnoreCase(sRecordMode) ) { fTransportMode = qtssRTPTransportModeRecord; break; } } while (false); }
void HTTPRequest::SetKeepAlive(StrPtrLen *keepAliveValue) { if ( sCloseString.EqualIgnoreCase(keepAliveValue->Ptr, keepAliveValue->Len) ) fRequestKeepAlive = sFalse; else { Assert( sKeepAliveString.EqualIgnoreCase(keepAliveValue->Ptr, keepAliveValue->Len) ); fRequestKeepAlive = sTrue; } }
void RTSPRequest::ParseRetransmitHeader() { StringParser theRetransmitParser(fHeaderDictionary.GetValue(qtssXRetransmitHeader)); StrPtrLen theProtName; Bool16 foundRetransmitProt = false; do { theRetransmitParser.ConsumeWhitespace(); theRetransmitParser.ConsumeWord(&theProtName); theProtName.TrimTrailingWhitespace(); foundRetransmitProt = theProtName.EqualIgnoreCase(RTSPProtocol::GetRetransmitProtocolName()); } while ( (!foundRetransmitProt) && (theRetransmitParser.GetThru(NULL, ',')) ); if (!foundRetransmitProt) return; // // We are using Reliable RTP as the transport for this stream, // but if there was a previous transport header that indicated TCP, // do not set the transport to be reliable UDP if (fTransportType == qtssRTPTransportTypeUDP) fTransportType = qtssRTPTransportTypeReliableUDP; StrPtrLen theProtArg; while (theRetransmitParser.GetThru(&theProtArg, '=')) { // // Parse out params static const StrPtrLen kWindow("window"); theProtArg.TrimWhitespace(); if (theProtArg.EqualIgnoreCase(kWindow)) { theRetransmitParser.ConsumeWhitespace(); fWindowSize = theRetransmitParser.ConsumeInteger(NULL); // Save out the window size argument as a string so we // can easily put it into the response // (we never muck with this header) fWindowSizeStr.Ptr = theProtArg.Ptr; fWindowSizeStr.Len = theRetransmitParser.GetCurrentPosition() - theProtArg.Ptr; } theRetransmitParser.GetThru(NULL, ';'); //Skip past ';' } }
QTSS_RTSPHeader RTSPProtocol::GetRequestHeader(const StrPtrLen &inHeaderStr) { if (inHeaderStr.Len == 0) return qtssIllegalHeader; QTSS_RTSPHeader theHeader = qtssIllegalHeader; //chances are this is one of our selected "VIP" headers. so check for this. switch(*inHeaderStr.Ptr) { case 'C': case 'c': theHeader = qtssCSeqHeader; break; case 'S': case 's': theHeader = qtssSessionHeader; break; case 'U': case 'u': theHeader = qtssUserAgentHeader; break; case 'A': case 'a': theHeader = qtssAcceptHeader; break; case 'T': case 't': theHeader = qtssTransportHeader; break; case 'R': case 'r': theHeader = qtssRangeHeader; break; case 'X': case 'x': theHeader = qtssExtensionHeaders; break; } // // Check to see whether this is one of our extension headers. These // are very likely to appear in requests. if (theHeader == qtssExtensionHeaders) { for (SInt32 y = qtssExtensionHeaders; y < qtssNumHeaders; y++) { if (inHeaderStr.EqualIgnoreCase(sHeaders[y].Ptr, sHeaders[y].Len)) return y; } } // // It's not one of our extension headers, check to see if this is one of // our normal VIP headers if ((theHeader != qtssIllegalHeader) && (inHeaderStr.EqualIgnoreCase(sHeaders[theHeader].Ptr, sHeaders[theHeader].Len))) return theHeader; // //If this isn't one of our VIP headers, go through the remaining request headers, trying //to find the right one. for (SInt32 x = qtssNumVIPHeaders; x < qtssNumHeaders; x++) { if (inHeaderStr.EqualIgnoreCase(sHeaders[x].Ptr, sHeaders[x].Len)) return x; } return qtssIllegalHeader; }
void RTSPRequest::ParseAddrSubHeader(StrPtrLen* inSubHeader, StrPtrLen* inHeaderName, UInt32* outAddr) { if (!inSubHeader || !inHeaderName || !outAddr) return; StringParser theSubHeaderParser(inSubHeader); // Skip over to the value StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // First make sure this is the proper subheader if (!theFirstBit.EqualIgnoreCase(*inHeaderName)) return; //Find the IP address theSubHeaderParser.ConsumeUntilDigit(); //Set the addr string param. StrPtrLen theAddr(theSubHeaderParser.GetCurrentPosition(), theSubHeaderParser.GetDataRemaining()); //Convert the string to a UInt32 IP address char theTerminator = theAddr.Ptr[theAddr.Len]; theAddr.Ptr[theAddr.Len] = '\0'; *outAddr = SocketUtils::ConvertStringToAddr(theAddr.Ptr); theAddr.Ptr[theAddr.Len] = theTerminator; }
QTSS_RTSPMethod RTSPProtocol::GetMethod(const StrPtrLen &inMethodStr) { //chances are this is one of our selected "VIP" methods. so check for this. QTSS_RTSPMethod theMethod = qtssIllegalMethod; switch(*inMethodStr.Ptr) { case 'S': case 's': theMethod = qtssSetupMethod; break; case 'D': case 'd': theMethod = qtssDescribeMethod; break; case 'T': case 't': theMethod = qtssTeardownMethod; break; case 'O': case 'o': theMethod = qtssOptionsMethod; break; case 'A': case 'a': theMethod = qtssAnnounceMethod; break; } if ((theMethod != qtssIllegalMethod) && (inMethodStr.EqualIgnoreCase(sMethods[theMethod].Ptr, sMethods[theMethod].Len))) return theMethod; for (SInt32 x = qtssNumVIPMethods; x < qtssIllegalMethod; x++) if (inMethodStr.EqualIgnoreCase(sMethods[x].Ptr, sMethods[x].Len)) return x; return qtssIllegalMethod; }
void RTSPRequest::ParseTimeToLiveSubHeader(StrPtrLen* inTimeToLiveSubHeader) { static StrPtrLen sTimeToLiveSubHeader("ttl"); StringParser theSubHeaderParser(inTimeToLiveSubHeader); // Skip over to the first part StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // Make sure this is the ttl subheader if (!theFirstBit.EqualIgnoreCase(sTimeToLiveSubHeader)) return; // Parse out the time to live... theSubHeaderParser.ConsumeWhitespace(); fTtl = (UInt16)theSubHeaderParser.ConsumeInteger(NULL); }
void RTSPRequest::ParsePrebufferHeader() { StringParser thePrebufferParser(fHeaderDictionary.GetValue(qtssXPreBufferHeader)); StrPtrLen thePrebufferArg; while (thePrebufferParser.GetThru(&thePrebufferArg, '=')) { thePrebufferArg.TrimWhitespace(); static const StrPtrLen kMaxTimeSubHeader("maxtime"); if (thePrebufferArg.EqualIgnoreCase(kMaxTimeSubHeader)) { thePrebufferParser.ConsumeWhitespace(); fPrebufferAmt = thePrebufferParser.ConsumeFloat(); } thePrebufferParser.GetThru(NULL, ';'); //Skip past ';' } }
void RTSPRequest::ParseClientPortSubHeader(StrPtrLen* inClientPortSubHeader) { static StrPtrLen sClientPortSubHeader("client_port"); static StrPtrLen sErrorMessage("Received invalid client_port field: "); StringParser theSubHeaderParser(inClientPortSubHeader); // Skip over to the first port StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // Make sure this is the client port subheader if (!theFirstBit.EqualIgnoreCase(sClientPortSubHeader)) return; // Store the two client ports as integers theSubHeaderParser.ConsumeWhitespace(); fClientPortA = (UInt16)theSubHeaderParser.ConsumeInteger(NULL); theSubHeaderParser.GetThru(NULL,'-'); theSubHeaderParser.ConsumeWhitespace(); fClientPortB = (UInt16)theSubHeaderParser.ConsumeInteger(NULL); if (fClientPortB != fClientPortA + 1) // an error in the port values { // The following to setup and log the error as a message level 2. StrPtrLen *userAgentPtr = fHeaderDictionary.GetValue(qtssUserAgentHeader); ResizeableStringFormatter errorPortMessage; errorPortMessage.Put(sErrorMessage); if (userAgentPtr != NULL) errorPortMessage.Put(*userAgentPtr); errorPortMessage.PutSpace(); errorPortMessage.Put(*inClientPortSubHeader); errorPortMessage.PutTerminator(); QTSSModuleUtils::LogError(qtssMessageVerbosity,qtssMsgNoMessage, 0, errorPortMessage.GetBufPtr(), NULL); //fix the rtcp port and hope it works. fClientPortB = fClientPortA + 1; } }
QTSS_Error QTSSDataConverter::StringToValue( char* inValueAsString, QTSS_AttrDataType inType, void* ioBuffer, UInt32* ioBufSize) { UInt32 theBufSize = 0; char* theFormat = NULL; if ( inValueAsString == NULL || ioBufSize == NULL) return QTSS_BadArgument; if ( inType == qtssAttrDataTypeCharArray ) { // // If this data type is a string, copy the string into // the destination buffer UInt32 theLen = ::strlen(inValueAsString); // // First check to see if the destination is big enough if ((ioBuffer == NULL) || (*ioBufSize < theLen)) { *ioBufSize = theLen; return QTSS_NotEnoughSpace; } // // Do the string copy. Use memcpy for speed. ::memcpy(ioBuffer, inValueAsString, theLen); *ioBufSize = theLen; return QTSS_NoErr; } if (inType == qtssAttrDataTypeBool16) { // // The text "enabled" means true, anything else means false if (*ioBufSize < sizeof(Bool16)) { *ioBufSize = sizeof(Bool16); return QTSS_NotEnoughSpace; } Bool16* it = (Bool16*)ioBuffer; StrPtrLen theValuePtr(inValueAsString); if (kEnabledStr.EqualIgnoreCase(inValueAsString, ::strlen(inValueAsString))) *it = true; else *it = false; *ioBufSize = sizeof(Bool16); return QTSS_NoErr; } // // If this is another type, format the string into that type switch ( inType ) { case qtssAttrDataTypeUInt16: { theBufSize = sizeof(UInt16); theFormat = "%hu"; } break; case qtssAttrDataTypeSInt16: { theBufSize = sizeof(SInt16); theFormat = "%hd"; } break; case qtssAttrDataTypeSInt32: { theBufSize = sizeof(SInt32); theFormat = "%d"; } break; case qtssAttrDataTypeUInt32: { theBufSize = sizeof(UInt32); theFormat = "%u"; } break; case qtssAttrDataTypeSInt64: { theBufSize = sizeof(SInt64); theFormat = "%" _64BITARG_ "d"; } break; case qtssAttrDataTypeUInt64: { theBufSize = sizeof(UInt64); theFormat = "%" _64BITARG_ "u"; } break; case qtssAttrDataTypeFloat32: { theBufSize = sizeof(Float32); theFormat = "%f"; } break; case qtssAttrDataTypeFloat64: { theBufSize = sizeof(Float64); theFormat = "%f"; } break; case qtssAttrDataTypeTimeVal: { theBufSize = sizeof(SInt64); theFormat = "%" _64BITARG_ "d"; } break; default: return ConvertCHexStringToBytes(inValueAsString,ioBuffer,ioBufSize); } if (( ioBuffer == NULL) || (*ioBufSize < theBufSize )) { *ioBufSize = theBufSize; return QTSS_NotEnoughSpace; } *ioBufSize = theBufSize; ::sscanf(inValueAsString, theFormat, ioBuffer); return QTSS_NoErr; }
Bool16 IsHomeDirURL(StrPtrLen& theUrl) { StrPtrLen token = theUrl; token.Len = 2; return token.EqualIgnoreCase(StrPtrLen("/~")); }
// This determines if a URL in an HTTP request is actually // a server admin request. Bool16 IsAdminURL(StrPtrLen& theUrl) { StrPtrLen token = theUrl; token.Len = 15; return token.EqualIgnoreCase(StrPtrLen("/modules/admin/")); }
// This determines if an incoming request is an HTTP GET // request. Bool16 IsHTTPGet(StrPtrLen& theRequest) { StrPtrLen token = theRequest; token.Len = 3; return token.EqualIgnoreCase(StrPtrLen("GET")); }
UInt32 ReplaceSessionAndTransportHeaders(StrPtrLen* inResponse, iovec* outNewResponse, StrPtrLen* inNewSessionID, StrPtrLen* inNewTransportHeader, UInt32* outNewResponseLen) { static StrPtrLen sTransportHeader("Transport"); static StrPtrLen sSessionHeader("Session"); StringParser reqParser(inResponse); StrPtrLen theHeaderName; UInt32 curVecIndex = 0; outNewResponse[0].iov_base = inResponse->Ptr; *outNewResponseLen = 0; while (reqParser.GetDataRemaining() > 0) { reqParser.ConsumeWord(&theHeaderName); if (theHeaderName.EqualIgnoreCase(sTransportHeader.Ptr, sTransportHeader.Len)) { // // Mark off the length of the last section of the header outNewResponse[curVecIndex].iov_len = (UInt32) ((PointerSizedUInt) theHeaderName.Ptr) - ((PointerSizedUInt) outNewResponse[curVecIndex].iov_base ); *outNewResponseLen += outNewResponse[curVecIndex].iov_len; // // Insert the new Transport header outNewResponse[curVecIndex+1].iov_base = inNewTransportHeader->Ptr; outNewResponse[curVecIndex+1].iov_len = inNewTransportHeader->Len; *outNewResponseLen += inNewTransportHeader->Len; // // Move onto the next iovec curVecIndex+=2; // // Mark the start of the next section reqParser.GetThruEOL(NULL); outNewResponse[curVecIndex].iov_base = reqParser.GetCurrentPosition(); } else if (theHeaderName.EqualIgnoreCase(sSessionHeader.Ptr, sSessionHeader.Len)) { reqParser.ConsumeLength(NULL, 2); //skip over ": " // // Mark off the length of the last section of the header outNewResponse[curVecIndex].iov_len = (UInt32) ((PointerSizedUInt) reqParser.GetCurrentPosition()) - ((PointerSizedUInt) outNewResponse[curVecIndex].iov_base); *outNewResponseLen += outNewResponse[curVecIndex].iov_len; // // Insert new session ID outNewResponse[curVecIndex+1].iov_base = inNewSessionID->Ptr; outNewResponse[curVecIndex+1].iov_len = inNewSessionID->Len; *outNewResponseLen += inNewSessionID->Len; // // Move onto the next empty vec curVecIndex+=2; // // Move past the session ID. Be careful, there may be a ';' that we need to look for StrPtrLen theSessionID; reqParser.GetThruEOL(&theSessionID); outNewResponse[curVecIndex].iov_base = &theSessionID.Ptr[theSessionID.Len]; while (theSessionID.Ptr < outNewResponse[curVecIndex].iov_base) { if (*theSessionID.Ptr == ';') { outNewResponse[curVecIndex].iov_base = theSessionID.Ptr; break; } theSessionID.Ptr++; } } else reqParser.GetThruEOL(NULL); } // // Finish off the vec by marking the len of the last section outNewResponse[curVecIndex].iov_len = (UInt32) ((PointerSizedUInt) reqParser.GetCurrentPosition()) - ((PointerSizedUInt) outNewResponse[curVecIndex].iov_base ); // // And finish off the total length *outNewResponseLen += outNewResponse[curVecIndex].iov_len; // // Return the number of vecs written return curVecIndex+1; }
void RTSPRequest::ParseTransportHeader() { static char* sRTPAVPTransportStr = "RTP/AVP"; StringParser theTransParser(fHeaderDictionary.GetValue(qtssTransportHeader)); //transport header from client: Transport: RTP/AVP;unicast;client_port=5000-5001\r\n // Transport: RTP/AVP;multicast;ttl=15;destination=229.41.244.93;client_port=5000-5002\r\n // Transport: RTP/AVP/TCP;unicast\r\n // // A client may send multiple transports to the server, comma separated. // In this case, the server should just pick one and use that. while (theTransParser.GetDataRemaining() > 0) { (void)theTransParser.ConsumeWhitespace(); (void)theTransParser.ConsumeUntil(&fFirstTransport, ','); if (fFirstTransport.NumEqualIgnoreCase(sRTPAVPTransportStr, ::strlen(sRTPAVPTransportStr))) break; if (theTransParser.PeekFast() == ',') theTransParser.Expect(','); } StringParser theFirstTransportParser(&fFirstTransport); StrPtrLen theTransportSubHeader; (void)theFirstTransportParser.GetThru(&theTransportSubHeader, ';'); while (theTransportSubHeader.Len > 0) { // Extract the relevent information from the relevent subheader. // So far we care about 3 sub-headers if (!this->ParseNetworkModeSubHeader(&theTransportSubHeader)) { theTransportSubHeader.TrimWhitespace(); switch (*theTransportSubHeader.Ptr) { case 'r': // rtp/avp/??? Is this tcp or udp? case 'R': // RTP/AVP/??? Is this TCP or UDP? { if ( theTransportSubHeader.EqualIgnoreCase("RTP/AVP/TCP") ) fTransportType = qtssRTPTransportTypeTCP; break; } case 'c': //client_port sub-header case 'C': //client_port sub-header { this->ParseClientPortSubHeader(&theTransportSubHeader); break; } case 'd': //destination sub-header case 'D': //destination sub-header { static StrPtrLen sDestinationSubHeader("destination"); //Parse the header, extract the destination address this->ParseAddrSubHeader(&theTransportSubHeader, &sDestinationSubHeader, &fDestinationAddr); break; } case 's': //source sub-header case 'S': //source sub-header { //Same as above code static StrPtrLen sSourceSubHeader("source"); this->ParseAddrSubHeader(&theTransportSubHeader, &sSourceSubHeader, &fSourceAddr); break; } case 't': //time-to-live sub-header case 'T': //time-to-live sub-header { this->ParseTimeToLiveSubHeader(&theTransportSubHeader); break; } case 'm': //mode sub-header case 'M': //mode sub-header { this->ParseModeSubHeader(&theTransportSubHeader); break; } } } // Move onto the next parameter (void)theFirstTransportParser.GetThru(&theTransportSubHeader, ';'); } }