realtimenetprots/sipfw/SIP/TransactionUser/src/UserAgentClient.h
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/TransactionUser/src/UserAgentClient.h	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,651 @@
+/*
+* Copyright (c) 2007-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          : UserAgentClient.h
+* Part of       : TransactionUser
+* Version       : SIP/6.0
+*
+*/
+
+
+
+
+/**
+ @internalComponent
+*/
+
+#ifndef USERAGENTCLIENT_H
+#define USERAGENTCLIENT_H
+
+// INCLUDES
+#include "sipsecobserver.h"
+#include "MSIPServerResolverObserver.h"
+#include "CUserAgent.h"
+
+// FORWARD DECLARATIONS
+class RStringF;
+class CSIPViaHeader;
+class CSIPSec;
+class CRouteSet;
+class CResolvingResults;
+
+// CLASS DECLARATION
+
+/**
+ * This is a base class for all UACs. 
+ */
+class CUserAgentClient :
+	public CUserAgent,
+	public MSIPServerResolverObserver,
+	public MSIPSecObserver
+	{
+public: // Destructor
+
+	virtual ~CUserAgentClient();
+
+public: // From CUserAgent
+
+	TBool IsUAS() const;
+
+protected: // From CUserAgent
+
+	virtual void CreateTransactionL() = 0;
+
+private:  // From CUserAgent
+
+	TRegistrationId RegistrationId() const;
+
+	/**
+	 * UAC detaches all references to the outgoing SIP message.
+	 * Depending on the current state of UAC; it may need to stop as in
+	 * certain states it cannot proceed without the outgoing SIP request.
+	 *
+	 * @post iOutgoingMsg = NULL
+	 */
+	virtual void DetachOutgoingMsg();
+
+public: // From MSIPServerResolverObserver
+
+	void CompletedL();
+
+	void ErrorOccured(TInt aError);	
+
+public:	// From MSIPSecObserver
+
+	void SIPSecCacheUpdated(TBool aSuccess);
+
+public: //New functions
+
+	/**
+	 * Handle a SIP request sent by upper layer. Request is checked, filled and
+	 * the remote address is determined and resolved. Transaction related parts
+	 * of the request are stored in CTransactionStore.
+	 *	 
+	 * @pre aReq != NULL
+	 *
+	 * @param aReq SIP request message. Ownership is transferred.
+	 * @param aRegistrationId Registration id by which TU tries to find an
+	 *	outbound proxy for the request.
+	 * @param aRemoteTarget Remote target of the request
+     * @param aResolve State the UAC will enter when it starts resolving URI
+	 */
+	void HandleSendRequestL(CSIPRequest* aReq,
+							TRegistrationId aRegisterId,
+							const CURIContainer& aRemoteTarget,
+                            const CUserAgentState& aResolve);
+
+	/**
+	 * Handle a SIP response received from network.
+	 *	 
+	 * @pre aResp != NULL
+	 *
+	 * @param aResp SIP response, ownership is transferred
+	 * @param aResolve State the UAC enters if it starts resolving URI
+	 * @param aWaitResponse State the UAC enters if it sends the request again
+	 * @param aWaitAckFromApp State InviteUAC enters if a 2xx response is
+	 *	passed to upper layer
+	 * @param aWaitTransactionToEnd State InviteUAC enters if an error response
+	 *	is passed to upper layer	 
+	 */	
+	virtual void ReceiveResponseL(CSIPResponse* aResp,						  
+						  const CUserAgentState& aResolve,
+						  const CUserAgentState& aWaitResponse,
+						  const CUserAgentState& aWaitAckFromApp,
+						  const CUserAgentState& aWaitTransactionToEnd) = 0;
+	
+	/**
+	 * Sets the value for CUserAgent::iOwnsOutgoingMsg
+	 *
+	 * @param aOwnsRequest ETrue: UAC owns the request in the send buffer
+	 *	(CUserAgent::iOutgoingMsg), EFalse: UAC doesn't own the request.
+	 */	
+	void SetRequestOwnership(TBool aOwnsRequest);
+
+	/**
+	 * Store the SIP response for asynchronous processing.
+	 *	 
+	 * @pre iIncomingMsg == NULL
+	 *
+	 * @param aResponse SIP response, ownership is transferred.
+	 */	
+	void StoreResponse(CSIPResponse* aResponse);
+
+	/**
+	 * Pick the next remote address and transport protocol from the resolved
+	 * addresses.
+	 *	 
+	 * @pre iOutgoingMsg != NULL && iResolvingResults != NULL
+	 *
+	 * @return ETrue if an address and protocol were found. EFalse if no more
+	 *	addresses are to try.
+	 */	
+	TBool SelectNextRemoteAddressL();
+
+	/**
+	 * The remote address has now been resolved and UAC can send the SIP
+	 * request to CTransaction.
+	 *
+	 * @param aNextState State where UAC moves after sending the request	 
+	 */	
+	void RemoteAddressResolvedL(const CUserAgentState& aNextState);	
+
+	/**
+	 * Returns information whether the UserAgent has passed a final response to
+	 * the upper layer.
+	 *
+	 * @return ETrue: UAC has already passed a final response, no more
+	 *	responses can be passed. EFalse: final response not passed.
+	 */
+	TBool FinalRespPassed() const;
+
+	/**
+	 * Dummy timer used to make a synchronous SIPSec call to work as
+	 * asynchronous, has completed.
+	 */
+	void SIPSecTimerExpiredL();
+
+	/**
+	 * SIPSec processing has been completed.
+	 */
+	TInt SIPSecReady(TBool aSuccess);
+
+	/**
+	 * SIPSec has completed updating the cache.
+	 *
+	 * @pre iIncomingMsg != NULL	 
+	 * @post iIncomingMsg == NULL
+	 *
+	 * @param aSuccess status of the authorized SIP request
+	 *		  ETrue: SIPSec has executed successfully
+	 *		  EFalse: otherwise
+	 * @param aResolve State the UAC enters if it starts resolving URI
+	 * @param aWaitResponse State the UAC enters if it sends the request again
+	 * @param aWaitAckFromApp State InviteUAC enters if a 2xx response is
+	 *	passed to upper layer
+	 * @param aWaitTransactionToEnd State InviteUAC enters if an error response
+	 *	is passed to upper layer	 
+	 *	upper layer	 
+	 */
+	void SIPSecCacheUpdatedL(TBool aSuccess,
+						     const CUserAgentState& aResolve,
+						     const CUserAgentState& aWaitResponse,
+							 const CUserAgentState& aWaitAckFromApp,
+							 const CUserAgentState& aWaitTransactionToEnd);
+
+	/**
+	 * Offers the aResp to SIPSec for processing.
+	 * Provisional responses are not offered.
+	 *
+	 * @pre iOutgoingMsg != NULL && iRemoteTarget != NULL
+	 *
+	 * @param aResp SIP response received from the network.
+     * @return ETrue  SIPSec processes the response asynchronously.     
+     *		   EFalse SIPSec has synchronously processed the response.     
+	 */
+	TBool PassResponseToSIPSecL(CSIPResponse& aResp);
+
+    /**
+	 * If UAC has more remote addresses to try, updates the SIP request and
+	 * sends it to the next address using a new CTransaction object.
+	 *
+	 * @param aError Reason why the next address will be tried. If aError is
+	 *	KErrNone, aResp must have a SIP response. If aError is not KErrNone,
+	 *	aResp must be NULL.
+	 * @param aResolve State which UAC will enter if it decides to resolve the
+	 *	outbound proxy.
+	 * @param aWaitResponse State which UAC enters if it decides to send
+	 *	request to the next ip-address.
+	 * @param aResp If transaction ended because of SIP response, this is the
+	 *	response. Ownership is transferred if TryNextAddressL returns ETrue.
+     * @return value ETrue if the request will be sent to next address.
+     *	Ownership of aResp has been taken.
+	 *	EFalse If request won't be sent again. Ownership of aResp has not been
+	 *	taken.
+	 */
+	TBool TryNextAddressL(TInt aError,
+						  const CUserAgentState& aResolve,
+						  const CUserAgentState& aWaitResponse,
+						  CSIPResponse* aResp = NULL);
+
+	/**
+	 * UAC receives a response from network. Determines whether UAC should
+	 * send the original request again, possibly to another address, or should
+	 * UAC pass the response to upper layer.
+	 *
+	 * @pre aResp != NULL	 
+	 *
+	 * @param aResp SIP response. If UAC sends the original request again, the
+	 *	ownership of aResp is transferred.
+	 * @param aResolve State which UAC enters if it decides to resolve the
+	 *	outbound proxy.
+	 * @param aWaitResponse State which UAC enters if it decides to send
+	 *	request to the next ip-address.
+	 * @return ETrue: UAC sends the request again and aResp isn't passed to
+	 *	upper layer. Ownership of aResp has been taken.
+	 *	EFalse: aResp should be passed to upper layer and it's ownership has
+	 *  not been taken.
+	 */
+	TBool ShouldUaTryAgainL(CSIPResponse* aResp,
+						    const CUserAgentState& aResolve,
+						    const CUserAgentState& aWaitResponse);
+
+	/**
+	 * CTransaction has ended before a final response was received
+	 *
+	 * @param aReason Reason why CTransaction ended
+	 * @param aResolve State which UAC will enter if it decides to resolve URI
+	 * @param aWaitResponse State which UAC enters if it decides to send
+	 *	request to the next ip-address.	 
+	 */    
+	void TransactionEndsWithoutFinalResponseL(TInt aReason,
+									 const CUserAgentState& aResolve,
+									 const CUserAgentState& aWaitResponse);
+
+    /**
+	 * Remove message headers from CTransactionStore, so that in case a
+     * retransmission of a response is received, it will be dropped.
+     * This is required when ClientTransaction terminates before SIPSec has
+     * completed adding authentication parameters to the request.	 
+	 */
+    void IgnoreResponseRetransmissionsL();	
+
+    /**
+	 * Cancel a pending asynchronous request issued to SIPSec.	 
+	 */
+    void CancelSIPSecRequest();
+
+	/**
+	 * Stores the remote target, replacing the possibly existing value.
+	 *
+	 * @param aRemoteTarget Remote target
+	 */
+	void StoreRemoteTargetL(const CURIContainer& aRemoteTarget);	
+
+	/**
+	 * Handle the situation when resolving address has failed.
+	 *	 
+	 * @param aResolve State which UAC will enter if it decides to resolve
+	 *	another address
+	 * @param aWaitResponse State which UAC enters if it decides to send
+	 *	request to the next ip-address.	 
+	 */							  
+	void HandleResolvingFailure(const CUserAgentState& aResolve,
+						  		const CUserAgentState& aWaitResponse);
+
+    /**
+	 * Returns the next hop address.	 
+	 */
+	const TInetAddr& NextHopIP() const;
+	
+protected:
+
+	CUserAgentClient(CUserAgentCreateParams& aParams,
+					 MSipUriResolver& aResolver,
+					 CSIPSec& aSIPSec,
+					 TUint32 aCSeqNumber);
+
+	void ConstructL();	
+
+	/**
+	 * Fills new Via header with branch, to the aReq.
+	 * Host part will be filled later by ConnectionMgr.
+	 *
+	 * @post aReq has one Via header
+	 * @param aReq SIP request
+	 * @param aBranch The branch value to put into the Via-header.
+	 *		  If this is an empty string, a new branch is generated.
+	 */
+	void FillNewViaL(CSIPRequest& aReq, RStringF aBranch) const;
+
+    /**
+	 * Stores the Request-URI of aReq into iRequestUri member. If iRequestUri
+	 * already had a value, it is replaced with the new value.
+	 *
+	 * @pre aReq.RequestURI() != NULL
+	 * @post iRequestUri != NULL
+	 *
+	 * @param aReq SIP request
+	 */
+	void StoreRequestUriL(CSIPRequest &aReq);
+
+	/**
+	 * Updates the SIP request, so it can be re-sent after modifying it, or
+	 * after obtaining another address.
+	 * Current Via is removed and an updated Via with a new branch and
+	 * transport to match the new remote address. CSeq is always updated.	 
+	 *
+	 * @pre iOutgoingMsg != NULL
+	 * @post The request in iOutgoingMsg has new Via branch & CSeq number
+	 */
+	void UpdateViaAndCSeqL() const;
+
+	/**
+	 * Updates transaction object and some SIP message headers to the
+	 * CTransactionStore.
+	 *
+	 * @param aReq SIP request from where a certain headers are updated to
+	 *	the store. If NULL, the headers are not updated.
+	 */
+	void UpdateInfoToStoreL(CSIPRequest* aReq) const;
+
+	/**
+	 * Sends the SIP request in the send buffer (CUserAgent::iOutgoingMsg) to
+	 * network. If the request is ACK, it is sent directly with CTransmitter.
+	 * Other requests are sent using CTransaction.
+	 *
+	 * @pre iOutgoingMsg != NULL
+	 */
+	void SendRequestToNetworkL();
+
+	/**
+	 * Passes the response to upper layer, except 100 response.	 
+	 *
+	 * @pre aResp != NULL, iFinalRespPassed == EFalse	 
+	 *
+	 * @param aResp SIP response, ownership is transferred
+	 * @param aUserAgent If non-NULL, points to UserAgent which has aTimer
+	 * @param aTimer If non-NULL, points to timer that will be stopped
+	 */
+	void PassRespToTransactionOwnerL(CSIPResponse* aResp,
+									 CUserAgent* aUserAgent=NULL,
+									 CUserAgentTimer* aTimer=NULL);
+	
+	/**
+	 * Copies the currently used remote address and transport protocol from the
+	 * given UAC (aSrc).
+	 *
+	 * @param aSrc UAC from which the address is copied
+	 */	
+	void CopyRemoteAddress(const CUserAgentClient& aSrc);
+
+	/**
+	 * Copies the route set and remote target from the given UAC (aSrc).
+	 *
+	 * @pre iRouteSet = NULL
+	 * @pre iRemoteTarget = NULL
+	 * @pre aSrc.iRouteSet != NULL
+	 * @pre aSrc.iRemoteTarget != NULL
+	 * @param aSrc UAC from which the route set and remote target are copied
+	 */
+	void CopyRouteSetAndRemoteTargetL(const CUserAgentClient& aSrc);    
+
+	/**
+	 * If UAC used a pre-configured route, but that failed, UAC tries to send
+	 * the request to outbound proxy (if one has been configured).
+	 *
+	 * @param aResolve State which UAC will enter if it decides to try and
+	 *	resolve the outbound proxy.
+	 * @return value ETrue if the request will be sent to next address,
+	 *	EFalse otherwise
+	 */
+	TBool TryOutboundProxyL(const CUserAgentState& aResolve);	
+
+	/**
+	 * Gets the next hop URI.
+	 *
+	 * @pre iRouteSet != NULL
+	 * @pre iRemoteTarget != NULL
+	 * @param aUseResolvedProxy, ETrue if resolved address of registration
+	 * @return CURIContainer& Next hop URI
+	 */
+	CURIContainer& NextHopL(TBool aUseResolvedProxy = EFalse) const;
+
+	/**
+	 * Resolves the next hop URI.
+	 *  
+	 * @param aCheckSigComp ETrue if sigcomp support is checked, EFalse
+	 * @param aUseResolvedProxy, ETrue if resolved address of registration
+	 *	otherwise.
+	 */
+	void ResolveNextHopL(TBool aCheckSigComp,TBool aUseResolvedProxy = EFalse);
+    
+	/**
+	 * Makes sure the CTransmitter is ready to be used for an updated request.
+	 *
+     * @param aNewTransactionId TransactionId that is given to the old
+     *  transaction.
+	 */
+    virtual void PrepareTxForNewRequestL(TTransactionId& aNewTransactionId) = 0;
+
+    /**
+	 * Let SIPSec fill the security parameters into outgoing request.
+	 *
+	 * @pre iOutgoingMsg != NULL, iRemoteTarget != NULL
+	 *
+	 * @return value ETrue if successful, EFalse in case of error
+	 */
+	TBool FillSecurityParamsL();
+
+protected: // Data
+
+	//SIP Security subsystem
+	CSIPSec& iSIPSec;
+
+	//CSeq sequence number to use in the SIP request, unless filled by upper
+	//layer.
+	TUint32 iCSeqNumber;
+
+	//Address where the request is sent
+	TInetAddr iRemoteAddr;
+
+	//ETrue if the transport of iRemoteAddr must not be changed from UDP
+	TBool iForceUDP;
+
+	//RegistrationId provided by the upper layer when it sent the request.	
+	TRegistrationId iRegisterId;
+
+    //Route set associated with the SIP request, owned.
+    CRouteSet* iRouteSet;
+
+	//Remote target of the SIP request, owned.
+    CURIContainer* iRemoteTarget;
+
+	//Resolver subsystem
+	MSipUriResolver& iResolver;
+
+	//Results obtained from resolving an URI. Owned.
+	CResolvingResults* iResolvingResults;
+	
+	//SIPSec Error
+	TInt iSipSecError;
+
+private:
+
+	/**
+	 * Fill the transaction related headers to the SIP request, unless they
+	 * have already been filled.
+	 *
+	 * @pre aReq must contain From header
+	 * @pre iRemoteTarget != NULL	 
+	 *
+	 * @param aReq SIP request which is filled	 
+	 */
+	void FillRequestL(CSIPRequest& aReq) const;
+
+	/**
+	 * Fills Call-ID header into aReq
+	 *
+	 * @param aReq SIP request	 
+	 */
+	void FillNewCallIdL(CSIPRequest& aReq) const;	
+
+	/**
+	 * Sets branch parameter to Via header.
+	 *
+	 * @post aVia Via header
+	 * @param aBranch The branch value to put into the Via-header.
+	 *		  If this is an empty string, a new branch is generated.
+	 */
+	void SetBranchL(CSIPViaHeader& aVia, RStringF aBranch) const;
+
+	/**
+	 * Processes the status of a SIPSec operation that can leave. If SIPSec
+	 * reported an error, UAC is stopped and HandleSIPSecErrorL leaves.
+	 *
+	 * @param aError If leave occurred from the SIPSec operation, this is the
+	 *				 leave code. Otherwise KErrNone.
+	 * @leave If aError != KErrNone, HandleSIPSecErrorL will leave.
+	 */
+	void HandleSIPSecErrorL(TInt aError);
+
+    /**
+	 * Client transaction terminated because of a timeout.
+     * If the request was sent compressed, send it uncompressed to the same
+     * address. Otherwise if there are other addresses to try, they are
+     * used and resolved if necessary.
+	 *
+	 * @param aResolve UAC will enter this state if it decides to resolve URI.
+	 *	Resolving isn't done if UAC already has more resolving results to try.
+	 * @param aWaitResponse UAC enters this state if it sends request again.
+	 * @return value ETrue if UAC sends the request again or resolves another
+     *  address. EFalse if UAC can't continue and will end.
+	 */
+    TBool HandleTimeoutL(const CUserAgentState& aResolve,
+    					 const CUserAgentState& aWaitResponse);	
+
+    /**
+	 * Updates Request-URI and Route-headers of the request when reverting to
+     * try the outbound proxy.
+	 *
+	 * @param aProxy Outbound proxy URI	 	 
+	 */
+    void UpdateRequestUriAndRouteL(const CURIContainer& aProxy);
+	
+	/**
+	 * Detach the current CTransaction object owned by the UserAgent. If the
+	 * CTransaction has reached Terminated state, it is freed using DeleteMgr,
+	 * otherwise it'll run independently of the UserAgent and when it enters
+	 * Terminated state, it'll delete itself using DeleteMgr.	 
+	 */	
+	void DetachCurrentTransactionL();
+
+	/**
+	 * Updates the SIP request and sends it using a new CTransaction object.
+	 *
+	 * The information of the current CTransaction object is removed from
+	 * CTransactionStore, and the old CTransaction is detached from UserAgent.
+	 * A new CTransaction instance is created and its information is added into
+	 * the CTransactionStore and the SIP request is sent to the new
+	 * CTransaction.
+	 *	 
+	 * @pre iOutgoingMsg != NULL
+	 *	 
+	 * @param aResolve UAC enters this state
+	 */
+	void UpdateAndSendRequestL(const CUserAgentState& aWaitResponse);
+
+	/**
+	 * Updates the SIP request, resolves the next hop URI and enters state
+	 * aResolve.
+	 *
+	 * @pre iOutgoingMsg != NULL
+	 *	 
+	 * @param aCheckSigComp ETrue if sigcomp is checked from aUri
+	 * @param aResolve UAC enters this state
+	 */
+	void UpdateAndResolveL(TBool aCheckSigComp,
+						   const CUserAgentState& aResolve);
+
+    /**
+	 * Stop with a previously stored error code. If a stored response exists,
+	 * pass it to upper layer before stopping.
+	 */
+	void StopWithLastError();	
+
+	/**
+	 * If the next hop is an outbound proxy, this function returns the outbound
+	 * proxy as descriptor. Otherwise returns an empty descriptor.	 
+	 *
+	 * @return const TDesC8& Outbound proxy, or empty descritor.
+	 */
+	const TDesC8& ProxyL() const;
+
+	/**
+	 * Determine if SIP messages should be handed to SIPSec or not.
+	 * @return ETrue if SIP messages are given to SIPSec, EFalse otherwise
+	 */
+	TBool UseSIPSec() const;
+
+private: // Data
+
+	// Indicates if UAC has passed a final response to MTransactionOwner
+	TBool iFinalRespPassed;
+
+	// Tells if any SIP response has been received.
+	TBool iResponseReceived;
+
+    // ETrue if UAC has attempted to resolve the outbound proxy, or sent a
+    // request to the outbound proxy. EFalse otherwise.
+    TBool iOutboundProxyHasBeenTried;
+
+	// Request-URI of the request, owned
+	CURIContainer* iRequestUri;
+
+    // Incremented each time a request and response are passed to SIPSec.
+    // Prevents infinite loop if the server always re-challenges.
+    TInt iSIPSecCounter;
+
+	// If transaction fails and UAC resolves the current URI again, the reason
+	// why transaction failed is stored here. If resolving the same URI fails,
+	// the stored error is passed to upper layer.
+    TInt iLastError;
+
+	// Normally EFalse. Temporarily set to ETrue to ignore SIPSec's callback
+	// when UAC cancels its pending SIPSec requests.
+	TBool iIgnoreSIPSecCallback;
+
+private: // For testing purposes
+
+#ifdef CPPUNIT_TEST	
+	friend class CUserAgentClient_Test;
+	friend class CTransactionUser_Test;
+	friend class CNormalUAC_ResolveAddress_Test;
+	friend class CNormalUAC_WaitResponse_Test;
+	friend class CInviteUAC_ResolveAddress_Test;
+	friend class CInviteUAC_WaitResponse_Test;
+	friend class CInviteUAC_WaitAckFromApp_Test;
+	friend class CInviteUAC_ResolveAckAddress_Test;
+	friend class CInviteUAC_SendingAck_Test;
+	friend class CInviteUAC_Start_Test;
+	friend class CUserAgent_Test;
+	friend class CTransactionStore_Test;	
+#endif
+
+	void __DbgTestInvariant() const;
+
+	};
+
+#endif // end of USERAGENTCLIENT_H
+
+// End of File