networkprotocols/dnsproxy/dnsproxyserver/src/dnsproxyqryhandler.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocols/dnsproxy/dnsproxyserver/src/dnsproxyqryhandler.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,573 @@
+// Copyright (c) 2008-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:
+// @internalTechnology
+//
+
+
+
+#include "dnsproxyengine.h"
+#include "dnsproxyqryhandler.h"
+#include "dnsproxyservconf.h"
+#include "dnsproxylistener.h"
+#include "dnsproxymsgproc.h"
+#include "dnsproxylog.h"
+#include <e32math.h>
+
+// Creates an instance of query handlers
+CDnsProxyQueryHandler* CDnsProxyQueryHandler::NewL(CDnsProxyEngine& aEngine, CDnsProxyListener& aListener)
+/**
+ * This is the method to create an instance of CDnsProxyQueryHandler
+ * @param	aEngine
+ *
+ * @internalTechnology
+*/
+	{
+	CDnsProxyQueryHandler* gResolver = new(ELeave)CDnsProxyQueryHandler(aEngine, aListener);
+	gResolver->ResetServerCount();
+	gResolver->iCurrentUplink = 0;
+	return gResolver;
+	}
+
+CDnsProxyQueryHandler::CDnsProxyQueryHandler(CDnsProxyEngine& aEngine, CDnsProxyListener& aListener):CActive(EPriorityStandard),iTimeout(TQueryTimeoutLinkage::TimeoutL),iProxyEngine(aEngine),iListener(aListener)
+/**
+ * Constructor and adds active object into active scheduler
+ * @param aEngine - reference to CDnsProxyEngine
+ *
+ * @internalTechnology
+ **/
+	{
+	CActiveScheduler::Add(this);
+	}
+
+/*
+ *  destructor and releases all the resources
+ * */
+CDnsProxyQueryHandler::~CDnsProxyQueryHandler()
+/**
+ * Destructor method cancel any pending operations and closes socket.
+ *
+ * @internalTechnology
+ **/
+	{
+	Cancel();
+	DeActivateSocket();
+	}
+
+
+//Invoked when request completes
+/*
+ * This function RunL will be invoked whenever request completes
+ *
+ * */
+void CDnsProxyQueryHandler::RunL()
+/**
+ * RunL of this active object is invoked when any pending read/write finishes.
+ *
+ * @internalTechnology
+ **/
+	{
+	__LOG3("CDnsProxyQueryHandler(%x)::RunL() Status(%d) and State(%d)", this, iStatus.Int(), GetActiveObjectState())		
+	if(iStatus.Int() == KErrNone)
+		{
+		if(GetActiveObjectState() == EInit)
+		   {
+		   SetTimer(iProxyEngine.GetConfig().iTimerVal);
+		   RunReader();
+		   }
+		else if(GetActiveObjectState() == EComplete)
+			{
+		    SetActiveObjectState(EInit);
+		    CancelTimer();
+		    SetQHandlerState(EFalse);
+		    iQueryContext->SetQueryState(EResolved);
+		    iQueryContext->SetDnsReplyMessage(iReply);
+			iProxyEngine.GetProxyListener()->SendTo(iQueryContext);
+		    //Query Finished from Handler Perspective
+			QueryDone();
+			//Process Next Query
+			ProcessNextQueryL();
+		   	}
+		 }
+	else
+		{
+		//Delete the Query context under processing
+    	iListener.DeleteQCtxFromListL(iQueryContext);
+    	//Complete the query
+		QueryDone();
+		//Process Next Query
+		ProcessNextQueryL();
+    	}	 
+	}
+
+void CDnsProxyQueryHandler::ProcessQueryL()
+/**
+ * This function gets called from the listener to start processing the query once
+ * it is assigned to the query handler.
+ * The function builds the dns server list, if there is not existing one.In case there
+ * are no DNS servers available/configured on the interfaces it sends DNS server failure
+ * as there is no uplink available.
+ * In case server count is zero or we are finished with all the configured servers
+ * reset the server count and send dns server failure message.
+ * Also check if there is anything else pending in the queue for processing.
+ *
+ * @internalTechnology
+ **/
+	{
+	/**
+	 * Build the server list here. This gives available DNS server addresses on the
+	 * already up interfaces.
+	 */
+	__LOG("\n CDnsProxyQueryHandler::ProcessQueryL Entry")
+	
+	if(iListener.GetConfiguredUplinkIap() != KErrNone)
+		{
+		//No Uplink available, hence send Dns server failure message
+    	__LOG("\n CDnsProxyQueryHandler::ProcessQueryL :No Uplink Available")
+    	SendDnsFailureL();
+    	return;
+		}
+    
+	TInt count = iProxyEngine.iProxyServer->GetServerCount();
+	if((count == 0) || (iListener.GetUplinkIap() != iCurrentUplink))
+		{
+		__LOG("\n CDnsProxyQueryHandler::ProcessQueryL Server Count is Zero")
+		iCurrentUplink = iListener.GetUplinkIap();
+		iProxyEngine.iProxyServer->BuildGlobalDnsServerListL(iCurrentUplink);
+		count = iProxyEngine.iProxyServer->GetServerCount();
+		__LOG1("\n CDnsProxyQueryHandler::ProcessQueryL Server Count is :%d", count)
+		}
+	//In case count is greater than zero do further processing else send dns failure message
+	if (count > 0)
+		{
+		TDnsServerInfo* info = NULL;
+		do 
+			{
+			//Get DNS server information from the list
+			info = iProxyEngine.iProxyServer->GetDnsServerInfo(iCurServer);
+
+			//coverity[new_values]
+			if(info)
+				{
+				//Set Uplink connection information in context
+				iListener.SetUplinkConnectionInfo(info->iConnInfo);
+				//Attach to given Uplink information 
+				TInt err = iListener.ActivateUplink();
+				if(err == KErrNone)
+					{
+					//Activate the socket function
+					ActivateSocketL();
+					//Send Query to Dns server address
+					SendQuery(info->iAddr);
+					}
+				else
+					{
+					//In case uplink is down, send Dns failure
+					__LOG("\n CDnsProxyQueryHandler::ProcessQueryL Unable to activate uplink")
+					SendDnsFailureL();
+					}
+				break;
+				}
+			else
+				{
+				//Loop through the available list
+				iCurServer++;
+				if(iCurServer == count)
+					{
+					__LOG("\n CDnsProxyQueryHandler::ProcessQueryL Invalid Uplinks")
+					ResetServerCount();	
+					SendDnsFailureL();
+					}
+					
+				}
+			}
+		//coverity[dead_error_line]
+		//coverity[dead_error_condition]
+		while(info != NULL && iCurServer < count);
+		}
+    else
+    	{
+    	//No Uplink available, hence send Dns server failure message
+    	__LOG("\n CDnsProxyQueryHandler::ProcessQueryL :No Uplink Available")
+    	SendDnsFailureL();
+    	}		
+	__LOG("\n CDnsProxyQueryHandler::ProcessQueryL Exit")
+	}
+			
+//Method to cancel outstanding request of the active object
+void CDnsProxyQueryHandler::DoCancel()
+/**
+ * This method is an implementation of DoCancel method of an active object
+ * Cancels pending read/ write operations and cancel the timer if active.
+ *
+ * @internalTechnology
+ **/
+	{
+	if (GetQHandlerState() != EFalse)
+		{
+		if(GetActiveObjectState() == EInit)
+			{
+		    iSocket.CancelSend();
+			}
+		else
+			{
+			CancelTimer();
+			iSocket.CancelRecv();
+			}
+		}
+	}
+
+
+void CDnsProxyQueryHandler::CancelTimer()
+/**
+ * This method cancels the timer if already active and gets called from DoCancel method.
+ * Also it resets the timer count.
+ *
+ * @internalTechnology
+ **/
+	{
+	if(iTimeout.IsActive())
+		{
+		iTimeout.Cancel();
+		}
+	iTimerCount = 0; //ReInitialize the Timer Count
+
+	}
+
+void CDnsProxyQueryHandler::SetQueryContext(TQueryContext* aQueryContext)
+/**
+ * This method sets the query context to be processes for this query handler.
+ *
+ * @internalTechnology
+ **/
+	{
+	iQueryContext = aQueryContext;
+	}
+
+void CDnsProxyQueryHandler::SetTimer(TUint aTime)
+/**
+ * This method sets the timer for the query whose response is pending.
+ * @param aTime - the value of timer
+ *
+ * @internalTechnology
+ **/
+	{
+
+	iTimeout.Set(iProxyEngine.GetProxyListener()->iTimer,aTime);
+
+	}
+
+TBool CDnsProxyQueryHandler::GetQHandlerState()
+/**
+ * This method gets the current state of query handler.
+ *
+ * @internalTechnology
+ **/
+	{
+	return iQueryHandlerStatus;
+	}
+
+
+void CDnsProxyQueryHandler::SetQHandlerState(TBool aQueryHandlerStatus)
+/**
+ * This method sets the current state of query handler.
+ * @param aQueryHandlerStatus - New state
+ *
+ * @internalTechnology
+ **/
+	{
+	iQueryHandlerStatus = aQueryHandlerStatus;
+	}
+
+/*
+ * Sets the time out value to specified object
+ * @param aNow - time out value
+ * */
+void CDnsProxyQueryHandler::TimeoutL(const TTime& /*aNow*/)
+/**
+ * Sets the time out value to specified object
+ * @param aNow - time out value
+ *
+ * @internalTechnology
+ **/
+	{
+	__LOG1("CDnsProxyQueryHandler(%x)::TimeoutL:Query Timed Out", this)
+	
+	// If already active cancel any pending request.
+	Cancel();
+
+	//Compare the timer count with the configured retry count
+	if(iTimerCount < iProxyEngine.GetConfig().iRetryCount)
+		{
+		//Set active object state to Init
+		SetActiveObjectState(EInit);
+		// increment timer(retry count) count
+		iTimerCount++;
+		// Move to next server in the list
+		iCurServer++;
+		//Process the query again.
+		ProcessQueryL();
+		}
+	else
+	    {
+	    //See if next query available in the queue to handle and deletes
+	    // the query handler
+	    QueryDone();
+	    //Delete the Query context under processing
+		iListener.DeleteQCtxFromListL(iQueryContext);
+	    //Process Next Unassigned query in the list if any
+	    ProcessNextQueryL();
+	    }
+	}
+
+void CDnsProxyQueryHandler::ProcessNextQueryL()
+/**
+ * The method fetches next available query context in the list for processing.
+ * and starts processing the same.
+ * @param None
+ *
+ * @internalTechnology
+ **/
+	{
+    __LOG1("CDnsProxyQueryHandler(%x)::ProcessNextQueryL() Entry", this)
+	TQueryContext *qCtx = iListener.GetQCtxFromList(EUnAssigned);
+
+	if((qCtx != NULL) && (qCtx->GetGlobalScope() == 1))
+	    {
+	    //Set the query state to assigned from unassigned.
+		qCtx->SetQueryState(EAssigned);
+		//Set query context for the Qhandler
+ 		SetQueryContext(qCtx);
+ 		//Process Query Context
+ 		ProcessQueryL();
+	    }
+	 __LOG1("CDnsProxyQueryHandler(%x)::ProcessNextQueryL() Exit", this)   
+	    
+	}
+
+void CDnsProxyQueryHandler::ActivateSocketL()
+/**
+ * The method closes the socket if already open. It then opens the socket and binds
+ * the same to new random port. The query handler status is ETRUE which means it's
+ * processing the query.
+ *
+ *
+ * @internalTechnology
+ **/
+	{
+	__LOG1("CDnsProxyQueryHandler(%x)::ActivateSocketL() Entry", this)
+	if(iActiveStatus == EFalse)
+		{
+		iActiveStatus = ETrue;
+		SetQHandlerState(ETrue);
+		User::LeaveIfError(iSocket.Open(iProxyEngine.GetSocketServer(), KAfInet, KSockDatagram, KProtocolInetUdp,iListener.GetUplinkConnHandle()));	
+ 		BindRandomPort();
+		}
+    __LOG1("CDnsProxyQueryHandler(%x)::ActivateSocketL() Exit", this)		
+	}
+
+void CDnsProxyQueryHandler::DeActivateSocket()
+/**
+ * The method closes the socket if already open.
+ *
+ * @internalTechnology
+ **/
+	{
+	__LOG2("CDnsProxyQueryHandler(%x)::DeActivateSocketL() Entry, Active Status(%d)", this, iActiveStatus)
+	if(iActiveStatus)
+		{
+		iSocket.CancelSend();
+		iSocket.CancelRecv();
+		iSocket.Close();
+		iActiveStatus = EFalse; 
+		}
+    __LOG2("CDnsProxyQueryHandler(%x)::DeActivateSocketL() Exit, Active Status(%d)", this, iActiveStatus)		
+    }
+
+void CDnsProxyQueryHandler::SendQuery(TInetAddr& aServerAddress)
+/**
+ * The method sends the query under processing to the external DNS server.
+ * @param aServerAddress -Address of the DNS server to which query needs to be send
+ *
+ * @internalTechnology
+ **/
+	{
+	__LOG1("CDnsProxyQueryHandler(%x)::SendQuery() Entry", this)		
+	if(IsActive())
+		{
+		__LOG1("CDnsProxyQueryHandler(%x)::SendQuery() is already active", this)		
+		return;
+		}
+
+    SetActiveObjectState(EInit);
+	TPtrC8 msg = iQueryContext->GetDnsQueryMessage();
+	iSocket.SendTo(msg,aServerAddress,0,iStatus);
+	SetActive();
+	__LOG1("CDnsProxyQueryHandler(%x)::SendQuery() Exit", this)		
+	}
+
+void CDnsProxyQueryHandler::SendDnsFailureL()
+/**
+ * The method sends the DNS server failure to the querying host.
+ * @param none
+ *
+ * @internalTechnology
+ **/
+	{
+	__LOG1("CDnsProxyQueryHandler(%x)::SendDnsFailureL() Entry", this)
+	TBuf8<KDnsMaxMessage> buf = iQueryContext->GetDnsQueryMessage();
+	TMsgBuf &msgbuf = TMsgBuf::Cast(buf);	
+	
+	iListener.GetMessageProc().GetDnsFailureMessage(msgbuf);
+		
+	SetQHandlerState(EFalse);
+	iQueryContext->SetQueryState(EResolved); 
+	iQueryContext->SetDnsReplyMessage(msgbuf);
+		
+	iProxyEngine.GetProxyListener()->SendTo(iQueryContext);
+	//Query Finished from Handler Perspective
+	QueryDone();
+	//Process Next Query
+	ProcessNextQueryL();
+	__LOG1("CDnsProxyQueryHandler(%x)::SendDnsFailureL() Exit", this)		
+	}
+
+void CDnsProxyQueryHandler::QueryDone()
+/**
+ * The method resets the Queryhandler.
+ *
+ * @internalTechnology
+ **/
+
+	{
+    __LOG1("CDnsProxyQueryHandler(%x)::QueryDone() Entry", this)		
+    Cancel();
+    
+    //Cancels timer if active
+    CancelTimer();
+    //Deactivates socket
+	DeActivateSocket();
+	iListener.DeActivateUplink();
+	ResetSockActiveStatus();
+	ResetServerCount();
+	ResetTimerCount();
+	SetQueryContext(NULL);
+	SetActiveObjectState(EInit);
+	//Set QHandler state to False which means it is available for processing next
+	SetQHandlerState(EFalse);
+	__LOG1("CDnsProxyQueryHandler(%x)::QueryDone() Exit", this)		
+
+	}
+
+void CDnsProxyQueryHandler::RunReader()
+/**
+ * The method initiates receive request for reading DNS response.
+ *
+ * @internalTechnology
+ **/
+	{
+	__LOG1("CDnsProxyQueryHandler(%x)::RunReader() Entry", this)		
+	// If already active then return
+	TBool is_active = IsActive();
+	if(is_active)
+		{
+	    return;
+		}
+
+	// Set socket status to Ecomplete.
+	SetActiveObjectState(EComplete);
+
+	iSocket.RecvFrom(iReply,iFrom,0,iStatus);
+	SetActive(); // Set the active object to active.
+	__LOG1("CDnsProxyQueryHandler(%x)::RunReader() Exit", this)		
+	}
+
+void CDnsProxyQueryHandler::BindRandomPort()
+/**
+ * This method generates the random port number and binds the socket to it.
+ * This function will be removed as it can be left to TCP/IP stack itself.
+ *
+ * @internalTechnology
+ * */
+	{
+	TInt64 seed =0;
+	TInt err = 0;
+	TInt min_num = 1100; //because standard port number range is:1 to 1024
+	TInt max_min = 65500;
+	TTime time;
+	TInt64 	iRandom_port;
+
+	do
+		{
+		time.UniversalTime();
+		seed = time.Int64();
+
+		TInt port_num = Math::Rand(seed);
+		TInt res = max_min - min_num;
+		TInt val = port_num % res; //if it fails then use min_num instead res
+		iRandom_port = val+min_num;
+
+		TInetAddr inetaddr2;
+		inetaddr2.SetPort(iRandom_port);
+
+		err = iSocket.Bind(inetaddr2);
+		}while(err!=KErrNone);
+	}
+
+TInt CDnsProxyQueryHandler::RunError(TInt aErr)
+/**
+ * This method implements RunError method of an active object. This helps in debugging.
+ *
+ * @internalTechnology
+ * */
+	{
+    __LOG2("CDnsProxyQueryHandler(%x)::RunError %d", this, aErr)		
+    if(iQueryContext)
+		{
+		//Delete the Query context under processing
+    	TRAPD(err,iListener.DeleteQCtxFromListL(iQueryContext));
+    	__LOG1("DeleteQCtxFromListL::RunError %d",err)
+    	}
+    //Complete the query
+	QueryDone();
+    //Flush all the queries in queue
+	iListener.DeleteAllQCtxFromList();
+	    	
+	return KErrNone;
+	}
+
+TStatus CDnsProxyQueryHandler::GetActiveObjectState()
+/**
+ * This method returns the state of the object
+ * @param None
+ * @return None
+ *
+ * @internalTechnology
+ * */
+	{
+	return iSocketStatus;
+
+	}
+
+void CDnsProxyQueryHandler::SetActiveObjectState(TStatus aState)
+/**
+ * This method returns the state of the object
+ * @param None
+ * @return None
+ *
+ * @internalTechnology
+ * */
+	{
+	iSocketStatus = aState;
+
+	}