diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/ClientResolver/Resolver/src/CSIPOptionsHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/ClientResolver/Resolver/src/CSIPOptionsHandler.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,648 @@ +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// Name : CSIPOptionsHandler.cpp +// Part of : SIP Client Resolver +// Version : 1.0 +// + + + +#include +#include +#include "CSIPOptionsHandler.h" +#include "sdpcodecstringconstants.h" +#include "sipresponse.h" +#include "siprequest.h" +#include "uricontainer.h" +#include "sipuri.h" +#include "siphostport.h" +#include "sipcontenttypeheader.h" +#include "sipacceptheader.h" +#include "sdpdocument.h" +#include "sdporiginfield.h" +#include "sdpconnectionfield.h" +#include "sdpmediafield.h" +#include "sdpfmtattributefield.h" +#include "siperr.h" +#include "sdpcodecstringpool.h" +#include "sipstrings.h" +#include "sipstrconsts.h" + +_LIT8(KSdp, "sdp"); +_LIT8(KApplication, "application"); +_LIT8(KSessionName, "-"); +_LIT8(KOriginFieldUser, "-"); + +const TUint KResponse200 = 200; +const TInt KSdpExternalizeBufferExpandSize = 100; + + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::NewL +// ---------------------------------------------------------------------------- +// +CSIPOptionsHandler* CSIPOptionsHandler::NewLC(CSIPRequest& aRequest) + { + CSIPOptionsHandler* self = new(ELeave)CSIPOptionsHandler; + CleanupStack::PushL(self); + self->ConstructL(aRequest); + return self; + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::CSIPOptionsHandler +// ---------------------------------------------------------------------------- +// +CSIPOptionsHandler::CSIPOptionsHandler() + { + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::ConstructL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::ConstructL(CSIPRequest& aRequest) + { + RStringPool strPool = SdpCodecStringPool::StringPoolL(); + + iSdpNetType = strPool.StringF(SdpCodecStringConstants::ENetType, + SdpCodecStringPool::StringTableL()); + + iSdpIPv4Type = strPool.StringF(SdpCodecStringConstants::EAddressTypeIP4, + SdpCodecStringPool::StringTableL()); + + iSdpIPv6Type = strPool.StringF(SdpCodecStringConstants::EAddressType, + SdpCodecStringPool::StringTableL()); + + iRtpAvp = strPool.StringF(SdpCodecStringConstants::EProtocolRtpAvp, + SdpCodecStringPool::StringTableL()); + + iRtpmap = strPool.StringF(SdpCodecStringConstants::EAttributeRtpmap, + SdpCodecStringPool::StringTableL()); + + iApplication = strPool.StringF(SdpCodecStringConstants::EMediaApplication, + SdpCodecStringPool::StringTableL()); + + iSdpAccepted = SDPAccepted(aRequest); + // Create SDP document + iSdpDocument = CSdpDocument::NewL(); + if (iSdpAccepted) + { + iSdpDocument->SetSessionNameL(KSessionName); + // Origin field + TPtrC8 localHost; + RStringF hostType; + LocalHostL(aRequest,localHost,hostType); + CSdpOriginField* originField = CreateOriginFieldL(localHost,hostType); + iSdpDocument->SetOriginField(originField); + // Connection field + CSdpConnectionField* connectionField = + CSdpConnectionField::NewL(iSdpNetType,hostType,localHost); + iSdpDocument->SetConnectionField(connectionField); + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::~CSIPOptionsHandler +// ---------------------------------------------------------------------------- +// +CSIPOptionsHandler::~CSIPOptionsHandler () + { + delete iSdpDocument; + iSipAcceptHeaders.ResetAndDestroy(); + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::AddClientDataL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::AddClientDataL(CSdpDocument& aSdpDocument) + { + RPointerArray& mediaFields = aSdpDocument.MediaFields(); + for (TInt i=0; i < mediaFields.Count(); i++) + { + CSdpMediaField& newMediaField = *mediaFields[i]; + CSdpMediaField* existingField = FindMatchingField(newMediaField); + if (!existingField) + { + CSdpMediaField* clone = newMediaField.CloneL(); + CleanupStack::PushL( clone ); + AppendMediaFieldL( clone ); + CleanupStack::Pop( clone ); + } + else + { + AddAttributesL(newMediaField,*existingField); + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::AddClientDataL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::AddClientDataL( RPointerArray* + aMediaFields) + { + if ( aMediaFields->Count() > 0 ) + { + RPointerArray& mediaFields = *aMediaFields; + for (TInt i=0; i < mediaFields.Count(); i++) + { + CSdpMediaField* existingField = FindMatchingField( *mediaFields[i] ); + if ( !existingField ) + { + AppendMediaFieldL( mediaFields[i] ); + aMediaFields->Remove( i ); + } + else + { + AddAttributesL( mediaFields[i],*existingField ); + } + } + } + } + +// ----------------------------------------------------------------------------- +// CSIPOptionsHandler::AppendMediaFieldL +// ----------------------------------------------------------------------------- +// +void CSIPOptionsHandler::AppendMediaFieldL( CSdpMediaField* aMediafield ) + { + aMediafield->SetPortL(0); + UpdateFormatListL(*aMediafield); + iSdpDocument->MediaFields().AppendL(aMediafield); + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::CreateResponseL +// ---------------------------------------------------------------------------- +// +CSIPResponse* CSIPOptionsHandler::CreateResponseL( RArray& aUids, + MSipClients& aSipClients, + CSIPClientResolver2& aClientResolver2 ) + { + CSIPResponse* response = + CSIPResponse::NewLC(KResponse200, + SIPStrings::StringF(SipStrConsts::EPhraseOk)); + if (iSdpAccepted) + { + // Add Content-Type-header + CSIPContentTypeHeader* contentType = + CSIPContentTypeHeader::NewLC(KApplication,KSdp); + response->AddHeaderL(contentType); + CleanupStack::Pop(contentType); + // Encode and add content + CBufFlat* sdpBuf = CBufFlat::NewL(KSdpExternalizeBufferExpandSize); + CleanupStack::PushL(sdpBuf); + RBufWriteStream writeStream(*sdpBuf,0); + writeStream.PushL(); + iSdpDocument->EncodeL(writeStream); + writeStream.Pop(); + writeStream.Close(); + TPtr8 encodedSdp = sdpBuf->Ptr(0); + response->SetContent(encodedSdp.AllocL()); + CleanupStack::PopAndDestroy(sdpBuf); + } + AddAcceptToResponseL( *response, aUids, aSipClients, aClientResolver2 ); + CleanupStack::Pop(response); + return response; + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::AddAcceptToResponseL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::AddAcceptToResponseL( CSIPResponse& aResponse, + RArray& aUids, + MSipClients& aSipClients, + CSIPClientResolver2& aClientResolver2 ) + { + CollectHeadersL( aUids,aSipClients,aClientResolver2 ); + RemoveDuplicateAcceptHeaders(); + CSIPAcceptHeader* acceptHeader; + + for ( TInt i=iSipAcceptHeaders.Count()-1;i >= 0;i-- ) + { + acceptHeader = static_cast( iSipAcceptHeaders[ i ] ); + if ( acceptHeader->IsEmpty() ) + { + delete acceptHeader; + acceptHeader = NULL; + iSipAcceptHeaders.Remove( i ); + } + else + { + CSIPHeaderBase* header = iSipAcceptHeaders[i]; + aResponse.AddHeaderL( header ); + iSipAcceptHeaders.Remove( i ); + } + } + if ( iSipAcceptHeaders.Count() > 0 ) + { + iSipAcceptHeaders.ResetAndDestroy(); + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::CollectHeadersL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::CollectHeadersL( + RArray& aUids, + MSipClients& aSipClients, + CSIPClientResolver2& aClientResolver2 ) + { + for ( TInt i=0; i < aUids.Count(); i++ ) + { + MSipClient* client = aSipClients.GetByUID( aUids[i] ); + if ( client ) + { + CollectHeadersL( client ); + } + } + for ( TInt i=0; i < aClientResolver2.Clients().Count(); i++ ) + { + CSIPResolvedClient2* client2 = aClientResolver2.Clients()[i]; + if ( client2 ) + { + CollectHeadersL( client2 ); + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::RemoveDuplicateAcceptHeaders +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::RemoveDuplicateAcceptHeaders() + { + for (TInt i=0;i( iSipAcceptHeaders[ i ] ); + + for ( TInt j=iSipAcceptHeaders.Count() - 1;j>i;j-- ) + { + CSIPAcceptHeader* acceptHeaderT = + static_cast ( iSipAcceptHeaders[ j ] ); + + if ( ( ( acceptHeader->MediaType().Compare( + acceptHeaderT->MediaType()) == 0 ) && + ( acceptHeader->MediaSubtype().Compare( + acceptHeaderT->MediaSubtype() ) == 0 ) ) ) + { + delete acceptHeaderT; + acceptHeaderT = NULL; + iSipAcceptHeaders.Remove( j ); + } + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::CollectHeadersL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::CollectHeadersL( MSipClient* aSipClient ) + { + RPointerArray& headers = aSipClient->SIPHeaders(); + + for ( TInt i=0; i < headers.Count();i++ ) + { + if ( headers[i]->Name() == + SIPStrings::StringF( SipStrConsts::EAcceptHeader ) ) + { + CSIPHeaderBase* accept = headers[i]->CloneL(); + CleanupStack::PushL( accept ); + iSipAcceptHeaders.AppendL( accept ); + CleanupStack::Pop( accept ); + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::CollectHeadersL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::CollectHeadersL( CSIPResolvedClient2* aClient ) + { + RPointerArray contentTypes; + TRAPD(err, contentTypes = aClient->SupportedContentTypesL()); + if ( err == KErrNoMemory ) + { + User::Leave( err ); + } + if ( !err ) + { + CSIPOptionsHandler::PushLC(&contentTypes); + for ( TInt i=0; i < contentTypes.Count();i++ ) + { + HBufC8* text = contentTypes[i]->ToTextValueL(); + CleanupStack::PushL( text ); + RPointerArray acceptHeaders; + acceptHeaders = CSIPAcceptHeader::DecodeL( *text ); + CleanupStack::PopAndDestroy( text ); + text = NULL; + CSIPOptionsHandler::PushLC(&acceptHeaders); + CSIPAcceptHeader* accept = NULL; + for (TInt j=0;j < acceptHeaders.Count();j++) + { + accept = acceptHeaders[j]; + iSipAcceptHeaders.AppendL( accept ); + acceptHeaders[j] = NULL; + } + CleanupStack::Pop();//acceptHeaders + acceptHeaders.Reset(); + } + CleanupStack::Pop();//contentTypes + contentTypes.ResetAndDestroy(); + } + } + +// ----------------------------------------------------------------------------- +// CSIPOptionsHandler::PushLC +// ----------------------------------------------------------------------------- +// +void CSIPOptionsHandler::PushLC(RPointerArray* aArray) + { + CleanupStack::PushL(TCleanupItem(ResetAndDestroyArray,aArray)); + } + +// ----------------------------------------------------------------------------- +// CSIPOptionsHandler::ResetAndDestroyArray +// ----------------------------------------------------------------------------- +// +void CSIPOptionsHandler::ResetAndDestroyArray(TAny* anArray) + { + RPointerArray* array = + reinterpret_cast*>(anArray); + if (array) + { + array->ResetAndDestroy(); + } + } + +// ----------------------------------------------------------------------------- +// CSIPOptionsHandler::PushLC +// ----------------------------------------------------------------------------- +// +void CSIPOptionsHandler::PushLC(RPointerArray* aArray) + { + CleanupStack::PushL(TCleanupItem(ResetAndDestroy,aArray)); + } + +// ----------------------------------------------------------------------------- +// CSIPOptionsHandler::ResetAndDestroyArray +// ----------------------------------------------------------------------------- +// +void CSIPOptionsHandler::ResetAndDestroy(TAny* anArray) + { + RPointerArray* array = + reinterpret_cast*>(anArray); + if (array) + { + array->ResetAndDestroy(); + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::SDPAccepted +// ---------------------------------------------------------------------------- +// +TBool CSIPOptionsHandler::SDPAccepted(CSIPRequest& aRequest) + { + TSglQueIter iter = + aRequest.Headers(SIPStrings::StringF(SipStrConsts::EAcceptHeader)); + + while (iter) + { + CSIPHeaderBase* header = iter++; + CSIPAcceptHeader* accept = static_cast(header); + if (accept->MediaType().CompareF(KApplication) == 0 && + accept->MediaSubtype().CompareF(KSdp) == 0) + { + return ETrue; + } + } + + return EFalse; + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::FindMatchingField +// ---------------------------------------------------------------------------- +// +CSdpMediaField* CSIPOptionsHandler::FindMatchingField( + const CSdpMediaField& aMediaField) + { + for (TInt i=0; i < iSdpDocument->MediaFields().Count(); i++) + { + CSdpMediaField* mField = iSdpDocument->MediaFields()[i]; + if (mField && + aMediaField.Media() == mField->Media() && + aMediaField.Protocol() == mField->Protocol()) + { + if (aMediaField.Media() != iApplication) + { + // FormatList is compared only for "application" media type + return mField; + } + if (aMediaField.FormatList().CompareF(mField->FormatList()) == 0) + { + return mField; + } + } + } + return NULL; + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::AddAttributesL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::AddAttributesL( + CSdpMediaField& aSource, + CSdpMediaField& aDestination) + { + RPointerArray attributes = + aSource.FormatAttributeFields(); + + if (aSource.Protocol() == iRtpAvp && attributes.Count() > 0) + { + TBool updateFormatList = EFalse; + for (TInt i=0; i < attributes.Count(); i++) + { + CSdpFmtAttributeField* attribute = attributes[i]; + if (attribute->Attribute() == iRtpmap && + !HasMatchingFmtAttritbute(aDestination,*attribute)) + { + CSdpFmtAttributeField* clone = attribute->CloneL(); + CleanupStack::PushL(clone); + updateFormatList = + AppendFormatAttributeFieldsL( clone, + aDestination ); + CleanupStack::Pop(clone); + } + } + if (updateFormatList) + { + UpdateFormatListL(aDestination); + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::AddAttributesL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::AddAttributesL( + CSdpMediaField* aSource, + CSdpMediaField& aDestination) + { + RPointerArray attributes = + aSource->FormatAttributeFields(); + if (aSource->Protocol() == iRtpAvp && attributes.Count() > 0) + { + TBool updateFormatList = EFalse; + for (TInt i=0; i < attributes.Count(); i++) + { + if (attributes[i]->Attribute() == iRtpmap && + !HasMatchingFmtAttritbute(aDestination,*attributes[i])) + { + updateFormatList =AppendFormatAttributeFieldsL( attributes[i], + aDestination ); + attributes[i] = NULL; + } + } + if (updateFormatList) + { + UpdateFormatListL(aDestination); + } + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::AppendFormatAttributeFieldsL +// ---------------------------------------------------------------------------- +// +TBool CSIPOptionsHandler::AppendFormatAttributeFieldsL( + CSdpFmtAttributeField* aAttribute, + CSdpMediaField& aDestination ) + { + aDestination.FormatAttributeFields().AppendL(aAttribute); + return ETrue; + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::CreateOriginFieldL +// ---------------------------------------------------------------------------- +// +CSdpOriginField* CSIPOptionsHandler::CreateOriginFieldL( + const TDesC8& aLocalHost, + const RStringF& aHostType) const + { + TTime now; + now.UniversalTime(); + TInt64 rand = now.Int64(); + TInt64 sessionID = Math::Rand(rand); + return CSdpOriginField::NewL(KOriginFieldUser, + sessionID, + sessionID, + iSdpNetType, + aHostType, + aLocalHost); + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::LocalHostL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::LocalHostL( + CSIPRequest& aRequest, + TPtrC8& aLocalHost, + RStringF& aHostType) const + { + CURIContainer* requestURI = aRequest.RequestURI(); + if (!requestURI || !requestURI->IsSIPURI()) + { + User::Leave(KErrSIPInvalidURIType); + } + const CSIPHostPort& hostPort = requestURI->SIPURI()->HostPort(); + aLocalHost.Set(hostPort.Host()); + if (hostPort.HostType() == CSIPHostPort::ESIPIpv6) + { + aHostType = iSdpIPv6Type; + } + else + { + aHostType = iSdpIPv4Type; + } + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::HasMatchingFmtAttritbute +// ---------------------------------------------------------------------------- +// +TBool CSIPOptionsHandler::HasMatchingFmtAttritbute( + CSdpMediaField& aMedia, + const CSdpFmtAttributeField& aAttribute) + { + RPointerArray& attributes = + aMedia.FormatAttributeFields(); + + for (TInt i=0; i < attributes.Count(); i++) + { + if (aAttribute == *attributes[i]) + { + return ETrue; + } + } + + return EFalse; + } + +// ---------------------------------------------------------------------------- +// CSIPOptionsHandler::UpdateFormatListL +// ---------------------------------------------------------------------------- +// +void CSIPOptionsHandler::UpdateFormatListL(CSdpMediaField& aMedia) + { + RPointerArray& attributes = + aMedia.FormatAttributeFields(); + + if (aMedia.Protocol() == iRtpAvp && attributes.Count() > 0) + { + // Calculate length for new format list + TInt newFormatListLength = 0; + for (TInt i=0; i < attributes.Count(); i++) + { + newFormatListLength += attributes[i]->Format().Length(); + newFormatListLength++; // space + } + // Create new format list + HBufC8* newFormatListBuf = HBufC8::NewLC(newFormatListLength); + TPtr8 newFormatListPtr = newFormatListBuf->Des(); + for (TInt i=0; i < attributes.Count(); i++) + { + newFormatListPtr.Append(attributes[i]->Format()); + if (i < attributes.Count()-1) + { + newFormatListPtr.Append(' '); // space + } + } + aMedia.SetFormatListL(newFormatListPtr); + CleanupStack::PopAndDestroy(newFormatListBuf); + } + }