diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/ConnectionMgr/src/COutgoingRequestQueue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/SIP/ConnectionMgr/src/COutgoingRequestQueue.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,609 @@ +// Copyright (c) 2006-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 : COutgoingRequestQueue.cpp +// Part of : ConnectionMgr +// Version : SIP/5.0 +// + + + +#include "COutgoingRequestQueue.h" +#include "MOutgoingRequestQueueContext.h" +#include "CTransport.h" +#include "siprequest.h" +#include "sipstrings.h" +#include "sipstrconsts.h" +#include "sipcontactheader.h" +#include "sipviaheader.h" +#include "siptoheader.h" +#include "sipfromheader.h" +#include "uricontainer.h" +#include "sipuri.h" +#include "sipaddress.h" +#include "siphostport.h" +#include "TSIPTransportParams.h" +#include "sipstrings.h" +#include "sipstrconsts.h" +#include "SIPHeaderLookup.h" +#include "siperr.h" +#include + +const TInt KRequestQueueGranularity = 4; + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::NewLC +// ----------------------------------------------------------------------------- +// +COutgoingRequestQueue* COutgoingRequestQueue::NewL( + MOutgoingRequestQueueContext& aContext, + CSIPNATTraversalController& aNATTraversal, + RConnection& aConnection, + TUint32 aIapId ) + { + COutgoingRequestQueue* self = + new ( ELeave ) COutgoingRequestQueue( aContext, + aNATTraversal, + aConnection, + aIapId ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::~COutgoingRequestQueue +// ----------------------------------------------------------------------------- +// +COutgoingRequestQueue::~COutgoingRequestQueue() + { + iNATTraversal.FreeResources( iIapId ); + iRequestQueue.Close(); + iStrNATTraversalRequired.Close(); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::RequestComplete +// From MSIPNATTraversalRequestObserver +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::RequestComplete( + TUint32 aRequestId, + TInt aCompletionCode ) + { + TInt index = FindRequestQueueItemIndex( aRequestId ); + if ( index != KErrNotFound ) + { + Complete( iRequestQueue[ index ], aCompletionCode, EFalse ); + iRequestQueue.Remove( index ); + iRequestQueue.Compress(); + } + ActivatePendingRequests(); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::PublicAddrResolved +// From MSIPNATTraversalRequestObserver +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::PublicAddrResolved( + TUint32 aRequestId, + const TInetAddr& aPublicAddr ) + { + TInt index = FindRequestQueueItemIndex( aRequestId ); + if ( index != KErrNotFound ) + { + Update( iRequestQueue[ index ], aPublicAddr ); + iRequestQueue.Remove( index ); + iRequestQueue.Compress(); + } + ActivatePendingRequests(); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::UsagePermissionChanged +// From MSocketUsagePermissionObserver +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::UsagePermissionChanged( + RSocket& aSocket, + TBool aPermissionToUse ) + { + TInt lastIndex( iRequestQueue.Count() - 1 ); + for ( TInt i = lastIndex; i >= 0; i-- ) + { + TOutgoingRequestQueueItem& item = iRequestQueue[ i ]; + if ( item.Match( aSocket ) ) + { + // May lead to removal of the item + HandleUsagePermissionChange( item, aPermissionToUse ); + } + } + ActivatePendingRequests(); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::NATTraverseL +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::NATTraverseL( + const TSIPTransportParams& aParams, + CSIPRequest& aRequest, + TBool aForceUDP, + const TInetAddr& aAddr, + const CUri8* aOutboundProxy, + TUint aOrigTransport, + TRequestStatus &aStatus, + const TInetAddr& aLocalAddr ) + { + HBufC8* localAddrBuf = CTransport::ConvertInetAddrToTextL( aLocalAddr ); + CleanupStack::PushL( localAddrBuf ); + TUint localPort = ContactPortL( aRequest, *localAddrBuf ); + CleanupStack::PopAndDestroy( localAddrBuf ); + + if ( aRequest.Method() == SIPStrings::StringF( SipStrConsts::ERegister ) && + aRequest.To()->HasParam( iStrNATTraversalRequired ) && + !aLocalAddr.IsUnspecified() ) //Nat Traversal for both IPv6 and IPv4 addresses. + { + RemoveNATTraversalParameter( aRequest ); + TBool permissionToUse( EFalse ); + iLocalAddr = aLocalAddr; + RSocket& udpSocket = iContext.GetUdpSocketL( aParams, + aAddr, + localPort, + this, + permissionToUse ); + + TOutgoingRequestQueueItem queueItem( aParams, + aRequest, + aForceUDP, + aAddr, + localPort, + aOutboundProxy, + aOrigTransport, + aStatus, + udpSocket, + permissionToUse ); + + // If there's already active request for this particular UDP socket, + // request cannot be activated before existing request has completed. + if ( permissionToUse && !HasRequestForSocket( udpSocket, EFalse ) ) + { + IssueRequestL( queueItem ); + } + + iRequestQueue.AppendL( queueItem ); + + // Request status has to be set to pending before going to async. + // Set it when this synchronous execution path cannot leave anymore. + aStatus = KRequestPending; + } + else + { + iNATTraversal.UpdateNextHop( + aAddr, + const_cast( aParams ).NATBindingObserver() ); + + iContext.ContinueSendToTransportL( aParams, + aRequest, + aForceUDP, + aAddr, + localPort, + aOrigTransport, + aStatus, + EFalse ); + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::FreeResources +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::FreeResources( + MSIPNATBindingObserver& aSIPNATBindingObserver ) + { + iNATTraversal.FreeResources( aSIPNATBindingObserver ); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::CancelSend +// ----------------------------------------------------------------------------- +// +TBool COutgoingRequestQueue::CancelSend( TRequestStatus& aStatus ) + { + for ( TInt i = 0; i < iRequestQueue.Count(); i++ ) + { + TOutgoingRequestQueueItem& item = iRequestQueue[ i ]; + if ( item.Match( aStatus ) ) + { + iNATTraversal.Cancel( item.RequestId() ); + Complete( item, KErrSIPTransportFailure, EFalse ); + iRequestQueue.Remove( i ); + iRequestQueue.Compress(); + return ETrue; + } + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::Update +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::Update( + TOutgoingRequestQueueItem& aItem, + const TInetAddr& aPublicAddr ) + { + TRAPD( err, UpdateHeadersL( aItem, iLocalAddr, aPublicAddr ) ); + Complete( aItem, err, ETrue ); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::Complete +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::Complete( + TOutgoingRequestQueueItem& aItem, + TInt aCompletionCode, + TBool aPublicAddrResolved ) + { + if ( !HasRequestForSocket( aItem.Socket(), ETrue ) ) + { + // Notify if no pending requests exists for the socket + iContext.UdpSocketFree( aItem.Params(), + aItem.Addr(), + aItem.LocalPort(), + this, + aItem.Socket() ); + } + + if ( !aCompletionCode ) + { + TRAP( aCompletionCode, + iContext.ContinueSendToTransportL( aItem.Params(), + aItem.Request(), + aItem.ForceUDP(), + aItem.Addr(), + aItem.LocalPort(), + aItem.OrigTransport(), + aItem.Status(), + aPublicAddrResolved ) ); + } + + if ( aCompletionCode ) + { + iContext.RequestFailed( aItem.Status(), aCompletionCode ); + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::UpdateHeadersL +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::UpdateHeadersL( + TOutgoingRequestQueueItem& aItem, + const TInetAddr& aLocalAddr, + const TInetAddr& aPublicAddr ) + { + // Some NAT-aware proxies/registrars detect from the private IP address + // that the UA is behind a NAT and maintain a persistent TCP-connection. + // If the public address is used with TCP, + // these proxies/registrars will not maintain persistent TCP-connection. + if ( aItem.OrigTransport() == KProtocolInetUdp ) + { + HBufC8* localAddrBuf = + CTransport::ConvertInetAddrToTextL( aLocalAddr ); + CleanupStack::PushL( localAddrBuf ); + + HBufC8* publicAddrBuf = + CTransport::ConvertInetAddrToTextL( aPublicAddr ); + CleanupStack::PushL( publicAddrBuf ); + + TUint publicPort( aPublicAddr.Port() ); + + UpdateContactHeaderL( aItem.Request(), *localAddrBuf, + *publicAddrBuf, publicPort ); + + UpdateViaHeaderL( aItem.Request(), *publicAddrBuf, publicPort ); + + CleanupStack::PopAndDestroy( publicAddrBuf ); + CleanupStack::PopAndDestroy( localAddrBuf ); + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::UpdateContactHeaderL +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::UpdateContactHeaderL( + CSIPMessage& aMessage, + const TDesC8& aLocalAddr, + const TDesC8& aPublicAddr, + TUint aPublicPort ) + { + if ( aMessage.HasHeader( + SIPStrings::StringF(SipStrConsts::EContactHeader) ) ) + { + TSglQueIter iter = + aMessage.Headers( + SIPStrings::StringF(SipStrConsts::EContactHeader) ); + CSIPHeaderBase* header = 0; + while ( ( header = iter++ ) != 0 ) + { + CSIPContactHeader* contact = + static_cast( header ); + CSIPAddress* sipAddr = contact->SIPAddress(); + + if ( sipAddr ) + { + CURIContainer& uriContainer = sipAddr->URI(); + if ( uriContainer.IsSIPURI() && + uriContainer.SIPURI()->HostPort().Host().Compare( + aLocalAddr ) == 0 ) + { + uriContainer.SIPURI()->HostPort().SetHostL( aPublicAddr ); + uriContainer.SIPURI()->HostPort().SetPort( aPublicPort ); + } + } + } + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::UpdateViaHeaderL +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::UpdateViaHeaderL( + CSIPMessage& aMessage, + const TDesC8& aPublicAddr, + TUint aPublicPort ) + { + CSIPViaHeader* via = CTransport::TopViaHeader( &aMessage ); + if ( via ) + { + via->SentByHostPort().SetHostL( aPublicAddr ); + via->SentByHostPort().SetPort( aPublicPort ); + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::HandleUsagePermissionChange +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::HandleUsagePermissionChange( + TOutgoingRequestQueueItem& aItem, + TBool aPermissionToUse ) + { + aItem.SetPermissionToUse( aPermissionToUse ); + + if ( !aPermissionToUse && aItem.IsActiveRequest() ) + { + CancelSend( aItem.Status() ); + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::HasRequestForSocket +// ----------------------------------------------------------------------------- +// +TBool COutgoingRequestQueue::HasRequestForSocket( + RSocket& aSocket, + TBool aFindPendingRequest ) + { + for ( TInt i = 0; i < iRequestQueue.Count(); i++ ) + { + TOutgoingRequestQueueItem& item = iRequestQueue[ i ]; + if ( item.Match( aSocket ) && + !item.IsFailed() && + ( item.IsActiveRequest() ^ aFindPendingRequest ) ) + { + return ETrue; + } + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::CleanupFailedRequests +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::CleanupFailedRequests() + { + TInt lastIndex( iRequestQueue.Count() - 1 ); + for ( TInt i = lastIndex; i >= 0; i-- ) + { + TOutgoingRequestQueueItem& item = iRequestQueue[ i ]; + if ( item.IsFailed() ) + { + iContext.RequestFailed( item.Status(), item.Error() ); + iRequestQueue.Remove( i ); + iRequestQueue.Compress(); + } + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::ActivatePendingRequests +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::ActivatePendingRequests() + { + for ( TInt i = 0; i < iRequestQueue.Count(); i++ ) + { + TOutgoingRequestQueueItem& item = iRequestQueue[ i ]; + + // Activate if there's no other active request for the socket + // this pending request uses. + if ( !item.IsActiveRequest() && + !HasRequestForSocket( item.Socket(), EFalse ) && + item.PermissionToUse() ) + { + TRAPD( err, IssueRequestL( item ) ); + item.SetFailed( err ); + if ( err && !HasRequestForSocket( item.Socket(), ETrue ) ) + { + // If no more pending requests, inform that socket is free + iContext.UdpSocketFree( item.Params(), + item.Addr(), + item.LocalPort(), + this, + item.Socket() ); + } + } + } + CleanupFailedRequests(); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::IssueRequestL +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::IssueRequestL( TOutgoingRequestQueueItem& aItem ) + { + __ASSERT_ALWAYS( !HasRequestForSocket( aItem.Socket(), EFalse ), + User::Leave( KErrInUse ) ); + + TPtrC8 domain( KNullDesC8 ); + CSIPURI* toSIPURI = aItem.Request().To()->SIPAddress().URI().SIPURI(); + if ( toSIPURI ) + { + domain.Set( toSIPURI->HostPort().Host() ); + } + + // Have to do const cast for transport params to get binding observer + TUint32 requestId = iNATTraversal.ResolvePublicAddrL( + iIapId, + iConnection, + iLocalAddr, + domain, + aItem.Socket(), + aItem.Addr(), + const_cast( aItem.Params() ).NATBindingObserver(), + *this ); + + aItem.SetRequestId( requestId ); + aItem.SetFailed( KErrNone ); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::FindRequestQueueItemIndex +// ----------------------------------------------------------------------------- +// +TInt COutgoingRequestQueue::FindRequestQueueItemIndex( TUint32 aRequestId ) const + { + for ( TInt i = 0; i < iRequestQueue.Count(); i++ ) + { + if ( iRequestQueue[ i ].Match( aRequestId ) ) + { + return i; + } + } + return KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::RemoveNATTraversalParameter +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::RemoveNATTraversalParameter( CSIPRequest& aRequest ) + { + CSIPToHeader* to = aRequest.To(); + if ( to ) + { + to->DeleteParam( iStrNATTraversalRequired ); + } + CSIPFromHeader* from = aRequest.From(); + if ( from ) + { + from->DeleteParam( iStrNATTraversalRequired ); + } + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::ContactPortL +// ----------------------------------------------------------------------------- +// +TUint COutgoingRequestQueue::ContactPortL( + CSIPRequest& aRequest, + const TDesC8& aLocalAddr ) + { + if ( aRequest.HasHeader( + SIPStrings::StringF(SipStrConsts::EContactHeader) ) ) + { + TSglQueIter iter = + aRequest.Headers( + SIPStrings::StringF(SipStrConsts::EContactHeader) ); + CSIPHeaderBase* header = 0; + while ( ( header = iter++ ) != 0 ) + { + CSIPContactHeader* contact = + static_cast( header ); + CSIPAddress* sipAddr = contact->SIPAddress(); + + if ( sipAddr ) + { + CURIContainer& uriContainer = sipAddr->URI(); + if ( uriContainer.IsSIPURI() && + uriContainer.SIPURI()->HostPort().Host().Compare( + aLocalAddr ) == 0 && + uriContainer.SIPURI()->HostPort().HasPort() ) + { + return uriContainer.SIPURI()->HostPort().Port(); + } + } + } + } + return 0; + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::ConvertToSIPURIRollBack +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::ConvertToSIPURIRollBack(TAny* /*aDummy*/) + { + SIPHeaderLookup::SetConvertToSIPURI(ETrue); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::ConstructL +// ----------------------------------------------------------------------------- +// +void COutgoingRequestQueue::ConstructL() + { + _LIT8( KNATTraversalRequired, "nat_traversal_required" ); + + iStrNATTraversalRequired = + SIPStrings::Pool().OpenFStringL( KNATTraversalRequired ); + } + +// ----------------------------------------------------------------------------- +// COutgoingRequestQueue::COutgoingRequestQueue +// ----------------------------------------------------------------------------- +// +COutgoingRequestQueue::COutgoingRequestQueue( + MOutgoingRequestQueueContext& aContext, + CSIPNATTraversalController& aNATTraversal, + RConnection& aConnection, + TUint32 aIapId ) : + iContext( aContext ), + iNATTraversal( aNATTraversal ), + iConnection( aConnection ), + iIapId( aIapId ), + iRequestQueue( KRequestQueueGranularity ) + { + } + +// End of file