realtimenetprots/sipfw/ClientResolver/Resolver/src/CSIPOptionsHandler.cpp
changeset 0 307788aac0a8
child 3 dc4cddf5f2f8
--- /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 <e32math.h>
+#include <uri8.h>
+#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<CSdpMediaField>& 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<CSdpMediaField>* 
+																aMediaFields)
+    {
+    if ( aMediaFields->Count() > 0 )
+    	{
+    	RPointerArray<CSdpMediaField>& 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<TUid>& 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<TUid>& aUids,
+									  MSipClients& aSipClients,
+    								  CSIPClientResolver2& aClientResolver2 )
+    {
+    CollectHeadersL( aUids,aSipClients,aClientResolver2 );
+    RemoveDuplicateAcceptHeaders();
+	CSIPAcceptHeader* acceptHeader;
+	
+	for ( TInt i=iSipAcceptHeaders.Count()-1;i >= 0;i-- )
+		{
+		acceptHeader = static_cast<CSIPAcceptHeader*>( 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<TUid>& 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.Count();i++)
+		{
+		CSIPAcceptHeader* acceptHeader =
+		    static_cast<CSIPAcceptHeader*>( iSipAcceptHeaders[ i ] );
+
+		for ( TInt j=iSipAcceptHeaders.Count() - 1;j>i;j-- )
+			{
+			CSIPAcceptHeader* acceptHeaderT =
+				static_cast<CSIPAcceptHeader*> ( 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<CSIPHeaderBase>& 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<CSIPContentTypeHeader> 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<CSIPAcceptHeader> 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<CSIPContentTypeHeader>* aArray)
+    {
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArray,aArray));
+    }
+  
+// -----------------------------------------------------------------------------
+// CSIPOptionsHandler::ResetAndDestroyArray
+// -----------------------------------------------------------------------------
+//
+void CSIPOptionsHandler::ResetAndDestroyArray(TAny* anArray)
+	{
+    RPointerArray<CSIPContentTypeHeader>* array =
+        reinterpret_cast<RPointerArray<CSIPContentTypeHeader>*>(anArray);
+    if (array)
+        {
+        array->ResetAndDestroy();
+        }
+	}      
+  
+// -----------------------------------------------------------------------------
+// CSIPOptionsHandler::PushLC
+// -----------------------------------------------------------------------------
+//
+void CSIPOptionsHandler::PushLC(RPointerArray<CSIPAcceptHeader>* aArray)
+    {
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroy,aArray));
+    }
+  
+// -----------------------------------------------------------------------------
+// CSIPOptionsHandler::ResetAndDestroyArray
+// -----------------------------------------------------------------------------
+//
+void CSIPOptionsHandler::ResetAndDestroy(TAny* anArray)
+	{
+    RPointerArray<CSIPAcceptHeader>* array =
+        reinterpret_cast<RPointerArray<CSIPAcceptHeader>*>(anArray);
+    if (array)
+        {
+        array->ResetAndDestroy();
+        }
+	}      
+  
+// ----------------------------------------------------------------------------
+// CSIPOptionsHandler::SDPAccepted
+// ----------------------------------------------------------------------------
+//  
+TBool CSIPOptionsHandler::SDPAccepted(CSIPRequest& aRequest)
+    {
+	TSglQueIter<CSIPHeaderBase> iter = 
+        aRequest.Headers(SIPStrings::StringF(SipStrConsts::EAcceptHeader));
+
+	while (iter)
+		{
+		CSIPHeaderBase* header = iter++;
+		CSIPAcceptHeader* accept = static_cast<CSIPAcceptHeader*>(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<CSdpFmtAttributeField> 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<CSdpFmtAttributeField> 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<CSdpFmtAttributeField>& 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<CSdpFmtAttributeField>& 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);
+        }
+    }