--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dvrengine/CommonRecordingEngine/src/CCRRTSPResponse.cpp Wed Sep 01 12:20:37 2010 +0100
@@ -0,0 +1,510 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: RTSP response parser and producer*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "CCRRtspResponse.h"
+#include "CRRTSPCommon.h"
+#include "videoserviceutilsLogger.h"
+
+// CONSTANTS
+const TInt KDVRMinRTSPResponseLen( 14 );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::CCRRtspResponse
+// C++ default constructor can NOT contain any code, that might leave.
+// -----------------------------------------------------------------------------
+//
+CCRRtspResponse::CCRRtspResponse()
+ : iStatusCode( ERTSPRespContinue ),
+ iServerPort( KErrNotFound ),
+ iSSRC( NULL, 0 )
+ {
+ // None
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CCRRtspResponse* CCRRtspResponse::NewL()
+ {
+ CCRRtspResponse* self = new( ELeave ) CCRRtspResponse();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CCRRtspResponse::ConstructL()
+ {
+ // None
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::~CCRRtspResponse
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CCRRtspResponse::~CCRRtspResponse()
+ {
+ LOG( "CCRRtspResponse::~CCRRtspResponse" );
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::TryParseL
+//
+// -----------------------------------------------------------------------------
+//
+void CCRRtspResponse::TryParseL( const TDesC8 &aString )
+ {
+ if ( aString.Length() < KDVRMinRTSPResponseLen )
+ {
+ LOG( "CCRRtspResponse::TryParseL(), Length less than minimum, Leaved: KErrUnderflow" );
+ User::Leave( KErrUnderflow );
+ }
+
+ // Copy the stuff into local variable:
+ delete iRtspText; iRtspText = NULL;
+ iRtspText = aString.AllocL();
+
+ const TInt KReplyHeaderOffset( KCRRTSPReplyHeader().Length() );
+ const TInt KStatusNumberLen( 5 );
+
+ // Try to find out if end of the command has been received
+ // "RTSP/1.0 XXX\r\n\r\n" at least..
+ TInt replyEndOffSet = aString.FindC( KCR2NewLines() );
+ if ( replyEndOffSet == KErrNotFound )
+ {
+ // Need to have more, do nothing yet.. except that some servers
+ // do not append 2 newlines to 404 or other error responses:
+ if ( !aString.Left( KReplyHeaderOffset ).CompareC( KCRRTSPReplyHeader() ) )
+ {
+ TPtrC8 statusNumberString(
+ aString.Mid( KReplyHeaderOffset, KStatusNumberLen ) );
+ TLex8 statusNumberLex( statusNumberString );
+ TInt statusCodeInteger( KErrNotFound );
+ User::LeaveIfError ( statusNumberLex.Val( statusCodeInteger ) ) ;
+ iStatusCode = static_cast<TResponseCode>( statusCodeInteger );
+ if ( iStatusCode != ERTSPRespOK &&
+ iStatusCode != ERTSPRespCreated &&
+ iStatusCode != ERTSPRespProxyAuthenticationRequired &&
+ iStatusCode != ERTSPRespUnauthorized )
+ {
+ // Was something else than ok or unauthorized-401
+ FindCSeqL();
+ LOG1( "CCRRtspResponse::TryParseL() out, with rtsp error code: %d", iStatusCode );
+ return;
+ }
+ }
+
+ LOG( "CCRRtspResponse::TryParseL() out, because response not complete" );
+ User::Leave( KErrUnderflow );
+ }
+
+ LOG1( "CCRRtspResponse::TryParseL(), replyEndOffSet: %d", replyEndOffSet );
+
+ // Find status code:
+ if ( iRtspText->Left( KReplyHeaderOffset ).CompareC( KCRRTSPReplyHeader() ) == 0 )
+ {
+ TPtrC8 statusNumberString( iRtspText->Mid(
+ KReplyHeaderOffset, KStatusNumberLen ) );
+ TLex8 statusNumberLex( statusNumberString );
+ TInt statusCodeInteger( KErrNotFound );
+ User::LeaveIfError ( statusNumberLex.Val( statusCodeInteger ) );
+ iStatusCode = ( TResponseCode )( statusCodeInteger );
+ }
+ else
+ {
+ LOG( "CCRRtspResponse::TryParseL(), Statuscode integer not found !" );
+ User::Leave( KErrNotSupported );
+ }
+
+ LOG1( "CCRRtspResponse::TryParseL(), iStatusCode: %d", iStatusCode );
+
+ FindContentL();
+ // Then find CSeq
+ FindCSeqL();
+ // Then find session id
+ FindSessionIdL();
+ // Then find server ports
+ FindServerPorts();
+ // Then find SSRC
+ FindSSRC();
+ // Then try finding rtp-info header if it was play reply
+ FindRTPInfoHeader();
+ // Find possible transport method
+ // IMPORTANT: should be done before parsing client port
+ FindTransport();
+ // Find possible client port
+ FindClientPorts();
+ if ( iServerPort == KErrNotFound && iClientPort != KErrNotFound )
+ {
+ LOG( "CCRRtspResponse::TryParseL(), using client port as server port -> UGLY!!" );
+ iServerPort = iClientPort ;
+ }
+ // Find destination address is existing
+ FindDestination();
+ // Try finding authentication
+ FindRTPAuthenticationL();
+ // Try to find range header
+ ParseRange();
+ // Try to find session-base header
+ FindContentBase();
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::StatusCode
+//
+// -----------------------------------------------------------------------------
+//
+CCRRtspResponse::TResponseCode CCRRtspResponse::StatusCode( void )
+ {
+ return iStatusCode;
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::FindServerPorts
+//
+// method that finds server port numeric value
+// -----------------------------------------------------------------------------
+//
+void CCRRtspResponse::FindServerPorts( void )
+ {
+ iServerPort = KErrNotFound;
+ TInt portNumberOffset( iRtspText->FindC( KCRServerPort ) );
+ if ( portNumberOffset != KErrNotFound )
+ {
+ const TInt KDVRPortNumberMaxLen ( 5 ) ;
+ TPtrC8 portNumberStr( iRtspText->Mid(
+ portNumberOffset + KCRServerPort().Length() + 1, KDVRPortNumberMaxLen ) );
+ TLex8 portNumberLex( portNumberStr );
+ if ( portNumberLex.Val( iServerPort ) != KErrNone )
+ { // something wrong?
+ LOG( "CCRRtspResponse::FindServerPorts(), portNumberLex.Val() != KErrNone" );
+ iServerPort = KErrNotFound;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::ServerPort
+//
+// method that returns server port numeric value
+// -----------------------------------------------------------------------------
+//
+TInt CCRRtspResponse::ServerPort( void )
+ {
+ return iServerPort;
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::FindSSRC
+//
+// -----------------------------------------------------------------------------
+//
+void CCRRtspResponse::FindSSRC( void )
+ {
+ LOG( "CCRRtspResponse::FindSSRC() in" );
+ TInt SSRCOffset( KErrNotFound );
+ iSSRC.Set( NULL, 0 );
+
+ if ( ( SSRCOffset = iRtspText->FindC( KCRSSRC ) ) != KErrNotFound )
+ {
+ TPtrC8 SSRCStr( iRtspText->Right(
+ ( iRtspText->Length() - SSRCOffset ) - 6 ) );
+ TInt SSRCLen( 0 );
+ for ( TInt i( 0 ); i < SSRCStr.Length(); i++ )
+ {
+ if ( TChar( SSRCStr[i] ).IsAlphaDigit() )
+ {
+ SSRCLen++;
+ }
+ else
+ {
+ iSSRC.Set( SSRCStr.Mid( 0, SSRCLen ) );
+ }
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::SSRC
+//
+// method that returns SSRC string
+// -----------------------------------------------------------------------------
+//
+TInt CCRRtspResponse::SSRC( TPtrC8& aSSRC )
+ {
+ if ( iSSRC.Ptr() != NULL )
+ {
+ aSSRC.Set( iSSRC );
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::FindRTPInfoHeader
+//
+// method that partially parses rtp info header
+// -----------------------------------------------------------------------------
+//
+void CCRRtspResponse::FindRTPInfoHeader( void )
+ {
+ TInt offset = iRtspText->FindC( KCRRtpInfo ); // "Rtp-Info: "
+ TInt url2OffSet( KErrNotFound );
+
+ iRTPInfoHeader.iFirstURL.Set( NULL , 0 );
+ iRTPInfoHeader.iFirstSeq = 0;
+ iRTPInfoHeader.iFirstTS = 0;
+ iRTPInfoHeader.iSecondURL.Set( NULL, 0 );
+ iRTPInfoHeader.iSecondSeq = 0;
+ iRTPInfoHeader.iSecondTS = 0;
+
+ if ( offset > 0 )
+ {
+ // Yes, there is header. That seems to be sucky to parse. We have delimiting
+ // characters ,; and nl and we may or may not find words url, seq and rtptime
+ // and maybe something else. We may be confident that there will be at max
+ // 2 url srings
+ offset += KCRRtpInfo().Length(); // add the len of "RTP-Info: "
+ TPtrC8 rtpInfoContent = iRtspText->Right( iRtspText->Length() - offset );
+ TInt urlOffSet = rtpInfoContent.FindC( KCRUrlStr );
+
+ for ( TInt i( 0 ); urlOffSet != KErrNotFound && i < 2; i ++ )
+ {
+ // At least one url string found
+ TPtrC8 urlContent( iRtspText->Right( iRtspText->Length() -
+ ( offset + urlOffSet + 4 ) ) );
+ // Above string now contains rest of the PLAY commands RTSP OK response
+ // so in practice there is 2 url-strings. If so, find the next one
+ // and cut our string
+ if ( ( url2OffSet = urlContent.FindC( KCRUrlStr ) ) > 0 )
+ {
+ urlContent.Set( urlContent.Left( url2OffSet ) );
+ }
+
+ // Ok, now there is only one url string in urlContent.
+ // then just find seq and ts
+ TInt seqOffSet = urlContent.FindC( KCRSeqStr );
+ if ( seqOffSet != KErrNotFound )
+ {
+ TPtrC8 seqContent( urlContent.Right( urlContent.Length() -
+ ( seqOffSet + KCRSeqStr().Length() ) ) );
+ TLex8 seqLex( seqContent );
+ if ( seqLex.Val( ( iRTPInfoHeader.iFirstURL.Length() == 0 )?
+ iRTPInfoHeader.iFirstSeq : iRTPInfoHeader.iSecondSeq,
+ EDecimal ) == KErrNone )
+ {
+ TInt tsOffSet( urlContent.FindC( KCRRtptimeStr ) );
+ if ( tsOffSet != KErrNotFound )
+ {
+ TPtrC8 tsContent( urlContent.Right( urlContent.Length() -
+ ( tsOffSet + KCRRtptimeStr().Length() ) ) );
+ TLex8 tsLex( tsContent );
+ tsLex.Val( ( iRTPInfoHeader.iFirstURL.Length() == 0 )?
+ iRTPInfoHeader.iFirstTS:
+ iRTPInfoHeader.iSecondTS, EDecimal );
+ }
+ }
+ else
+ {
+ urlContent.Set ( NULL , 0 ) ;
+ }
+ }
+ else
+ {
+ urlContent.Set ( NULL , 0 ) ;
+ }
+
+ if ( urlContent.Length() > 0 )
+ {
+ TInt semicolonOffSet( urlContent.Locate(';') );
+ const TInt KDVRMinSemicolonOffset ( 5 ) ;
+ if ( iRTPInfoHeader.iFirstURL.Length() == 0 && semicolonOffSet > KDVRMinSemicolonOffset )
+ {
+ iRTPInfoHeader.iFirstURL.Set(
+ urlContent.Mid( 0, semicolonOffSet ) );
+ }
+ else
+ {
+ const TInt KDVRURLBeginOffset ( 4 ) ;
+ iRTPInfoHeader.iSecondURL.Set(
+ urlContent.Mid( KDVRURLBeginOffset,
+ semicolonOffSet - KDVRURLBeginOffset ) );
+ }
+ }
+
+ // Then continue with next url
+ urlOffSet = url2OffSet;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::RTPInfoHeader
+//
+// method that returns rtp-info header content
+// -----------------------------------------------------------------------------
+//
+TInt CCRRtspResponse::RTPInfoHeader(
+ CCRRtspResponse::SRTPInfoHeader &aRTPInfoHeader )
+ {
+ if ( iRTPInfoHeader.iFirstURL.Length() == 0 )
+ {
+ return KErrNotFound;
+ }
+ else
+ {
+ aRTPInfoHeader.iFirstURL.Set( iRTPInfoHeader.iFirstURL );
+ aRTPInfoHeader.iFirstSeq = iRTPInfoHeader.iFirstSeq;
+ aRTPInfoHeader.iFirstTS = iRTPInfoHeader.iFirstTS;
+ aRTPInfoHeader.iSecondURL.Set( iRTPInfoHeader.iSecondURL );
+ aRTPInfoHeader.iSecondSeq = iRTPInfoHeader.iSecondSeq;
+ aRTPInfoHeader.iSecondTS = iRTPInfoHeader.iSecondTS;
+
+ return KErrNone;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCRRtspResponse::FindRTPAuthenticationL
+//
+// method that partially parses rtp authentication header
+// -----------------------------------------------------------------------------
+//
+void CCRRtspResponse::FindRTPAuthenticationL( void )
+ {
+ TInt endPos( KErrNotFound );
+
+ // First look for authorization method(basic / digest)
+ TInt pos = iRtspText->FindC( KCRAuthDigest );
+
+ // digest
+ if ( pos != KErrNotFound )
+ {
+ // Digest found, we can continue
+ LOG( "CCRRtspResponse::FindRTPAuthenticationL() Digest found" );
+
+ delete iAuthType;
+ iAuthType = NULL;
+ iAuthType = HBufC8::NewL( KCRAuthDigest().Length() );
+ iAuthType->Des().Copy( KCRAuthDigest );
+
+ // find "realm"
+ pos = iRtspText->FindC( KCRAuthRealm );
+ if ( pos != KErrNotFound )
+ {
+ LOG( "CCRRtspResponse::FindRTPAuthenticationL() realm found" );
+ pos = pos + KCRAuthRealm().Length(); // realm
+ endPos = iRtspText->Mid( pos ).LocateF( '"' );
+
+ if ( endPos != KErrNotFound )
+ {
+ TPtrC8 data = iRtspText->Mid( pos ).Left( endPos );
+ delete iRealm;
+ iRealm = NULL;
+ iRealm = HBufC8::NewL( data.Length() );
+ iRealm->Des().Copy( data );
+ }
+ }
+
+ // Find "nonce"
+ pos = iRtspText->FindC( KCRAuthNonce() );
+ if ( pos != KErrNotFound )
+ {
+ LOG( "CCRRtspResponse::FindRTPAuthenticationL() nonce found" );
+ pos = pos + KCRAuthNonce().Length(); // nonce
+ endPos = iRtspText->Mid( pos ).LocateF( '"' );
+ if ( endPos != KErrNotFound )
+ {
+ TPtrC8 nonceData = iRtspText->Mid( pos ).Left( endPos );
+ delete iNonce;
+ iNonce = NULL;
+ iNonce = HBufC8::NewL( nonceData.Length() );
+ iNonce->Des().Copy( nonceData );
+ }
+ }
+
+ // Find "opaque"(it seems that Darwin streaming server does not send this one)
+ pos = iRtspText->FindC( KCRAuthOpaque() );
+ if ( pos != KErrNotFound )
+ {
+ LOG( "CCRRtspResponse::FindRTPAuthenticationL() opaque found" );
+ pos = pos + KCRAuthOpaque().Length(); // opaque
+ endPos = iRtspText->Mid( pos ).LocateF( '"' );
+ if ( endPos != KErrNotFound )
+ {
+ TPtrC8 opaqData = iRtspText->Mid( pos ).Left( endPos );
+ delete iOpaque;
+ iOpaque = NULL;
+ iOpaque = HBufC8::NewL( opaqData.Length() );
+ iOpaque->Des().Copy( opaqData );
+ }
+ }
+ }
+
+ // basic
+ else
+ {
+ pos = iRtspText->FindC( KCRAuthBasic );
+
+ if ( pos != KErrNotFound )
+ {
+ LOG( "CCRRtspResponse::FindRTPAuthenticationL() Basic found" );
+
+ delete iAuthType;
+ iAuthType = NULL;
+ iAuthType = HBufC8::NewL( KCRAuthBasic().Length() );
+ iAuthType->Des().Copy( KCRAuthBasic );
+
+ // find "realm"
+ pos = iRtspText->FindC( KCRAuthRealm );
+
+ if ( pos != KErrNotFound )
+ {
+ LOG( "CCRRtspResponse::FindRTPAuthenticationL() realm found" );
+ pos = pos + KCRAuthRealm().Length(); // realm
+ endPos = iRtspText->Mid( pos ).LocateF( '"' );
+
+ if ( endPos != KErrNotFound )
+ {
+ TPtrC8 data = iRtspText->Mid( pos ).Left( endPos );
+ delete iRealm;
+ iRealm = NULL;
+ iRealm = HBufC8::NewL( data.Length() );
+ iRealm->Des().Copy( data );
+ }
+ }
+ }
+ }
+ }
+
+// End of File