datacommsserver/esockserver/ssock/SS_RSLV.CPP
changeset 0 dfb7c4ff071f
child 12 8b5d60ce1e94
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/SS_RSLV.CPP	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,1328 @@
+// Copyright (c) 1997-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:
+//
+
+#define SYMBIAN_NETWORKING_UPS
+
+#include <comms-infras/ss_roles.h>
+#include <comms-infras/ss_log.h>
+#include <ss_glob.h>
+#include <ss_std.h>
+#include <comms-infras/ss_subconnflow.h>
+#include "ss_flowrequest.h"
+#include <es_prot.h>
+#include "SS_rslv.H"
+#include <comms-infras/nifif.h>
+#include <comms-infras/ss_sapshim.h>
+#include <comms-infras/ss_nodemessages_dataclient.h>
+#include <es_mbuf.h>
+
+#include <comms-infras/ss_msgintercept.h>
+
+
+#ifdef _DEBUG
+// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
+// (if it could happen through user error then you should give it an explicit, documented, category + code)
+_LIT(KSpecAssert_ESockSSockS_RSLV, "ESockSSockS_RSLV");
+#endif
+
+#define MSG_PRM(prmIndex)		(prmIndex)
+
+using namespace ESock;
+using namespace Messages;
+
+CHostResolver::CHostResolver(CSockSession* aSession, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId)
+: CSockSubSession(aSession, aPlayer, aSubSessionUniqueId),
+  Messages::ASimpleNodeIdBase(),
+  iPtrQryBuf(NULL, 0),
+  iPtrQryResBuf(NULL, 0)
+
+/**
+Constructor - set up default options.
+
+*/
+	{
+	LOG_NODE_CREATE(KESockFlowTag, CHostResolver)
+    }
+
+CHostResolver::~CHostResolver()
+/**
+Destructor
+
+*/
+	{
+   	delete ipQryRespBuf; //-- delete query response buffer
+   	delete ipQryBuf;     //-- delete query buffer
+	LOG_NODE_DESTROY(KESockFlowTag, CHostResolver)
+	}
+
+void CHostResolver::InitiateDestruction()
+	{
+	// Remove the subsession from the session's subsession list.
+    if(iSession)
+		{
+		iSession->SubSessions().Lock();
+
+		Den::CSubSessionIx::TSubSessionHandle handle;
+		if(iSession->SubSessions().Find(this, handle) == KErrNone)
+			{
+			iSession->PitBoss().RemoveSubSession(handle, iSession);
+			}
+
+		iSession->SubSessions().Unlock();
+		}
+
+	SetClosing();
+
+    if (iRSP)
+        {
+//    	ASSERT(iFlowBinderControl);	// in OOM cases may not have been bound
+		if(iFlowBinderControl)
+			{
+	  		iFlowBinderControl->Unbind();
+			}
+		delete iRSP;
+        }
+
+	if (!FlowRequestPending())
+		delete this;
+	}
+
+CHostResolver * CHostResolver::NewLC(CProtocolRef* aProtRef, CSockSession *aSession, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId)
+/**
+Create a new CHostresolver
+
+*/
+	{
+	CHostResolver* h = new(ELeave) CHostResolver(aSession, aPlayer, aSubSessionUniqueId);
+	CleanupStack::PushL(h);
+	h->CreateL(aProtRef);
+	ESOCK_DEBUG_REGISTER_GENERAL_NODE(ESockDebug::KHostResolverNodeUid, h);
+	return h;
+	}
+
+void CHostResolver::CreateL(CProtocolRef* aProtRef)
+	{
+	CSockSubSession::ConstructL(aProtRef->Protocol());
+	iBusy=EFalse;
+	iAwaitingConnection=EFalse;
+	iProtocolInfo = &(aProtRef->Info());
+	}
+
+void CHostResolver::FinalCompleteAllBlockedMessages(TInt aResult)
+	{
+	if(iBusy)
+		{
+		CompleteMessage(iBlockedReq, aResult);
+		}
+	}
+
+void CHostResolver::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+    {
+    (void) aRecipient;
+	ESOCK_DEBUG_MESSAGE_INTERCEPT(aSender, aMessage, aRecipient);
+
+    if (aMessage.IsMessage<TEBase::TError>())
+    	{
+    	//The first error would be from the flow request, any other error iIsFlowRequestPending must be false anyway
+		if (FlowRequestPending())
+			{
+			TEBase::TError& errorMsg(static_cast<TEBase::TError&>(aMessage));
+			CompleteFlowRequestMessage(errorMsg.iValue);
+			SetFlowRequestPending(EFalse);
+			}
+
+		//We are no longer needed and the client has been completed too, tear us down.
+		InitiateDestruction();
+		}
+    else if (aMessage.IsMessage<TCFDataClient::TBindTo>())
+		{
+		// An error here is propagated back to the waiting CFlowRequest
+		TCFDataClient::TBindTo& bindToMsg(static_cast<TCFDataClient::TBindTo&>(aMessage));
+		SetFlowRequestPending(EFalse);
+
+		TInt err;
+		if (IsClosing())
+			{
+			err = KErrAbort;
+			}
+		else
+			{
+			TRAP(err,BindToL(bindToMsg));
+			}
+
+		TCFDataClient::TBindToComplete bindCompleteMsg(err);
+		RClientInterface::OpenPostMessageClose(Id(), aSender,
+			bindCompleteMsg);
+
+		CompleteFlowRequestMessage(err);
+
+		if (IsClosing())
+			{
+			InitiateDestruction();
+			}
+		}
+    else
+        {
+  		__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSockS_RSLV, 1));
+        }
+    }
+
+void CHostResolver::BindToL(const TCFDataClient::TBindTo& aBindTo)
+    {
+    __ASSERT_DEBUG(iLowerControl==NULL, User::Panic(KSpecAssert_ESockSSockS_RSLV, 2));
+#if defined(__GCCXML__)
+    CSubConnectionFlowBase* flow = reinterpret_cast<CSubConnectionFlowBase*>(reinterpret_cast<Messages::ANode*>(aBindTo.iNodeId.Ptr()));
+#else
+    CSubConnectionFlowBase* flow = mcfnode_cast<CSubConnectionFlowBase>(reinterpret_cast<Messages::ANode*>(aBindTo.iNodeId.Ptr()));
+#endif
+    if (flow==NULL)
+        {
+        User::Leave(KErrArgument);
+        }
+
+    NM_LOG((KESockServerTag, _L8("CHostResolver %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL"),
+			this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) )
+
+	iFlowBinderControl = flow->GetBinderControlL();
+	iLowerControl = iFlowBinderControl->GetControlL(KNullDesC8);
+	iLowerDataSender = iFlowBinderControl->BindL(KNullDesC8, NULL, this);
+
+
+#ifdef SYMBIAN_NETWORKING_UPS
+	LOG(ESockLog::Printf(KESockConnectionTag, _L8("CHostResolver %08x:\tBindToL(%08x)"), this, &aBindTo.iNodeId.Node()) );
+	LOG(ESockLogExternal::Printf(KCFNodeTag, KESockFlowTag, _L8("CHostResolver %08x:\tSynchronous call: Sender=%08x, Recipient=%08x, Function=BindToL"), this, static_cast<ANode*>(this), &aBindTo.iNodeId.Node()) );
+
+	// UPS support
+	InitialiseFlow(flow);
+#endif
+
+    LockToConnectionInfo();
+    }
+
+#ifdef SYMBIAN_NETWORKING_UPS
+
+void CHostResolver::InitialiseFlow(CSubConnectionFlowBase* aFlow)
+/**
+Initialise the flow for Host Resolver UPS operation
+
+@param aFlow Underlying flow to initialise
+*/
+	{
+	CTransportFlowShim* shimFlow = Factories::factoryobject_cast<CTransportFlowShim>(aFlow);
+    if (shimFlow)
+    	{
+    	// Pass the MProvdSecurityChecker down to the CTransportFlowShim so that it can perform
+    	// the Platform Security check.
+    	shimFlow->SecurityCheck(Session());
+
+    	// Pass the thread/process id down to the CTransportFlowShim as these are required
+    	// to perform UPS authorisation.
+		TSoOwnerInfo info;
+		GetOwnerInfo(info.iProcessId, info.iUid, info.iThreadId);
+
+		shimFlow->SetOption(KSOLProvider, KSoOwnerInfo, TPckgC<TSoOwnerInfo>(info));
+
+		//
+		// In addition to KSoOwnerInfo, communicate an MPlatSecApiExt instance downwards in order
+		// to allow dynamic retrieval of process and thread id (rather than the process/thread id
+		// at the time of the subsession open.  It is not certain that our MPlatsecApiExt can
+		// actually provide a valid process/thread id all the time, so the KSoOwnerInfo gives
+		// default values for circumstances where MPlatsecApiExt).
+		//
+		// @TODO REQ1116 - clean this whole area up - especially the use of two mechanisms
+		// "one in case the other doesn't always work".  Can we just use the dynamic one?
+		//
+		shimFlow->SetOption(KSOLProvider, KSoSetPlatSecApi, TPckgC<const MPlatsecApiExt*>(this));
+    	}
+	}
+#endif
+
+TBool CHostResolver::GetFlowAndSCPR(Messages::TNodeId& aFlow, Messages::TNodeId& aSCPR) const
+    {
+    if (iFlowBinderControl)
+        {
+    	aFlow = iFlowBinderControl->Flow()->Id();
+    	aSCPR = iFlowBinderControl->Flow()->ControlProvider().RecipientId();
+    	return ETrue;
+        }
+    return EFalse;
+    }
+
+HBufC8* CHostResolver::GetBuffer(HBufC8* apBuf, TInt aBufLenRequired)
+/**
+Allocate buffer on heap or reallocate it if required size is more than existing
+
+@param    apBuf           pointer to the existing buffer. If NULL new bufeer will be allocated.
+@param    aBufLenRequired reuired buffer length.
+@return   pointer to the new buffer
+@return   NULL in case of memory problems or other errors
+*/
+	{
+    HBufC8* pBufResult = NULL;
+
+    if(aBufLenRequired <= 0 )
+		{
+		PanicClient(KESockClientPanic, EBadDescriptorLength);
+        return NULL; //-- invalid argument
+		}
+
+    if(!apBuf)
+		{//-- the buffer is not allocated at all, try allocate it
+		pBufResult = HBufC8::New(aBufLenRequired);
+		}
+    else
+		{//-- the buffer is already allocated. Check its size and try to reallocate if
+		//-- required size is bigger than existing. Otherwise do nothing.
+
+		if(apBuf->Des().MaxSize() >= aBufLenRequired)
+			pBufResult = apBuf; //-- do nothing, existing buffer is big enough
+		else
+			{  //-- delete and allocate new buffer to avoid data copying
+			delete apBuf;
+			pBufResult = HBufC8::New(aBufLenRequired);
+			}
+
+		}
+
+    return pBufResult;
+	}
+
+
+TBool CHostResolver::GetQueryRespBuffer(void)
+/**
+Allocate or reallocate buffer for CHostResolver::Query() response data.
+The length of the buffer obtained from Message().Ptr1(), as it is the 2nd parameter in RHostResolver::Query() that
+shall contain pointer to the client's TPckgBuf query response data.
+ipQryRespBuf is used for buffer pointer.
+
+@return ETrue if the buffer has been successfully allocated (or increased)
+*/
+	{
+    //-- obtain the length of the client's buffer and allocate the same buffer on our(server) side.
+    //-- data there will be put by the protocol and then copied to the client side in QueryComplete.
+    //-- we need to append sizeof(TDes8) to the buffer lenght because from client point of view the buffer is TPckgBuf<...>
+    TInt len = iBlockedReq.GetDesLength(1) + sizeof(TDes8);
+
+    ipQryRespBuf = GetBuffer(ipQryRespBuf, len); //-- claim buffer big enough for query response data
+
+    if(ipQryRespBuf)
+		{//-- memory allocated, store TPtr8 associated with buffer on the heap, which
+		//-- can be used later in asynchonous environment by the protocol.
+        iPtrQryResBuf.Set(ipQryRespBuf->Des());
+        return ETrue;
+		}
+    else
+		{//-- memory alocation failure
+        iPtrQryResBuf.Set(NULL, 0, 0);
+        return EFalse;
+		}
+	}
+
+
+TBool CHostResolver::GetQueryBuffer(void)
+/**
+Allocate or reallocate buffer for CHostResolver::Query() data.
+The length of the buffer obtained from Message().Ptr0(), as it is the 1st parameter in RHostResolver::Query() that
+shall contain pointer to the client's TPckgBuf query data.
+
+@return ETrue if the buffer has been successfully allocated (or increased)
+*/
+{
+    TInt len = iBlockedReq.GetDesLength(0) + sizeof(TDes8);
+//    TInt len = iBlockedReq.Client().GetDesLength(Message().Ptr0()) + sizeof(TDes8);
+
+    ipQryBuf = GetBuffer(ipQryBuf, len); //-- claim buffer big enough for query data
+
+    if(ipQryBuf)
+    {//-- memory allocated, store TPtr8 associated with buffer on the heap, which
+     //-- can be used later in asynchonous environment by the protocol.
+        iPtrQryBuf.Set(ipQryBuf->Des());
+        return ETrue;
+    }
+    else
+    {//-- memory alocation failure
+        iPtrQryBuf.Set(NULL, 0, 0);
+        return EFalse;
+    }
+}
+
+void CHostResolver::QueryL(void)
+/**
+Host Resolver Query implementation
+Query the current protocol and obtain the result
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	iBlockedReq=Message();
+
+    //-- allocate or reallocate buffer for query and query  response.
+    if(! GetQueryRespBuffer() || ! GetQueryBuffer())
+		{//-- buffer hasn't been allocated
+        SetReturn(KErrNoMemory);
+		return;
+		}
+
+	//-- read query data from client's buffer to the CHostResolver's internal one
+    //-- Ptr0() points to client's Query data buffer, Ptr1() - to the client's query response
+   	SafeMessage().ReadL(0, iPtrQryBuf);
+
+	iBusy=ETrue;
+	iAwaitingConnection = EFalse;
+	DontCompleteCurrentRequest();
+
+	iCurrentOp=EHrQuery;
+
+
+	iCount=0;
+
+    //-- call CHostResolvProvdBase Query method implemented in appropriate protocol
+    iRSP->Query(iPtrQryBuf, iPtrQryResBuf, iCount);
+	}
+
+void CHostResolver::QueryGetNext(void)
+/**
+Host Resolver QueryGetNext implementation.
+Obtain the next query result.
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	if(iCount<1)
+		{//-- tried to call QueryGetNext() before Query()
+		PanicClient(KESockClientPanic, ENoQueryFirst);
+		SetReturn(KErrNotFound);
+		return;
+		}
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	//-- call CHostResolvProvdBase QueryGetNext method implemented in appropriate protocol
+	if(iCurrentOp == EHrQuery)
+		{	//-- iCount is incremented in QueryComplete,
+        //-- iQryBuf isn't supposed to be in use here.
+        //-- buffer for response ipQryRespBuf must have been allocated by CHostResolver::Query
+        if(!ipQryRespBuf)
+			{//-- buffer hasn't been allocated, it means memory problems
+            SetReturn(KErrNoMemory);
+			return;
+			}
+
+        iRSP->Query(iPtrQryBuf, iPtrQryResBuf, iCount);
+		}
+
+	}
+
+
+void CHostResolver::GetByNameL()
+/**
+Start a get by name query
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	SafeMessage().ReadL(MSG_PRM(0),iNameRec.iName);
+
+	iBusy=ETrue;
+	iAwaitingConnection = EFalse;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iCurrentOp=EHRGetByName;
+	iCount=0;
+	iNameRec.iFlags=iCount;
+	iRSP->GetByName(iNameRec);
+	}
+
+void CHostResolver::Next()
+/**
+Retrieve next record
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	if(iCount<1)
+		{
+		PanicClient(KESockClientPanic, ENoResolveFirst);
+		SetReturn(KErrNotFound);
+		return;
+		}
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iNameRec.iFlags=iCount;
+	if(iCurrentOp==EHRGetByName)
+		iRSP->GetByName(iNameRec);
+	else
+		iRSP->GetByAddress(iNameRec);
+	}
+
+void CHostResolver::GetByAddressL()
+/**
+Start a get by address query
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	SafeMessage().ReadL(MSG_PRM(0),iNameRec.iAddr);
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iCurrentOp=EHRGetByAddress;
+
+	iCount=0;
+	iNameRec.iFlags=iCount;
+	iRSP->GetByAddress(iNameRec);
+	}
+
+void CHostResolver::GetHostName()
+/**
+Get the name of the local host
+
+*/
+	{
+    iCurrentOp = EHRGetHostName;
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iRSP->GetHostName(iNameRec.iName);
+	}
+
+void CHostResolver::SetHostNameL()
+/**
+Set the name of the host machine
+
+*/
+	{
+   iCurrentOp = EHRSetHostName;
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+	THostName n;
+	SafeMessage().ReadL(MSG_PRM(0),n);
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iRSP->SetHostName(n);
+	}
+
+void CHostResolver::SetOptionL()
+	{
+	iCurrentOp = EHRSetOpt;
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	ReadAndSetOptionL();
+	
+	}
+
+
+void CHostResolver::Cancel()
+/**
+Cancel any pending request
+
+*/
+	{
+	if (!iBusy)
+		return;
+
+	iBusy=EFalse;
+	iCount=0;
+
+	CompleteMessage(iBlockedReq, KErrCancel);
+	iRSP->CancelCurrentOperation();
+	}
+
+void CHostResolver::QueryComplete(TInt anError)
+/**
+outstanding request has completed
+
+*/
+	{
+	LOG(ESockLog::Printf(KESockConnectionTag, _L8("CHostResolver %08x:\tQueryComplete(TInt anError)\taError %d"), this, anError) );
+
+	if(!iBusy)
+		return;
+
+	Den::RSafeMessage& message = static_cast<Den::RSafeMessage&>(const_cast<RMessage2&>(iBlockedReq));
+	if (anError == KErrCompletion && RequiresConnectionStartup())
+		{
+		//
+		// KErrCompletion from Host Resolvers that require connection startup indicates that
+		// the name was not found locally, a connection needs to be started, and the
+		// GetByName() re-issued.   In some ways, this is the equivalent of CSocket::NoBearer().
+		//
+ 		TRAP(anError,HandleConnectionSetupL());
+ 		if ( anError == KErrNone )
+ 			{
+			return;
+ 			}
+#ifdef SYMBIAN_NETWORKING_UPS
+ 		else
+ 		if (anError == KErrPermissionDenied)
+			{
+			// This code path supports the UPS "Disabled" configuration.  A KErrPermissionDenied error
+			// is returned if the platsec capability check failed.  See if the provider has an error
+			// code that it prefers to complete the request with.  This supports the behaviour in the
+			// TCP provider whereby the lack of capabilities means that the request is looked up locally
+			// without using the network and, if not found, a provider specific error code is returned
+			// rather than KErrPermissionDenied.
+			TInt err = iRSP->SetOption(KSOLProvider, KSoGetErrorCode, KNullDesC8());
+			if (err > 0)
+				{
+				anError = -err;
+				}
+			}
+#endif //SYMBIAN_NETWORKING_UPS
+		}
+	else
+	if (anError==KErrNone)
+		{
+		switch (iBlockedReq.Function())
+			{
+		case EHRNext:
+		case EHRGetByName:
+		case EHRGetByAddress:
+			{
+			TInt ret = message.Write(MSG_PRM(1),TPtr8((TUint8 *)&iNameRec,sizeof(iNameRec),sizeof(iNameRec)));
+			if(ret!=KErrNone)
+				{
+				iBusy=EFalse;
+				return;
+				}
+			++iCount;
+			break;
+			}
+		case EHRGetHostName:
+			{
+			TInt ret = message.Write(MSG_PRM(0),iNameRec.iName);
+			if(ret!=KErrNone)
+				{
+				iBusy=EFalse;
+				return;
+				}
+			break;
+			}
+		case EHRSetHostName:
+		case EHRSetOpt:
+			break;
+
+        //-- protocol has completed Query or QueryNext write query response data into the client's buffer
+        case EHrQuery:
+            if(ipQryRespBuf)
+            {
+                TInt ret = message.Write(1, iPtrQryResBuf);
+				if(ret!=KErrNone)
+					{
+					iBusy=EFalse;
+					return;
+					}
+				++iCount;
+			}
+            else
+              Panic(EBadErrorCall);
+        break;
+
+        case EHrQueryNext:
+            if(ipQryRespBuf)
+            {
+				TInt ret = message.Write(0, iPtrQryResBuf);
+				if(ret!=KErrNone)
+					{
+					iBusy=EFalse;
+					return;
+					}
+				++iCount;
+			}
+            else
+                Panic(EBadErrorCall);
+        break;
+
+    	default:
+			Panic(ENothingToComplete);
+			}
+		}
+	else
+		iCount=0;
+
+	iBusy=EFalse;
+	iAwaitingConnection = EFalse;
+	message.Complete(anError);
+	}
+
+//
+//TBool CHostResolver::FetchOwnerInfo(CConnectionProviderBase::TEnumClients aClientType, TProcessId& aProcessId, TUidType& aUidType, TThreadId& aThreadId)
+//	{
+//	TBool b = aClientType == CConnectionProviderBase::EAll || aClientType == CConnectionProviderBase::EHostResolver;
+//	if ( b )
+//		{
+//		GetOwnerInfo( aProcessId, aUidType, aThreadId);
+//		}
+//	return b;
+//	}
+//
+
+void CHostResolver::StartSending()
+/**
+Called when we have got a valid connection info that we can set
+
+*/
+    {
+	LOG(ESockLog::Printf(KESockConnectionTag, _L8("CHostResolver %08x:\tStartSending() iBusy %d, iAwaitingConnection %d"), this,iBusy,iAwaitingConnection) );
+	LockToConnectionInfo();
+	if (iBusy && iAwaitingConnection)
+		{
+		switch (iCurrentOp)
+			{
+		case EHRGetByName:
+			iRSP->GetByName(iNameRec);
+			break;
+		case EHRGetByAddress:
+			iRSP->GetByAddress(iNameRec);
+			break;
+
+        case EHrQuery:
+
+            if(! GetQueryRespBuffer())
+	        {//-- buffer hasn't been allocated
+                SetReturn(KErrNoMemory);
+		        break;
+	        }
+            else
+            {
+                //-- call CHostResolvProvdBase Query method implemented in appropriate protocol
+               iRSP->Query(iPtrQryBuf, iPtrQryResBuf, iCount);
+            }
+			break;
+
+		case EHRGetHostName:
+			iRSP->GetHostName(iNameRec.iName);
+			break;
+
+		case EHRSetHostName:
+			{
+			THostName n;
+			SafeMessage().ReadL(MSG_PRM(0),n);
+			iRSP->SetHostName(n);
+			}
+			break;
+			
+
+		case EHRSetOpt:
+			{
+			TInt err;
+			TRAP(err,ReadAndSetOptionL());	
+			if(err != KErrNone)
+				{
+				SetReturn(err);
+				}
+			}
+			break;
+
+		default:
+			Panic(ENothingToComplete);
+			}
+		}
+	iAwaitingConnection = EFalse;
+    }
+
+void CHostResolver::Error(TInt aError)
+	{
+	LOG(ESockLog::Printf(KESockConnectionTag, _L8("CHostResolver %08x:\tError(aError %d)"), this, aError) );
+
+#ifdef SYMBIAN_NETWORKING_UPS
+	if (aError == KErrPermissionDenied)
+		{
+		// UPS support.  We received a TError in response to a TNoBearer sent previously, indicating
+		// UPS authorisation failure.
+		//
+		// ASSERT(incoming message is a TError with iMsgId set to TNoBearer)
+		//
+		// See if the provider has an error code that it prefers to complete the request with.
+		// This supports the behaviour in the TCP provider whereby the lack of capabilities
+		// (lack of authorisation when using UPS) means that the request is looked up locally
+		// without using the network and, if not found, a provider specific error code is returned.
+		//
+		// The SetOption() interface towards Host Resolver SAPs does not allow for the
+		// retrieval of a TInt value (being a const interface).  So take a positive return value
+		// to represent a valid error code to use.
+
+		TInt err = iRSP->SetOption(KSOLProvider, KSoGetErrorCode, KNullDesC8());
+		if (err > 0)
+			{
+			aError = -err;
+			}
+		}
+#endif //SYMBIAN_NETWORKING_UPS
+
+	QueryComplete(aError);
+	iAwaitingConnection = EFalse;
+	TBuf8<sizeof(TConnectionInfo)> buf;
+	if (aError == KErrBindersInvalid)
+	    {
+        iLowerControl = NULL;
+    	iFlowBinderControl = NULL;
+	    iLowerDataSender = NULL;
+	    }
+	else if (aError == KErrDisconnected || iLowerControl->Control((TUint)KSOLProvider, (TUint)KSoConnectionInfo, buf)!=KErrNone)
+	    {
+    	//reset the scope
+    	TConnectionInfo info(0,0);
+    	TPckg<TConnectionInfo> infoBuf(info);
+
+    	LockToConnectionInfo(infoBuf);
+	    }
+    }
+
+void CHostResolver::HandleConnectionSetupL()
+/**
+Handle any implicit connection setup which is required as a result of a Host Resolver request.
+
+*/
+	{
+	LOG(ESockLog::Printf(KESockConnectionTag, _L8("CHostResolver %08x:\tHandleConnectionSetup selecting....."), this) );
+
+	iAwaitingConnection = ETrue;
+
+	// Workaround to kick off the flow set-up
+	RMBufChain dummy;
+#ifdef SYMBIAN_NETWORKING_UPS
+	User::LeaveIfError(iLowerDataSender->Send(dummy));
+#else
+	iLowerDataSender->Send(dummy);
+#endif
+	}
+
+void CHostResolver::LockToConnectionInfo()
+    {
+    // retrieve default connection info
+    TPckgBuf<TConnectionInfo> info;
+    __ASSERT_DEBUG(iLowerControl!=NULL, User::Panic(KSpecAssert_ESockSSockS_RSLV, 3));
+    iLowerControl->Control((TUint)KSOLProvider, (TUint)KSoConnectionInfo, info);
+
+    // set host resolver connection info
+	TPckgBuf<TSoIfConnectionInfo> ifInfo;
+    ifInfo().iIAPId = info().iIapId;
+	ifInfo().iNetworkId = info().iNetId;
+    LockToConnectionInfo(ifInfo);
+    }
+
+void CHostResolver::LockToConnectionInfo(const TDesC8& aConnectionInfo)
+/**
+Called when interface selection has completed in order to communicate the connection
+information to the Host Resolver.
+
+@param aConnectionInfo Connection information identifying the interface
+*/
+	{
+	if (aConnectionInfo.Length() > 0)
+		{
+		LOG( ESockLog::ConnectionInfoPrintf(aConnectionInfo, _L("CHostResolver %08x:\tLockToConnectionInfo()"), this) );
+		iRSP->SetOption(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), aConnectionInfo);
+		}
+	}
+
+
+void CHostResolver::ProcessMessageL()
+	{
+	switch(Message().Function())
+		{
+	   case EHRGetByName:
+			GetByNameL();
+			break;
+
+		case EHRNext:
+			Next();
+			break;
+
+		case EHRGetByAddress:
+			GetByAddressL();
+			break;
+
+		case EHRGetHostName:
+			GetHostName();
+			break;
+
+		case EHRSetHostName:
+			SetHostNameL();
+			break;
+
+		case EHRCancel:
+			Cancel();
+			break;
+
+		case EHrQuery:
+			QueryL();
+			break;
+
+		case EHrQueryNext:
+			QueryGetNext();
+			break;
+
+	    case EHRClose:
+	    	InitiateDestruction();
+			break;
+			
+	    case EHRSetOpt:
+	    	SetOptionL();
+	    	break;
+			
+		default:
+			SetReturn(KErrNotSupported);
+		}
+	}
+
+#ifdef SYMBIAN_NETWORKING_UPS
+TInt CHostResolver::GetProcessAndThreadId(TProcessId& aProcessId, TThreadId& aThreadId) const
+	{
+	if (iBusy && !iBlockedReq.IsNull())
+		{
+		return ASockSubSessionPlatsecApiExt::GetProcessAndThreadIdFromRMessage(iBlockedReq, aProcessId, aThreadId);
+		}
+	else
+		{
+		return KErrNotFound;
+		}
+	}
+#endif
+
+void CHostResolver::ReadAndSetOptionL()
+	{
+
+	TInt optionName=Message().Int0();
+	TInt optionLevel=Message().Int2();
+
+	RBuf8 setOptionBuf;  
+	setOptionBuf.CreateL(Message().GetDesLengthL(1)); //1 - is the option that is passed 
+	CleanupClosePushL(setOptionBuf);
+	SafeMessage().ReadL(MSG_PRM(1),setOptionBuf);
+
+	TPtrC8 setOptionPtr(setOptionBuf);
+ 	SetReturn(iRSP->SetOption(optionLevel,optionName,setOptionPtr));
+	
+	CleanupStack::PopAndDestroy();
+
+	}
+
+
+// ============================================================================================
+
+CServiceResolver::CServiceResolver(CSockSession* aSession, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId)
+/**
+Constructor - set up default options.
+
+*/
+: CSockSubSession(aSession, aPlayer, aSubSessionUniqueId)
+	{
+	}
+
+CServiceResolver * CServiceResolver::NewLC(CProtocolRef* aProtRef, CSockSession *aSession, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId)
+/**
+Create a new CService resolver
+*/
+	{
+	CServiceResolver* r = new(ELeave) CServiceResolver(aSession, aPlayer, aSubSessionUniqueId);
+	CleanupStack::PushL(r);
+	r->ConstructL(aProtRef->Protocol());
+	r->iSession=aSession;
+	return r;
+	}
+
+void CServiceResolver::FinalCompleteAllBlockedMessages(TInt aResult)
+	{
+	if(iBusy)
+		{
+		CompleteMessage(iBlockedReq, aResult);
+		}
+	}
+
+void CServiceResolver::GetByNameL()
+/**
+Start a get by name query
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	SafeMessage().ReadL(MSG_PRM(0),iNameBuf);
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iRSP->GetByName(iNameBuf,iPortNum);
+	}
+
+void CServiceResolver::GetByNumber()
+/**
+Start a get by number query
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iRSP->GetByNumber(iNameBuf,Message().Int1());
+	}
+
+void CServiceResolver::RegisterServiceL()
+/**
+Register a new service
+
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+
+	SafeMessage().ReadL(MSG_PRM(0),iNameBuf);
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iPortNum=Message().Int1();
+	iRSP->RegisterService(iNameBuf,iPortNum);
+	}
+
+void CServiceResolver::RemoveServiceL()
+/**
+delete an entry in the services database
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	SafeMessage().ReadL(MSG_PRM(0),iNameBuf);
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+	iPortNum=Message().Int1();
+	iRSP->RemoveService(iNameBuf,iPortNum);
+	}
+
+void CServiceResolver::Cancel()
+/**
+Cancel any pending request
+
+*/
+	{
+	if (!iBusy)
+		return;
+
+	iBusy=EFalse;
+	CompleteMessage(iBlockedReq, KErrCancel);
+	iRSP->CancelCurrentOperation();
+	}
+
+
+void CServiceResolver::QueryComplete(TInt anError)
+/**
+a request has completed
+*/
+	{
+
+	//__ASSERT_DEBUG(iBusy,PanicClient(Message(), EBadQueyComplete));
+	if(!iBusy)
+		return;
+
+	Den::RSafeMessage& message = static_cast<Den::RSafeMessage&>(const_cast<RMessage2&>(iBlockedReq));
+
+	LOG(ESockLog::Printf(KESockConnectionTag, _L8("CServiceResolver %08x:\tQueryComplete(TInt anError)\t aError %d, message %08X"), this, anError, message.Handle()) );
+
+	TPortNum num;
+
+	if (anError==KErrNone)
+		switch (iBlockedReq.Function())
+			{
+		case ESRGetByName:
+			{
+			num=iPortNum;
+			TInt ret = message.Write(MSG_PRM(1),num);
+			if(ret!=KErrNone)
+				{
+				iBusy=EFalse;
+				return;
+				}
+			break;
+			}
+		case ESRGetByNumber:
+			{
+			TInt ret = message.Write(MSG_PRM(0),iNameBuf);
+			if(ret!=KErrNone)
+				{
+				iBusy=EFalse;
+				return;
+				}
+			break;
+			}
+		case ESRRegisterService:
+		case ESRRemoveService:
+			break;
+		default:
+			Panic(ENothingToComplete);
+			}
+
+	iBusy=EFalse;
+	message.Complete(anError);
+	}
+
+CServiceResolver::~CServiceResolver()
+	{
+	delete iRSP;
+	}
+
+void CServiceResolver::ProcessMessageL()
+	{
+	switch(Message().Function())
+		{
+		case ESRGetByName:
+			GetByNameL();
+			break;
+
+		case ESRGetByNumber:
+			GetByNumber();
+			break;
+
+		case ESRRegisterService:
+			RegisterServiceL();
+			break;
+
+		case ESRRemoveService:
+			RemoveServiceL();
+			break;
+
+		case ESRCancel:
+			Cancel();
+			break;
+
+		case ESRClose:
+			delete this;
+			break;
+
+		default:
+			SetReturn(KErrNotSupported);
+		}
+	}
+CNetDatabase* CNetDatabase::NewLC(CProtocolRef* aProtRef, CSockSession *aSession, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId)
+/**
+Create a new CNetDatabase
+*/
+	{
+	CNetDatabase* n = new(ELeave) CNetDatabase(aSession, aPlayer, aSubSessionUniqueId);
+	CleanupStack::PushL(n);
+	n->ConstructL(aProtRef->Protocol());
+	n->iSession=aSession;
+	return n;
+	}
+
+
+CNetDatabase::CNetDatabase(CSockSession *aSession, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId)
+/**
+Constructor - set up default options.
+*/
+: CSockSubSession(aSession, aPlayer, aSubSessionUniqueId)
+	{
+	}
+
+void CNetDatabase::FinalCompleteAllBlockedMessages(TInt aResult)
+	{
+	if(iBusy)
+		{
+		CompleteMessage(iBlockedReq, aResult);
+		}
+	}
+
+void CNetDatabase::RequestL()
+/**
+Perform a query
+*/
+	{
+	if (iBusy)
+		{
+		PanicClient(KESockClientPanic, ETwice);
+		SetReturn(KErrInUse);
+		return;
+		}
+
+	delete iBuf;
+	iBuf=0;
+	iBuf=HBufC8::NewMaxL(Message().Int1());
+
+	delete iBufPtr;
+	iBufPtr=0;
+	iBufPtr=new(ELeave) TPtr8(iBuf->Des());
+
+	SafeMessage().ReadL(MSG_PRM(0),*iBufPtr);
+
+	iBusy=ETrue;
+	iBlockedReq=Message();
+	DontCompleteCurrentRequest();
+
+
+	switch (Message().Function())
+		{
+	case ENDQuery:
+		iRSP->Query(*iBufPtr);
+		break;
+	case ENDAdd:
+		iRSP->Add(*iBufPtr);
+		break;
+	case ENDRemove:
+		iRSP->Remove(*iBufPtr);
+		break;
+		}
+	}
+
+void CNetDatabase::Cancel()
+/**
+Cancel any pending request
+*/
+	{
+	if (!iBusy)
+		return;
+
+	iBusy=EFalse;
+	CompleteMessage(iBlockedReq, KErrCancel);
+	iRSP->CancelCurrentOperation();
+	}
+
+void CNetDatabase::QueryComplete(TInt anError)
+/**
+An outstanding query had completed
+*/
+	{
+
+	if(!iBusy)
+		return;
+	Den::RSafeMessage& message = static_cast<Den::RSafeMessage&>(const_cast<RMessage2&>(iBlockedReq));
+
+	if (anError==KErrNone && iBlockedReq.Function()==ENDQuery)
+		{
+		TInt ret = message.Write(MSG_PRM(2),*iBufPtr);
+		if(ret!=KErrNone)
+			{
+			iBusy=EFalse;
+			return;
+			}
+		}
+	iBusy=EFalse;
+	message.Complete(anError);
+	}
+
+CNetDatabase::~CNetDatabase()
+	{
+	delete iRSP;
+	delete iBuf;
+	delete iBufPtr;
+	}
+
+void CNetDatabase::ProcessMessageL()
+	{
+	switch(Message().Function())
+		{
+		case ENDQuery:
+		case ENDAdd:
+		case ENDRemove:
+			RequestL();
+			break;
+
+		case ENDCancel:
+			Cancel();
+			break;
+
+		case ENDClose:
+			delete this;
+			break;
+
+		default:
+			SetReturn(KErrNotSupported);
+		}
+	}