diff -r 000000000000 -r 1bce908db942 natfw/natfwstunturnclient/src/cstunrelaybindingimplementation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/natfw/natfwstunturnclient/src/cstunrelaybindingimplementation.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,1316 @@ +/* +* 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 "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: +* +*/ + + + + +#include "stunassert.h" +#include "natfwunsaflog.h" +#include "natfwunsafmessagefactory.h" +#include "natfwunsafbindingrequest.h" +#include "natfwunsafallocaterequest.h" +#include "natfwunsafconnectrequest.h" +#include "natfwunsafsetactivedestinationrequest.h" +#include "natfwunsafsendindication.h" +#include "cstunrelaybindingimplementation.h" +#include "natfwstunbinding.h" +#include "cstunbindinginit.h" +#include "cstunbindinggetsharedsecret.h" +#include "cstunbindinggetaddress.h" +#include "cstunbindingactive.h" +#include "cstunbindingwaittoretry.h" +#include "mstunbindingobserver.h" +#include "cstuntransaction.h" +#include "stunutils.h" +#include "natfwstunclientdefs.h" +#include "cstunindicationtransmitter.h" +#include "natfwunsaftcprelaypacketfactory.h" + +// Attributes +#include "natfwunsafusernameattribute.h" +#include "natfwunsafxoronlyattribute.h" +#include "natfwunsafunknownattributesattribute.h" +#include "natfwunsafmagiccookieattribute.h" +#include "natfwunsafdataattribute.h" +#include "natfwunsafremoteaddressattribute.h" +#include "natfwunsafusecandidateattribute.h" +#include "natfwunsafpriorityattribute.h" +#include "natfwunsaficecontrollingattribute.h" +#include "natfwunsaficecontrolledattribute.h" +#include "natfwunsafalternateserverattribute.h" +#include "natfwunsafrealmattribute.h" +#include "natfwunsafnonceattribute.h" + + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::NewL +// --------------------------------------------------------------------------- +// +CSTUNRelayBindingImplementation* + CSTUNRelayBindingImplementation::NewL( CBinding& aBinding, + MSTUNBindingObserver& aClient, + RSocket& aSocket ) + { + + CSTUNRelayBindingImplementation* self = + new ( ELeave ) CSTUNRelayBindingImplementation( aBinding, aClient, aSocket ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::NewL - overloaded +// --------------------------------------------------------------------------- +// +CSTUNRelayBindingImplementation* + CSTUNRelayBindingImplementation::NewL( CBinding& aBinding, + MSTUNBindingObserver& aClient, + TUint aStreamId, + TUint aConnectionId, + MNcmConnectionMultiplexer* aMux ) + { + + CSTUNRelayBindingImplementation* self = + new ( ELeave ) CSTUNRelayBindingImplementation( aBinding, aClient, aStreamId, + aConnectionId, aMux ); + CleanupStack::PushL( self ); + self->ConstructL( ); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::CSTUNRelayBindingImplementation +// --------------------------------------------------------------------------- +// +CSTUNRelayBindingImplementation::CSTUNRelayBindingImplementation( + CBinding& aBinding, + MSTUNBindingObserver& aClient, + RSocket& aSocket ) : + CBindingImplementation( aClient, aBinding, aSocket ) + { + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::CSTUNRelayBindingImplementation +// --------------------------------------------------------------------------- +// +CSTUNRelayBindingImplementation::CSTUNRelayBindingImplementation( + CBinding& aBinding, + MSTUNBindingObserver& aClient, + TUint aStreamId, + TUint aConnectionId, + MNcmConnectionMultiplexer* aMux ) : + CBindingImplementation( aClient, aBinding, aStreamId, aConnectionId, aMux ) + { + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::ConstructL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::ConstructL() + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::ConstructL" ) + ClientL().AttachBindingL( iBinding ); + + iGetAddress = new ( ELeave ) CSTUNBindingGetAddress(); + iGetSharedSecret = + new ( ELeave ) CSTUNBindingGetSharedSecret( *iGetAddress ); + iInit = new ( ELeave ) CSTUNBindingInit( *iGetSharedSecret ); + iActive = new ( ELeave ) CSTUNBindingActive( *iGetSharedSecret ); + iWaitToRetry = new ( ELeave ) CSTUNBindingWaitToRetry( *iGetSharedSecret ); + iGetAddress->SetNeighbourStates( *iGetSharedSecret, + *iWaitToRetry, + *iActive ); + + iIndicationTx = CStunIndicationTransmitter::NewL( *iMux, + iStreamId, + iConnectionId ); + ChangeState( *iInit ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::~CSTUNRelayBindingImplementation +// --------------------------------------------------------------------------- +// +CSTUNRelayBindingImplementation::~CSTUNRelayBindingImplementation() + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::~CSTUNRelayBindingImplementation" ) + if ( iClient ) + { + iClient->DetachBinding( iBinding ); + } + + this->FreeRequestData(); + + delete iInit; + delete iGetSharedSecret; + delete iGetAddress; + delete iWaitToRetry; + delete iActive; + delete iIndicationTx; + + iSocket = NULL; + iMux = NULL; + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::~CSTUNRelayBindingImplementation exit" ) + } + +// ----------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::TimerExpiredL +// ----------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::TimerExpiredL() + { + iState->TimerExpiredL( *this ); + } + +// ----------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::LeaveFromTimerExpired +// ----------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::LeaveFromTimerExpired( TInt aError ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::LeaveFromTimerExpired" ) + __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument ); + + Terminate( aError ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::PublicAddressObtainedL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::PublicAddressObtainedL( + const TInetAddr& aAddress ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::PublicAddressObtainedL 1" ) + iState->PublicAddressReceivedL( *this, aAddress ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::PublicAddressObtainedL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::PublicAddressObtainedL( + const TInetAddr& aReflexiveAddr, const TInetAddr& aRelayAddr ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::PublicAddressObtainedL 2" ) + iState->PublicAddressReceivedL( *this, aReflexiveAddr, aRelayAddr ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::TransactionError +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::TransactionError( TInt aError, + CNATFWUNSAFUnknownAttributesAttribute* aUnknownAttr ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::TransactionError" ) + delete iUnknownAttr; + iUnknownAttr = aUnknownAttr; + + __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument ); + iState->TransactionError( *this, aError ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::TransactionEventOccurredL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::TransactionEventOccurredL( + TSTUNCallbackInfo::TFunction aEvent ) + { + __STUNTURNCLIENT_INT1( + "CSTUNRelayBindingImplementation::TransactionEventOccurredL event:", + aEvent ) + if ( ESetActiveDestinationRequest == iRequestType ) + { + *iTimerValue = iTransaction->TimerValue(); + } + + FreeRequestData(); + ChangeState( *iActive ); + ClientL().BindingEventOccurred( iBinding, aEvent ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::HandleTransactionError +// --------------------------------------------------------------------------- +// +TBool CSTUNRelayBindingImplementation::HandleTransactionError( TInt aError ) + { + __STUNTURNCLIENT_INT1( "HandleTransactionError, reason", aError ) + + const TInt KMaxErrorResponseCount = 3; + + __STUN_ASSERT_RETURN_VALUE( iRequest && aError != KErrNone, + EFalse ); + + delete iTransaction; + iTransaction = NULL; + iTransactionError = aError; + + if ( ( aError > 0 ) && ( ++iErrorResponseCount >= KMaxErrorResponseCount ) ) + { + iErrorResponseCount = 0; + return EFalse; + } + + CNATFWUNSAFAlternateServerAttribute* alternateServer = NULL; + HBufC8* realmValue = NULL; + + switch ( aError ) + { + case KErrTimedOut: + __STUNTURNCLIENT( + "CSTUNRelayBindingImplementation - KErrTimedOut" ) + //Clear iAddXorOnly as another address is tried + iAddXorOnly = EFalse; + return iClient && iClient->ObtainServerAddress( iServerAddress ); + + case E300TryAlternate: + // The client SHOULD attempt a new transaction to the server + // indicated in the ALTERNATE-SERVER attribute. + alternateServer = static_cast + ( iRequest->Attribute( CNATFWUNSAFAttribute::EAlternateServer ) ); + if ( alternateServer ) + { + iServerAddress = alternateServer->Address(); + return ETrue; + } + return EFalse; + + case E4XX: + return EFalse; + + case E401Unauthorized: + if ( iSharedSecret ) + { + CNATFWUNSAFRealmAttribute* realm = + static_cast + ( iRequest->Attribute( CNATFWUNSAFAttribute::ERealm ) ); + if ( realm || !iRealmFromResponse ) + { + // indicates that this was retry and it did not work. + // notify client -> unrecoverable error + return EFalse; + } + } + return ETrue; + + case E420UnknownAttributes: + //Remove the unknown attributes and retry + return iUnknownAttr != NULL; + + case E430StaleCredentials: + // Client used a short term credential that has expired so + // generate a new Shared Secret request + return iSharedSecret != NULL; + + case E431IntegrityCheckFailure: + { + TBool retry = EFalse; + TRAPD( err, retry = + ClientL().SharedSecretRejectedL( iBinding, + Username(), + *iSharedSecret ) ); + return err == KErrNone && retry; + } + + case E432MissingUsername: + //If missing USERNAME or MESSAGE-INTEGRITY, add them and retry + return !iRequest->Attribute( CNATFWUNSAFAttribute::EUsername ) || + !iSharedSecret; + + case E433UseTLS: + // If request was a Shared Secret request and wasn't sent over + // TLS, the client SHOULD retry the request with TLS. + return iSharedSecret != NULL; + + case E434MissingRealm: + if ( !iRequest->Attribute( CNATFWUNSAFAttribute::ERealm ) && + iSharedSecret ) + { + // use a long term credential and retry the request using the username + // and password associated with the REALM + return ETrue; + } + + TRAPD( err, realmValue = ( static_cast + ( iRequest->Attribute( CNATFWUNSAFAttribute::ERealm ) ) )-> + Value().AllocL() ); + if ( err || !realmValue ) + { + delete realmValue; + return EFalse; + } + + if ( KErrNone != realmValue->Compare( *iRealmFromResponse ) ) + { + // the client SHOULD retry using the username and + // password associated with the REALM in the response + iUseRealmFromResponse = ETrue; + delete realmValue; + return ETrue; + } + delete realmValue; + return EFalse; + + + case E435MissingNonce: + if ( iRequest->Attribute( CNATFWUNSAFAttribute::ENonce ) ) + { + return EFalse; + } + // retry using a nonce from error response + return ETrue; + + case E436UnknownUsername: + if ( iSharedSecret ) + { + return ETrue; + } + // If the username was collected from the user, alert the user. + return EFalse; + + case E437NoBindind: + // There is none yet in place + return EFalse; + + case E438StaleNonce: + if ( iRequest->Attribute( CNATFWUNSAFAttribute::ENonce ) ) + { + // retry using a nonce from error response + return ETrue; + } + return EFalse; + + case E439Transitioning: + // The client should reset the active destination, wait for + // 5 seconds and set the active destination to the new value. + return EFalse; + + case E442UnsupportedTransportProtocol: + + return EFalse; + + case E443InvalidIPAddress: + + return EFalse; + + case E444InvalidPort: + + return EFalse; + + case E445OperationForTCPOnly: + + return EFalse; + + case E446ConnectionAlreadyExists: + + return EFalse; + + case E486AllocationQuotaReached: + // The user or client is not authorized to request additional + // allocations. + return EFalse; + + case E500ServerError: + return ETrue; + + case E507InsufficientCapacity: + // The server cannot allocate a new port for this client as it has + // exhausted its relay capacity. + return EFalse; + + case E600GlobalFailure: + return EFalse; + + case ERetryAfterAddingXorOnly: + iAddXorOnly = ETrue; + return ETrue; + + default: + return STUNUtils::Is5xxResponse( aError ); + } + + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::IcmpError +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::IcmpError( const TInetAddr& aAddress ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::IcmpError" ) + if ( iTransaction && iServerAddress.CmpAddr( aAddress ) ) + { + //Try next address, or terminate with KErrTimedOut. + iTransaction->Terminate( KErrTimedOut ); + } + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::AllocateRequestL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::AllocateRequestL( TUint /*aRtoValue*/ ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::AllocateRequestL" ) + iRequestType = EAllocateRequest; + iState->SendRequestL( *this ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::SetActiveDestinationRequestL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::SetActiveDestinationRequestL( + const TInetAddr& aRemoteAddr, TUint32& aTimerValue ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SetActiveDestinationRequestL" ) + + iRequestType = ESetActiveDestinationRequest; + iRemoteAddr = aRemoteAddr; + iTimerValue = NULL; + iTimerValue = &aTimerValue; + iState->SendRequestL( *this ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::SendIndicationL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::SendIndicationL( + const TInetAddr& aRemoteAddr, const TDesC8& aData, + TBool /*aAddFingerprint*/ ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SendIndicationL" ) + + TNATFWUNSAFTransactionID transactionID; + ClientL().ObtainTransactionIDL( transactionID ); + + CNATFWUNSAFMessage* + indication = CNATFWUNSAFSendIndication::NewL( transactionID ); + CleanupStack::PushL( indication ); + + indication->AddAttributeL( CNATFWUNSAFDataAttribute::NewLC( aData ) ); + CleanupStack::Pop(); // CNATFWUNSAFDataAttribute + + indication->AddAttributeL( CNATFWUNSAFRemoteAddressAttribute::NewLC( + aRemoteAddr ) ); + CleanupStack::Pop(); // CNATFWUNSAFRemoteAddressAttribute + + + if ( iUnknownAttr ) + { + STUNUtils::RemoveUnknownAttributes( *indication, *iUnknownAttr ); + delete iUnknownAttr; + iUnknownAttr = NULL; + } + + if ( ETcpProtocol == ClientL().TransportProtocol() ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SendIndicationL TCP" ) + + CBufBase* message = indication->EncodeL(); + CleanupStack::PushL( message ); + CNATFWUNSAFTcpRelayPacket* packet = + CNATFWUNSAFTcpRelayPacket::NewLC( message->Ptr( 0 ), + CNATFWUNSAFTcpRelayPacket::EFrameTypeStun ); + + iIndicationTx->TransmitL( *packet ); + CleanupStack::PopAndDestroy( packet ); + CleanupStack::PopAndDestroy( message ); + } + else + { + iIndicationTx->TransmitL( *indication ); + } + + CleanupStack::PopAndDestroy( indication ); + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SendIndicationL exit" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::ConnectRequestL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::ConnectRequestL( + const TInetAddr& aRemoteAddr ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::ConnectRequestL" ) + iRemoteAddr = aRemoteAddr; + iRequestType = ETCPConnectRequest; + iState->SendRequestL( *this ); + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::ConnectRequestL end" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::StreamId +// --------------------------------------------------------------------------- +// +TUint CSTUNRelayBindingImplementation::StreamId() const + { + return iStreamId; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::ConnectionId +// --------------------------------------------------------------------------- +// +TUint CSTUNRelayBindingImplementation::ConnectionId() const + { + return iConnectionId; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::CancelRequest +// If transaction exists, delete it to stop using the socket. +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::CancelRequest() + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::CancelRequest" ) + if ( AddressResolved() ) + { + ChangeState( *iActive ); + } + else + { + //The initial request is canceled + ChangeState( *iInit ); + } + + delete iTransaction; + iTransaction = NULL; + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::CancelRequest end" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::Socket +// --------------------------------------------------------------------------- +// +const RSocket& CSTUNRelayBindingImplementation::Socket() const + { + return *iSocket; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::AddressResolved +// The most recent public address is kept also during a refresh. +// --------------------------------------------------------------------------- +// +TBool CSTUNRelayBindingImplementation::AddressResolved() const + { + return !iPublicAddr.IsUnspecified(); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::PublicAddr +// --------------------------------------------------------------------------- +// +const TInetAddr& CSTUNRelayBindingImplementation::PublicAddr() const + { + return iPublicAddr; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::AlternateServerAddr +// --------------------------------------------------------------------------- +// +const TInetAddr& CSTUNRelayBindingImplementation::AlternateServerAddr() const + { + return iServerAddress; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::RealmFromResponse +// --------------------------------------------------------------------------- +// +const HBufC8* CSTUNRelayBindingImplementation::RealmFromResponse() const + { + return iRealmFromResponse; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::HandleDataL +// Must NOT leave, if aData is not a STUN message! +// --------------------------------------------------------------------------- +// +HBufC8* CSTUNRelayBindingImplementation::HandleDataL( + const TDesC8& aData, TBool& aConsumed, TInetAddr& aRemoteAddr ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::HandleDataL" ) + aConsumed = EFalse; + TInt err( KErrNone ); + HBufC8* dataPointer = NULL; + CNATFWUNSAFMessage* msg = NULL; + CNATFWUNSAFTcpRelayPacket* relayPacket = NULL; + + if ( ETcpProtocol == ClientL().TransportProtocol() ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::HandleDataL - TCP" ) + + TRAP( err, relayPacket = DecodeTcpRelayMessageL( aData ) ); + CleanupStack::PushL( relayPacket ); + + if ( KErrNone == err && relayPacket && + CNATFWUNSAFTcpRelayPacket::EFrameTypeStun == relayPacket->Type() ) + { + TRAP( err, msg = DecodeMessageL( relayPacket->Data() ) ); + if ( KErrNoMemory == err ) + { + User::Leave( err ); + } + CleanupStack::PopAndDestroy( relayPacket ); + } + else if ( relayPacket && + CNATFWUNSAFTcpRelayPacket::EFrameTypeData == relayPacket->Type() ) + { + HBufC8* ptr = relayPacket->Data().AllocL(); + CleanupStack::PopAndDestroy( relayPacket ); + return ptr; + } + else if ( KErrNoMemory == err ) + { + User::Leave( err ); + } + else + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::HandleDataL -\ + Tcp framing invalid!" ) + + CleanupStack::PopAndDestroy( relayPacket ); + return NULL; + } + } + else + { + TRAP( err, msg = DecodeMessageL( aData ) ); + if ( KErrNoMemory == err ) + { + User::Leave( err ); + } + } + if ( msg ) + { + CleanupStack::PushL( msg ); + CNATFWUNSAFRealmAttribute* realm = static_cast( + msg->Attribute( CNATFWUNSAFAttribute::ERealm ) ); + if ( realm ) + { + delete iRealmFromResponse; + iRealmFromResponse = NULL; + const TDesC8& realmValue = ( static_cast( + msg->Attribute( CNATFWUNSAFAttribute::ERealm ) )->Value() ); + iRealmFromResponse = realmValue.AllocL(); + __STUNTURNCLIENT_STR8( "realm: ", *iRealmFromResponse ) + } + + CNATFWUNSAFNonceAttribute* nonce = static_cast( + msg->Attribute( CNATFWUNSAFAttribute::ENonce ) ); + if ( nonce ) + { + delete iNonce; + iNonce = NULL; + const TDesC8& nonceValue = ( static_cast( + msg->Attribute( CNATFWUNSAFAttribute::ENonce ) )->Value() ); + iNonce = nonceValue.AllocL(); + } + + // if aData contains data indication, decode it + if ( msg->Type() == CNATFWUNSAFMessage::EDataIndication && + KErrNone == err ) + { + const TDesC8& data = ( static_cast( + msg->Attribute( CNATFWUNSAFAttribute::EData ) )->Value() ); + + // Remote address is returned through reference + CNATFWUNSAFRemoteAddressAttribute* remoteAddress = + static_cast + ( msg->Attribute( CNATFWUNSAFAttribute::ERemoteAddress ) ); + + if( remoteAddress ) + { + aRemoteAddr = remoteAddress->Address(); + } + else + { + remoteAddress = NULL; + } + + CNATFWUNSAFMessage* msg_unsaf = NULL; + + dataPointer = data.AllocLC(); // to cleanupstack + + TRAP( err, msg_unsaf = DecodeMessageL( *dataPointer ) ); + CleanupStack::PushL( msg_unsaf ); + if ( KErrNoMemory == err ) + { + User::Leave( err ); + } + // if we have outstanding transaction, offer data to it + if ( iTransaction && iRequest && !err && msg_unsaf ) + { + if ( ValidateMsgType( msg_unsaf ) && + iRequest->TransactionID() == msg_unsaf->TransactionID() ) + { + // Data was encapsulated in data indication. + // Data is consumed. dataPointer is not needed. + aConsumed = ETrue; + iTransaction->ReceiveL( *msg_unsaf, *dataPointer ); + CleanupStack::PopAndDestroy( msg_unsaf ); + CleanupStack::PopAndDestroy( dataPointer ); + dataPointer = NULL; + } + } + + if ( dataPointer ) + { + // dataPointer is still valid. This means that message was not + // consumed, and data indication is ripped off from it. + // Message can also contain media data. + // Data indication is decapsulated out of that message. + CleanupStack::PopAndDestroy( msg_unsaf ); + CleanupStack::Pop( dataPointer ); + } + } + + // Data was NOT in encapsulated in data indication, so offer + // message to this client. + else if ( KErrNone == err && iTransaction && iRequest ) + { + if ( ValidateMsgType( msg ) && + iRequest->TransactionID() == msg->TransactionID() ) + { + aConsumed = ETrue; + iTransaction->ReceiveL( *msg, aData ); + } + } + else + { + // for PCLint approval + } + CleanupStack::PopAndDestroy( msg ); + } + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::HandleDataL end" ) + + // if there is not any outstanding transaction, data does not belong + // to this client. Pointer to decoded data IS NOT returned. + return dataPointer; + } + + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::STUNClient +// --------------------------------------------------------------------------- +// +const CSTUNClient* CSTUNRelayBindingImplementation::STUNClient() const + { + return iClient ? &iClient->STUNClient() : NULL; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::GetServerAddressL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::GetServerAddressL() + { + __ASSERT_ALWAYS( iServerAddress.IsUnspecified(), + User::Leave( KErrAlreadyExists ) ); + __ASSERT_ALWAYS( ClientL().ObtainServerAddress( iServerAddress ), + User::Leave( KErrNotFound ) ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::GetSharedSecretL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::GetSharedSecretL() + { + ClientL().ObtainSharedSecretL( iBinding ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::Username +// --------------------------------------------------------------------------- +// +const TDesC8& CSTUNRelayBindingImplementation::Username() const + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::Username" ) + if ( iRequest && iRequest->HasAttribute( CNATFWUNSAFAttribute::EUsername ) ) + { + return static_cast( + iRequest->Attribute( CNATFWUNSAFAttribute::EUsername ) )->Value(); + } + + return KNullDesC8; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::DetachClient +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::DetachClient() + { + iClient = NULL; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::StoreAddressL +// Transaction no longer needed. +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::StoreAddressL( + const TInetAddr& aReflexiveAddr, + const TInetAddr& aRelayAddr ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::StoreAddressL" ) + + iErrorResponseCount = 0; + iPublicAddr = aReflexiveAddr; + iRelayAddr = aRelayAddr; + ClientL().AddressResolvedL( iBinding ); + + FreeRequestData(); + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::StoreAddressL end" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::StoreAddressL +// Transaction no longer needed. +// This is kind of wrong functionality if this method get called. +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::StoreAddressL( + const TInetAddr& aPublicAddress ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::StoreAddressL" ) + + iErrorResponseCount = 0; + iPublicAddr = aPublicAddress; + ClientL().AddressResolvedL( iBinding ); + + FreeRequestData(); + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::StoreAddressL end" ) + } + +// ----------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::ChangeState +// ----------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::ChangeState( + CSTUNBindingState& aNewState ) + { + iState = &aNewState; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::Terminate +// Binding can be re-started with SendRequestL. +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::Terminate( TInt aError ) + { + __STUNTURNCLIENT_INT1( "CSTUNRelayBindingImplementation::Terminate, error:", aError ) + __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument ); + + NATFWUNSAF_INTLOG( "STUNRelayBinding terminated, reason", aError ) + + TInetAddr emptyAddr; + iPublicAddr = emptyAddr; + iServerAddress = emptyAddr; + iAddXorOnly = EFalse; + iErrorResponseCount = 0; + FreeRequestData(); + + if ( iState != iInit ) + { + __STUNTURNCLIENT( "Binding terminated" ) + + ChangeState( *iInit ); + TRAP_IGNORE( ClientL().BindingErrorL( Binding(), aError, ETrue ) ) + } + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::FreeRequestData +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::FreeRequestData() + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::FreeRequestData" ) + delete iTransaction; + iTransaction = NULL; + delete iUnknownAttr; + iUnknownAttr = NULL; + delete iRequest; + iRequest = NULL; + delete iSharedSecret; + iSharedSecret = NULL; + delete iRealmFromResponse; + iRealmFromResponse = NULL; + delete iNonce; + iNonce = NULL; + iRequestType = EUnknown; + iRemoteAddr.SetAddress( KAFUnspec ); + iICEAttributes = TICEAttributes(); + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::FreeRequestData end" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::IsWaitingSharedSecret +// --------------------------------------------------------------------------- +// +TBool CSTUNRelayBindingImplementation::IsWaitingSharedSecret() const + { + return iState == iGetSharedSecret; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::SharedSecretObtainedL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::SharedSecretObtainedL( + const TDesC8& aUsername, const TDesC8& aPassword ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SharedSecretObtainedL" ) + __STUN_ASSERT_L( ( aUsername.Length() > 0 && aPassword.Length() > 0 ) || + ( aUsername.Length() == 0 && aPassword.Length() == 0 ), KErrArgument ); + + + iState->SharedSecretObtainedL( *this, aUsername, aPassword ); + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SharedSecretObtainedL end" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::CreateBindingRequestL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::CreateBindingRequestL( + const TDesC8& aUsername, const TDesC8& aPassword ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::CreateBindingRequestL" ) + + delete iRequest; + iRequest = NULL; + + if ( IsSharedSecretRequired() && + ( aUsername.Length() == 0 || aPassword.Length() == 0 ) ) + { + Terminate( KErrAccessDenied ); + User::Leave( KErrAccessDenied ); + } + iTransactionError = KErrNone; + + HBufC8* newSharedSecret = aPassword.AllocL(); + delete iSharedSecret; + iSharedSecret = newSharedSecret; + + TNATFWUNSAFTransactionID transactionID; + ClientL().ObtainTransactionIDL( transactionID ); + + // Check the request type + switch( iRequestType ) + { + case ESendRequest: + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - BindingRequest" ) + iRequest = CNATFWUNSAFBindingRequest::NewL( transactionID ); + break; + + case EAllocateRequest: + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - AllocateRequest" ) + iRequest = CNATFWUNSAFAllocateRequest::NewL( transactionID ); + break; + + case ETCPConnectRequest: + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - ConnectRequest" ) + iRequest = CNATFWUNSAFConnectRequest::NewL( transactionID ); + break; + + case ESetActiveDestinationRequest: + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - SetActiveDestinationRequest" ) + iRequest = CNATFWUNSAFSetActiveDestinationRequest::NewL( + transactionID ); + break; + + // request not recognised + default: + User::Leave( KErrArgument ); + } + + + if ( aUsername.Length() > 0 ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - Add USERNAME attribute" ) + iRequest->AddAttributeL( CNATFWUNSAFUsernameAttribute::NewLC( + aUsername ) ); + CleanupStack::Pop(); // CNATFWUNSAFUsernameAttribute + } + + if ( iICEAttributes.iPriority > 0 ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - Add PRIORITY attribute" ) + iRequest->AddAttributeL( CNATFWUNSAFPriorityAttribute::NewLC( + iICEAttributes.iPriority ) ); + CleanupStack::Pop(); // CNATFWUNSAFPriorityAttribute + } + + if ( iICEAttributes.iUseCandidate ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - Add USE_CANDIDATE attribute" ) + iRequest->AddAttributeL( CNATFWUNSAFUseCandidateAttribute::NewLC() ); + CleanupStack::Pop(); // CNATFWUNSAFUseCandidateAttribute + } + + if ( iICEAttributes.iControlled > 0 ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - Add CONTROLLED attribute" ) + iRequest->AddAttributeL( CNATFWUNSAFIceControlledAttribute::NewLC( + iICEAttributes.iControlled ) ); + CleanupStack::Pop(); // CNATFWUNSAFIceControlledAttribute + } + + if ( iICEAttributes.iControlling > 0 ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - Add CONTROLLING attribute" ) + iRequest->AddAttributeL( CNATFWUNSAFIceControllingAttribute::NewLC( + iICEAttributes.iControlling ) ); + CleanupStack::Pop(); // CNATFWUNSAFIceControllingAttribute + } + + if ( !iRemoteAddr.IsUnspecified() ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - Add REMOTEADDRESS attribute" ) + iRequest->AddAttributeL( CNATFWUNSAFRemoteAddressAttribute::NewLC( + iRemoteAddr ) ); + CleanupStack::Pop(); // CNATFWUNSAFRemoteAddressAttribute + } + + if ( iUseRealmFromResponse ) + { + iRequest->AddAttributeL( CNATFWUNSAFRealmAttribute::NewLC( + *iRealmFromResponse ) ); + + CleanupStack::Pop(); // CNATFWUNSAFRealmAttribute + } + + if ( iUnknownAttr ) + { + STUNUtils::RemoveUnknownAttributes( *iRequest, *iUnknownAttr ); + delete iUnknownAttr; + iUnknownAttr = NULL; + } + + if ( iNonce ) + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL - Add NONCE attribute" ) + + iRequest->AddAttributeL( CNATFWUNSAFNonceAttribute::NewLC( + *iNonce ) ); + CleanupStack::Pop(); // CNATFWUNSAFNonceAttribute + } + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::\ + CreateBindingRequestL, exit" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::SendBindingRequestL +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::SendBindingRequestL() + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SendBindingRequestL" ) + + __STUN_ASSERT_L( !iTransaction, KErrAlreadyExists ); + __STUN_ASSERT_L( iRequest && iSharedSecret, KErrNotFound ); + // Happens if resolving returned unspecified address + + if ( iSocket ) + { + // old way to do it + iTransaction = CSTUNTransaction::NewL( *iRequest, + iServerAddress, + *iSharedSecret, + *iSocket, + ClientL().TimerProvider(), + ClientL().RetransmitInterval(), + *this, + KStunRelay, + ClientL().TransportProtocol() ); + } + + else + { + // New way, to be used + iTransaction = CSTUNTransaction::NewL( *iRequest, + iServerAddress, + *iSharedSecret, + iStreamId, + iConnectionId, + ClientL().TimerProvider(), + ClientL().RetransmitInterval(), + *this, + KStunRelay, + *iMux, + ClientL().TransportProtocol() ); + } + + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::SendBindingRequestL end" ) + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::WaitBeforeRetrying +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::WaitBeforeRetrying() + { + StartTimer( STUNUtils::EWaitBeforeRetryDuration ); + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::SetICESpecificAttributes +// --------------------------------------------------------------------------- +// +void CSTUNRelayBindingImplementation::SetICESpecificAttributes( + const TICEAttributes& aAttributes ) + { + iICEAttributes = aAttributes; + } + + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::Binding +// --------------------------------------------------------------------------- +// +const CBinding& CSTUNRelayBindingImplementation::Binding() + { + return iBinding; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::RelayAddr +// --------------------------------------------------------------------------- +// +const TInetAddr& CSTUNRelayBindingImplementation::RelayAddr() const + { + __STUNTURNCLIENT( "CSTUNRelayBindingImplementation::RelayAddr" ) + + return iRelayAddr; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::IsSharedSecretRequired +// --------------------------------------------------------------------------- +// +TBool CSTUNRelayBindingImplementation::IsSharedSecretRequired() const + { + return iTransactionError == E401Unauthorized || + iTransactionError == E430StaleCredentials || + iTransactionError == E431IntegrityCheckFailure || + iTransactionError == E432MissingUsername || + iTransactionError == E433UseTLS || + iTransactionError == E434MissingRealm; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::ClientL +// --------------------------------------------------------------------------- +// +MSTUNBindingObserver& CSTUNRelayBindingImplementation::ClientL() const + { + __ASSERT_ALWAYS( iClient, User::Leave( KErrNotFound ) ); + + return *iClient; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::DecodeMessageL +// --------------------------------------------------------------------------- +// +CNATFWUNSAFMessage* + CSTUNRelayBindingImplementation::DecodeMessageL( const TDesC8& aData ) const + { + CNATFWUNSAFMessageFactory* decoder = CNATFWUNSAFMessageFactory::NewLC(); + CNATFWUNSAFMessage* msg = decoder->DecodeL( aData ); + CleanupStack::PopAndDestroy( decoder ); + return msg; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::DecodeTcpRelayMessageL +// --------------------------------------------------------------------------- +// +CNATFWUNSAFTcpRelayPacket* + CSTUNRelayBindingImplementation::DecodeTcpRelayMessageL( const TDesC8& aData ) const + { + CNATFWUNSAFTcpRelayPacketFactory* decoder = + CNATFWUNSAFTcpRelayPacketFactory::NewLC(); + CNATFWUNSAFTcpRelayPacket* msg = decoder->DecodeL( aData ); + CleanupStack::PopAndDestroy( decoder ); + return msg; + } + +// --------------------------------------------------------------------------- +// CSTUNRelayBindingImplementation::ValidateMsgType +// --------------------------------------------------------------------------- +// +TBool CSTUNRelayBindingImplementation::ValidateMsgType( + CNATFWUNSAFMessage* aMsg ) const + { + if ( aMsg ) + { + return ( aMsg->Type() == CNATFWUNSAFMessage::EBindingResponse || + aMsg->Type() == CNATFWUNSAFMessage::EAllocateResponse || + aMsg->Type() == CNATFWUNSAFMessage::EBindingErrorResponse || + aMsg->Type() == CNATFWUNSAFMessage::EAllocateErrorResponse || + aMsg->Type() == CNATFWUNSAFMessage::EConnectResponse || + aMsg->Type() == CNATFWUNSAFMessage::EConnectErrorResponse || + aMsg->Type() == + CNATFWUNSAFMessage::ESetActiveDestinationResponse || + aMsg->Type() == + CNATFWUNSAFMessage::ESetActiveDestinationErrorResponse ); + } + return EFalse; + } + +