datacommsserver/esockserver/ssock/ss_intsock.cpp
changeset 0 dfb7c4ff071f
child 4 928ed51ddc43
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/ss_intsock.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,3237 @@
+// 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:
+//
+
+#define SYMBIAN_NETWORKING_UPS
+
+#include <es_prot.h>
+#include <comms-infras/ss_roles.h>
+#include <comms-infras/ss_log.h>
+#include "es_mbufif.h"
+#include <ss_glob.h>
+#include <ss_protprov.h>
+#include <comms-infras/ss_sapshim.h>
+#include <comms-infras/ss_intsock.h>
+#include <in_sock.h>
+#include "ss_flowrequest.h"
+#include "ss_sapfactshim.h"
+#include <comms-infras/ss_nodemessages_dataclient.h>
+#include <comms-infras/cfmacro.h>
+#include <comms-infras/ss_msgintercept.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <es_sock_internal.h>
+#endif
+
+#ifdef SYMBIAN_NETWORKING_UPS
+#include <comms-infras/ss_platsec_apiext.h>		// MPlatSecApiExt
+#endif //SYMBIAN_NETWORKING_UPS
+
+#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_ESockSSocksntsck, "ESockSSocksntsck");
+#endif
+
+
+using namespace ESock;
+using namespace Messages;
+using namespace Factories;
+using namespace Den;
+
+/**
+ @internalComponent
+ */
+const TUint KAllSelectFlags = (KSockSelectRead | KSockSelectWrite | KSockSelectExcept);
+
+#define MSG_PRM(prmIndex)		(prmIndex)
+
+
+ASocket::ASocket(TInt aSocketType)
+	: iSocketType(aSocketType),
+	  iIsFlowRequestPending(EFalse)
+/**
+ Constructor - set up default options.
+ */
+	{
+	}
+
+const RNodeInterface* ASocket::ServiceProvider() const
+	{
+	return iServiceProvider.IsOpen()? &iServiceProvider : NULL;
+	}
+
+TBool ASocket::GetFlowAndSCPR(Messages::TNodeId& aFlow, Messages::TNodeId& aSCPR) const
+    {
+    if (iFlowBinder)
+        {
+    	aFlow = iFlowBinder->Flow()->Id();
+    	aSCPR = iFlowBinder->Flow()->ControlProvider().RecipientId();
+    	return ETrue;
+        }
+    return EFalse;
+    }
+
+void ASocket::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>())
+		{
+		TCFDataClient::TBindTo& bindToMsg(static_cast<TCFDataClient::TBindTo&>(aMessage));
+
+		TInt err;
+		if (IsClosing())
+			{
+			err = KErrAbort;
+			}
+		else
+			{
+			TRAP(err,BindToL(bindToMsg));
+			}
+
+		RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete(err).CRef());
+
+		CompleteFlowRequestMessage(err);
+		SetFlowRequestPending(EFalse);
+
+		if ( IsClosing () )
+			InitiateDestruction ();
+		}
+    else
+        {
+   		__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksntsck, 1));
+    	}
+    }
+
+void ASocket::BindToL(const TCFDataClient::TBindTo& aBindTo)
+    {
+    __ASSERT_DEBUG(iSSP==NULL, User::Panic(KSpecAssert_ESockSSocksntsck, 2));
+
+#ifdef SYMBIAN_NETWORKING_UPS
+	LOG(ESockLog::Printf(_L8("CSocket %08x:\tBindToL(%08x)"), this, &aBindTo.iNodeId.Node()) );
+	LOG(ESockLogExternal::Printf(KCFNodeTag, KESockFlowTag, _L8("CSocket %08x:\tSynchronous call: Sender=%08x, Recipient=%08x, Function=BindToL"), this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) );
+#endif
+
+#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)
+        {
+	    NM_LOG((KESockServerTag, _L8("CSocket %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL Error flow is null"),
+				this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) )
+        User::Leave(KErrArgument);
+        }
+
+    NM_LOG((KESockServerTag, _L8("CSocket %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL"),
+			this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) )
+
+	// Perform the binding to the flow below
+	iFlowBinder = flow->GetBinderControlL();
+	iServiceProvider.Open(iFlowBinder->Flow()->Id());
+	iSSP = iFlowBinder->GetControlL(iProtocolInfo->iSockType, *this);
+	iSSPData = iFlowBinder->BindL(*this);
+
+	if(RequiresOwnerInfo())
+		{
+		CommunicateOwner();
+		}
+
+	// ask the socket provider to perform security policy checking
+	TInt ret = SecurityCheck();
+    NM_LOG((KESockServerTag, _L8("CSocket %08x:\tSynchronous call: From=%08x To=%08x Func=SecurityCheck Result Error Code=%d"),
+			this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node(), ret) )
+	User::LeaveIfError(ret);
+	iSSP->Start();
+    }
+
+
+void ASocket::AcceptSetupL(const ASocket& aParentSocket, CSubConnectionFlowBase& aFlow)
+/**
+Copy constructor type thing for Accept
+Takes all the useful info from a parent socket, sets up the supplied SSP and
+Other default values.
+*/
+	{
+	iOptions = aParentSocket.iOptions;
+	iProtocolInfo = aParentSocket.iProtocolInfo;
+
+    __ASSERT_DEBUG(iFlowBinder==NULL, User::Panic(KSpecAssert_ESockSSocksntsck, 3));
+	iFlowBinder = aFlow.GetBinderControlL();
+	iSSP = iFlowBinder->GetControlL(iProtocolInfo->iSockType, *this);
+	iSSPData = iFlowBinder->BindL(*this);
+	iIsBound=ETrue;
+
+	iRecBufSize=aParentSocket.iRecBufSize;
+	iSendBufSize=aParentSocket.iSendBufSize;
+	}
+
+void ASocket::Create(TServerProtocolDesc *aServiceInfo)
+/**
+Create for all sockets.
+*/
+	{
+	/** We create non connection orinted sockets "Open" and sockets without an ssp "NULL" */
+	if (!aServiceInfo)
+		{
+		SetState(ESStateNull);
+		UnregisterSelf();	// Null sockets need no cookie (and subsequently trying to deregister from a different Accept()ing Player is problematic and adds no benefit
+		}
+	else
+		{
+		iProtocolInfo=aServiceInfo;
+		if (!IsConnectionOriented())
+			{
+			SetState(ESStateOpen);
+			}
+		}
+
+	iOptions=KESocketDefaultOptions;
+	iIsBound=EFalse;
+
+#ifdef ESOCK_GULP
+    // allocate extra memory for experimental gulp implementation
+    iRecBufSize=KSocketDefaultBufferSize * 4;
+#else
+    iRecBufSize=KSocketDefaultBufferSize;
+#endif
+	iSendBufSize=KSocketDefaultBufferSize;
+	}
+
+
+ASocket::~ASocket()
+/**
+Socket destructor. Will ensure that the SSP (and any accept queue) is shutdown before destroying it.
+Automatically completes all outstanding requests.
+
+*/
+	{
+	iServiceProvider.Close();
+
+	delete iDisconnectData;
+	iDatagramTail.Free();	// we should normally have done this in closing
+	iSendData.Free();		// we should normally have done this in closing
+
+	if (iAcceptQ)
+		{
+		while (iAcceptQ->Count())
+			{
+			TAcceptQEntry a;
+			iAcceptQ->Remove(&a);
+
+			// the SSPs on an accept queue shouldn't have been Start()ed so we don't need to shut them down.
+			// a.iSSP->DeleteMeNow();	// destruction no longer synchronous & vertical
+			CTransportFlowShim* shimFlow = factoryobject_cast<CTransportFlowShim>(a.iSSP);
+
+		 	// The SAP is no longer owned by the listener socket.
+			shimFlow->iListenerControlNotify = NULL;
+
+			shimFlow->InitDestroy();
+			delete a.iConnectData;
+			}
+		delete iAcceptQ;
+		}
+	delete iNextAcceptQ;
+	delete iAllocAsync;
+
+	delete iCurrentMsg;
+	delete iReadMsg;
+	delete iWriteMsg;
+	delete iBlockedCloseMsg;
+	delete iBlockedConnectMsg;
+	delete iBlockedIoctlMsg;
+	delete iBlockedSetLocalNameMsg;
+	}
+
+void ASocket::InitiateDestruction()
+    {
+    SetClosing();
+
+    if (iSSP)
+		{
+		if ((State()==ESStateOpeningActive || State()==ESStateOpeningPassive
+			|| State()==ESStateOpen || State()==ESStateConnected
+||  State()==ESStateBinding
+			))
+		    {
+		    iSSP->Shutdown(MSessionControl::EImmediate);
+		    }
+
+		__ASSERT_DEBUG(iFlowBinder, User::Panic(KSpecAssert_ESockSSocksntsck, 4));
+		iFlowBinder->Unbind();
+		}
+
+    /*
+		CSubConnectionFlowBase* flow = iFlowBinder->Flow();
+		if(!flow->HasControlPlane())
+			{
+			CNetworkFlow* netFlow = static_cast<CNetworkFlow*>(flow);
+			delete netFlow;
+			iSSP = NULL;
+			delete this;
+			}
+
+		}
+	else
+		{
+		// Either stillborn with OOM or after Shutdown() has detached
+		delete this;
+		}
+     */
+    }
+
+void ASocket::ShutdownL(RSocket::TShutdown aType, TBool aDisconnectData)
+/**
+Terminate the protocol
+*/
+	{
+	if (State()==ESStateShuttingDown)
+		{
+		PanicSocketClient(EShutDownTwice);
+		return;
+		}
+
+	if (!CheckRunningAndSetReturn())
+		{
+		return;
+		}
+
+	MSessionControl::TCloseType h=MSessionControl::ENormal;
+	if (SupportsGracefulClose())
+		{
+		switch (aType)
+			{
+		case RSocket::ENormal:
+			CompleteWrite(KErrCancel);
+			CompleteRead(KErrCancel);
+			h=MSessionControl::ENormal;
+			iBlockedOperations|=(EReadStopped|EWriteStopped);
+			break;
+		case RSocket::EStopInput:
+			CompleteRead(KErrCancel);
+			h=MSessionControl::EStopInput;
+			iBlockedOperations|=EReadStopped;
+			iDatagramTail.Free();
+			break;
+		case RSocket::EStopOutput:
+			h=MSessionControl::EStopOutput;
+			iBlockedOperations|=EWriteStopped;
+			CompleteWrite(KErrCancel);
+			break;
+		case RSocket::EImmediate:
+			h=MSessionControl::EImmediate;
+			CompleteWrite(KErrCancel);
+			CompleteRead(KErrCancel);
+			iDatagramTail.Free();
+			break;
+			}
+		}
+	else
+		{
+		CompleteWrite(KErrCancel);
+		CompleteRead(KErrCancel);
+		h=MSessionControl::EImmediate;
+		}
+
+	CompleteConnect(KErrCancel);
+	CompleteSetLocalName(KErrCancel);
+
+	SetState(ESStateShuttingDown);
+
+	if(h!=MSessionControl::EImmediate)
+	    {
+	    SetBlockedClose();
+	    DontCompleteCurrentRequest();
+	    }
+
+	if (CanSendDisconnectData() && h!=MSessionControl::EImmediate && aDisconnectData)
+		{
+        TDes8& sendBuf = *BorrowTemporaryBufferL(iSendBufSize);
+		ReadParamL(ESocketCurrentMessage,MSG_PRM(1),sendBuf);
+		iSSP->Shutdown(h,sendBuf);
+		}
+	else
+		{
+		iSSP->Shutdown(h);
+		}
+
+	if (iErrorOperationMask & MSessionControlNotify::EErrorClose)
+		{
+		SetReturn(iError);
+		ClearErrorIfNotFatal(); //Sets iError = 0;
+		iErrorOperationMask = 0;
+		}
+	// OK to access socket because a CanClose would set the socket state to dead
+	else if (h==MSessionControl::EImmediate)
+		{
+		// Set state to dead - let close delete the socket
+		SetState(ESStateDead);
+		}
+	else
+		{
+		if (!(iOptions & KOptBlocking) && IsBlockedClose())
+			{
+			CompleteClose(KErrWouldBlock);
+			}
+		}
+	}
+
+TBool ASocket::CloseSocket()
+/**
+A Client has closed our RSocket - or we're being closed by the session because our client has exited
+*/
+	{
+	SetClosing();
+	TBool immediateClose = EFalse;
+	switch (State())
+		{
+	case ESStateNull:
+	case ESStateAccepting:
+	case ESStateCreated:
+	case ESStateError:
+	case ESStateDead:
+	case ESStateDisconnected:
+		immediateClose = ETrue;
+		break;
+
+	case ESStateShuttingDown:
+        CompleteClose(KErrCancel);
+		SetReturn(KErrAlreadyExists);
+		SetState(ESStateClosing);
+		immediateClose = ETrue;
+		break;
+
+	case ESStateOpeningActive:
+	case ESStateOpeningPassive:
+	case ESStateOpen:
+	case ESStateConnected:
+	case ESStateBinding:
+        {
+		SetState(ESStateClosing);
+
+        TBool graceful = SupportsGracefulClose() && iSSP;
+		// CanClose will be called irrespective of whether the socket
+		// supports graceful close or not.
+		// ASocket can take care of the ownership of deletion via InitiateDestruction.
+		// Also, CanClose will call InitiateDestruction if we are in ESStateClosing.
+		// We already set to ESStateClosing.
+	    SetBlockedClose();
+	    DontCompleteCurrentRequest(); // Block closes regardless of NonBlocking mode state
+
+        if (graceful)
+           	{
+	        iSSP->Shutdown(MSessionControl::ENormal);
+	        }
+        else
+           	{
+           	if (iSSP)
+               	{
+               	iSSP->Shutdown(MSessionControl::EImmediate);
+               	}
+            CanClose(MSessionControlNotify::EDelete);
+            }
+        }
+        break;
+
+	case ESStateClosing:
+		PanicSocketClient(ECloseTwice);
+		break;
+		}
+	return immediateClose;
+	}
+
+void ASocket::BindL()
+/**
+Set local address from a client request.
+*/
+	{
+	if (!CheckRunningAndSetReturn())
+		{
+		return;
+		}
+
+	if (IsConnectionOriented() && iIsBound)
+		{
+		SetReturn(KErrAlreadyExists);
+		}
+	else
+if (State() == ESStateBinding)
+		{
+		SetReturn(KErrInUse);
+		}
+		else
+		{
+		TSockAddr a;
+		ReadParamL(ESocketCurrentMessage,MSG_PRM(0),a);
+		
+		
+		// Set to blocked before call to SetLocalName. This allows for immediate callback,
+		// as some conditions may not require asynchronous processing.
+		SetBlockedSetLocalName();
+		DontCompleteCurrentRequest();
+
+		// Save off the state for transition later.
+		iNextState = State();
+		SetState(ESStateBinding);
+		
+		iSSP->SetLocalName(a);
+
+		}
+	}
+
+void ASocket::AutoBind()
+	{
+	iSSP->AutoBind();
+	iIsBound=ETrue;
+	}
+
+
+void ASocket::ConnectL(TBool aConnectData)
+/**
+Active open the socket - from a client request.
+*/
+	{
+	TSockAddr a;
+	TInt ret=KErrNone;
+	switch (State())
+		{
+	case ESStateOpeningActive:
+	case ESStateOpeningPassive:
+		PanicSocketClient(EConnectingAlready);
+		break;
+		
+		case ESStateBinding:
+		SetReturn(KErrInUse);
+		break;
+
+	case ESStateConnected:
+		if (IsConnectionOriented())
+			{
+			if(IsBlockedConnect())
+				{
+				PanicSocketClient(EConnectingAlready);
+				}
+
+			SetReturn(KErrAlreadyExists);
+			return;
+			}
+		// Fall through - non connection oriented sockets can call Connect as much as they like.
+	case ESStateOpen:
+	case ESStateCreated:
+		{
+		ReadParamL(ESocketCurrentMessage,MSG_PRM(0),a);
+
+		ret=iSSP->SetRemName(a);
+		if (ret!=KErrNone)
+			{
+			SetReturn(ret);
+			return;
+			}
+
+		if(!iIsBound)
+			{
+			SetBlockedConnect();
+			DontCompleteCurrentRequest();
+			
+			if (!IsConnectionOriented())
+			    {
+			    iNextState = ESStateConnected;
+				}
+			else
+				{
+				iConnectData = aConnectData;
+			    iNextState = ESStateOpeningActive;
+				}
+			SetState(ESStateBinding);
+			AutoBind();
+
+			if (!(iOptions&KOptBlocking) && IsBlockedConnect())
+				{
+				CompleteConnect(KErrWouldBlock);
+				}
+			return;
+		
+			}
+
+		if (!IsConnectionOriented())
+		    {
+			SetState(ESStateConnected);
+			TryToCompleteSelectIoctl();
+		    }
+		else
+			{
+
+			SetBlockedConnect();
+			DontCompleteCurrentRequest();
+
+			SetState(ESStateOpeningActive);
+			
+			if (CanSendConnectData() && aConnectData)
+				{
+				TDes8& sendBuf = *BorrowTemporaryBufferL(iSendBufSize);
+				ReadParamL(ESocketCurrentMessage,MSG_PRM(1),sendBuf);
+				iSSP->ActiveOpen(sendBuf);
+				}
+			else
+				{
+				iSSP->ActiveOpen();
+				}
+
+			if (!(iOptions&KOptBlocking) && IsBlockedConnect())
+				{
+				CompleteConnect(KErrWouldBlock);
+				}
+			}
+		}
+		break;
+	case ESStateDisconnected:
+	case ESStateShuttingDown:
+	case ESStateClosing:
+	case ESStateDead:
+		SetReturn(KErrBadHandle);
+		break;
+	case ESStateError:
+		SetReturn(iError);
+		return;
+	default:
+        PanicSocketClient(ECannotConnect);
+		//Fault(EBadState);
+		break;
+		}
+
+	}
+
+//indexes of the data elements in RMessage for Get/SetOpt
+#define  OPT_NAME_INDEX		    0
+#define  OPT_OPTION_INDEX		1 //for the option value
+#define  OPT_OPT_LENGTH_INDEX	2
+#define  OPT_OPT_LEVEL_INDEX	3
+
+/**
+    Set a socket option from a client request
+*/
+void ASocket::SetSockOptionL(TInt aOptionName, TInt aOptionLength, TInt aOptionLevel)
+	{
+
+	if (aOptionName & KSocketInternalOptionBit)
+		{
+		SetReturn(KErrAccessDenied);
+		return;
+		}
+
+	if (aOptionLevel==KSOLSocket)
+		{
+
+		TBufC8<sizeof(TUint)> smallOptionBuf;
+  		TPtr8 option=smallOptionBuf.Des();
+
+		switch(aOptionName)
+			{
+			case KSOSendBuf:
+				{
+				ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+				iSendBufSize=*(TUint*)smallOptionBuf.Ptr();
+
+				// Even though we don't respect the sendbuf size for transfers we need to
+				// be able to echo the value back to a GetOpt() - also it's used for
+				// sizing the Connect/Shutdown_WithData operations
+				if (iSendBufSize==KSocketBufSizeUndefined)
+					{
+					iSendBufSize=KSocketDefaultBufferSize;
+					iOptions&=~KOptSendBufSet;
+					break;
+					}
+
+				iOptions|=KOptSendBufSet;
+				break;
+				}
+			case KSORecvBuf:
+				{
+	            ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+				iRecBufSize=*(TUint*)smallOptionBuf.Ptr();
+
+                // Even though we don't respect the recvbuf size for transfers we need to
+                // be able to echo the value back to a GetOpt()
+				if (iRecBufSize==KSocketBufSizeUndefined)
+					{
+					iOptions&=~KOptRecBufSet;
+					break;
+					}
+				iOptions|=KOptRecBufSet;
+				break;
+				}
+
+			case KSODebug:
+				{
+				ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+				TBool b;
+				TPtr8 p((TUint8*)&b,sizeof(iSendBufSize),sizeof(iSendBufSize));
+				ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),p);
+				if(*(TBool*)option.Ptr())
+					{
+					iOptions|=KOptDebug;
+					}
+				else
+					{
+					iOptions&=~KOptDebug;
+					}
+				break;
+				}
+			case KSONonBlockingIO:
+				iOptions &= ~KOptBlocking;
+				break;
+			case KSOBlockingIO:
+				iOptions |= KOptBlocking;
+				break;
+
+			//-- enable socket transfer to another process with capabilities check.
+			//-- socket option must be TPckgBuf<TSecurityPolicy>, TSecurityPolicy in turn must contain the capabilities set for the
+			//-- process that is going to receive this socket as a result of RSocket::Transfer().
+			case    KSOEnableTransfer:
+				{
+				if(State() == ESStateNull || State() == ESStateAccepting)
+					{
+					User::Leave(KErrNotReady);
+					}
+			    //-- read security information (capabilities set) from the client
+			    TSecurityPolicyBuf secPolicyBuf;
+			    ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),secPolicyBuf);
+
+			    //-- store the capabilities set for the future check in ProtocolManager::TransferSocketL()
+			    iSecTransferEnabled=EFalse;
+			    User::LeaveIfError(iTransferSecPolicy.Set(secPolicyBuf));
+			    iSecTransferEnabled=ETrue; //-- indication that the RSocket::Transfer() security information is ready to check
+				}
+			break;
+
+			//-- Disable socket transfer by indicating that the transfer security information is not valid
+			case    KSODisableTransfer:
+			    iSecTransferEnabled=EFalse;
+			break;
+
+
+			default:
+				SetReturn(KErrNotSupported);
+			}
+		}
+	else
+		{
+		if (CheckRunningAndSetReturn())
+			{
+			HBufC8* optionBuf=NULL;
+			optionBuf=HBufC8::NewMaxLC(aOptionLength);
+			TPtr8 option=optionBuf->Des();
+			ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+			SetReturn(iSSP->SetOption(aOptionLevel,aOptionName,option));
+			CleanupStack::PopAndDestroy(optionBuf);
+			}
+		}
+	}
+
+void ASocket::GetSockOptionL(TInt aOptionName, TInt aOptionLength, TInt aOptionLevel, TInt aWriteBack)
+/**
+Read a socket option from us (or attempt the protocol if we don't support the option)
+
+*/
+	{
+
+	if (aOptionName&KSocketInternalOptionBit)
+		{
+		SetReturn(KErrAccessDenied);
+		return;
+		}
+	if (aOptionLevel==KSOLSocket)
+		{
+		// Most KSOLSocket options use argument1 as an out parameter
+		switch(aOptionName)
+			{
+		case KSOSendBuf:
+		case KSORecvBuf:
+		case KSODebug:
+		case KSONonBlockingIO:
+		case KSOBlockingIO:
+		case KSOSelectPoll:
+			{
+			if(aWriteBack)
+				{
+				// Retrieve the required value
+				TUint optionVal;
+				switch(aOptionName)
+					{
+				case KSOSendBuf:
+					{
+					optionVal =iSendBufSize;
+					break;
+					}
+				case KSORecvBuf:
+					{
+					optionVal =iRecBufSize;
+					break;
+					}
+				case KSODebug:
+					{
+					optionVal =(iOptions&KOptDebug);
+					break;
+					}
+				case KSONonBlockingIO:
+					{
+					optionVal =!(iOptions&KOptBlocking);
+					break;
+					}
+				case KSOBlockingIO:
+					{
+					optionVal =iOptions&KOptBlocking;
+					break;
+					}
+				case KSOSelectPoll:
+					{
+					if(CheckRunningAndSetReturn())
+						{
+						optionVal =SelectConditionsReady();
+						}
+					else
+						{
+						aWriteBack = EFalse;
+						}
+					break;
+					}
+                // coverity [dead_error_begin] :
+				default:
+			        // the default should never be called and is there to catch coding errors.
+					__ASSERT_DEBUG(0, User::Panic(KSpecAssert_ESockSSocksntsck, 5));
+				}
+				if(aWriteBack)
+					{
+					TPckg <TUint> option(optionVal);
+					WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+					}
+				}
+			else
+				{
+				// Somehow they passed a NULL second argument - should we panic them?
+				SetReturn(KErrArgument);
+				}
+
+			break;
+			}
+		case KSOSelectLastError:
+			{
+			SetReturn(iError);
+					
+			if(aWriteBack)
+				{
+				TPckg <TUint> option(iError);
+				WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+				}
+			else
+				{
+				// Somehow they passed a NULL second argument - should we panic them?
+				SetReturn(KErrArgument);
+				}
+						
+		    ClearErrorIfNotFatal();
+			break;
+			}
+
+		case KSOReadBytesPending:
+		case KSOUrgentDataOffset:
+			{
+			if(!CheckRunningAndSetReturn())
+				{
+				break;
+				}
+
+			if(aOptionName==((TInt)KSOUrgentDataOffset) && !CanSendUrgentData())
+				{
+				SetReturn(KErrNotSupported);
+				break;
+				}
+			TSockXfrLength len;
+			len()=iRecOffset;
+			SetReturn(iSSP->GetOption(aOptionLevel,aOptionName,len));
+			if (aWriteBack)
+				{
+				WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),len);
+				}
+			break;
+			}
+		default:
+			SetReturn(KErrNotSupported);
+		}
+		}
+
+	else
+		{
+		if(CheckRunningAndSetReturn())
+			{
+			if (aWriteBack)
+				{
+				RBuf8 optionBuf;
+				optionBuf.CreateMaxL(aOptionLength);
+				CleanupClosePushL(optionBuf);
+				TPtr8 option=optionBuf.MidTPtr(0);
+				ReadParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+				SetReturn(iSSP->GetOption(aOptionLevel,aOptionName,option));
+				WriteParamL(ESocketCurrentMessage,MSG_PRM(OPT_OPTION_INDEX),option);
+				CleanupStack::PopAndDestroy(&optionBuf);
+				}
+			else
+        		{
+        		SetReturn(KErrArgument);
+        		}
+			}
+		}
+	}
+
+void ASocket::IoctlL(TInt aOptionName, TInt aOptionLength, TInt aOptionLevel, TBool aReadOption)
+/**
+Perform an Ioctl from a user request
+*/
+	{
+
+	if (IsBlockedIoctl())
+		{
+		PanicSocketClient(ETwoIoctls);
+		return;
+		}
+
+	if (aOptionName&KInternalIoctlBit)
+		{
+		SetReturn(KErrAccessDenied);
+		return;
+		}
+
+	if (aOptionLevel==KSOLSocket)
+		{
+
+		if(aOptionName==(TInt)KIOctlSelect)
+		    {
+
+			if(!CheckRunningAndSetReturn())
+				{
+				return;
+				}
+            TPckgBuf<TUint> flags;
+			ReadParamL(ESocketCurrentMessage,MSG_PRM(1), flags);
+			iSelectFlags=flags();
+			if((iSelectFlags&KAllSelectFlags)!=0)
+			    {
+                SetBlockedIoctl();
+		        DontCompleteCurrentRequest();
+			    TryToCompleteSelectIoctl();
+			    }
+			else
+				{
+                SetReturn(KErrArgument);
+                }
+		    }
+		else
+			{
+		    SetReturn(KErrNotSupported);
+		    }
+		}
+	else
+		{
+//		if(!(iOptions & KOptBlocking))
+//			{
+//			SetReturn(KErrWouldBlock);
+//			return;
+//          }
+
+//		if (CheckRunningAndSetReturn()==EFalse)
+//	        return;
+		if(iSSP == NULL)
+			{
+		    SetReturn(KErrNotSupported);
+			return;
+			}
+
+		if (aReadOption)
+			{
+			if(aOptionLength < 0)
+				{
+				User::Leave(aOptionLength);
+				}
+			HBufC8* ioctlBuf=HBufC8::NewLC(aOptionLength);
+			TPtr8 des=ioctlBuf->Des();
+			ReadParamL(ESocketCurrentMessage,MSG_PRM(1),des);
+			// only set ioctl blocked if successfull allocation
+			SetBlockedIoctl();
+			DontCompleteCurrentRequest();
+
+			iSSP->Ioctl(aOptionLevel,aOptionName,&des);
+            CleanupStack::PopAndDestroy(ioctlBuf);
+			}
+		else
+			{
+			SetBlockedIoctl();
+			DontCompleteCurrentRequest();
+			iSSP->Ioctl(aOptionLevel,aOptionName,NULL);
+			}
+		}
+	LOG(
+		if (IsBlockedIoctl())
+			{
+			ESockLog::Printf(KESockSessDetailTag, _L8("ASocket::IoctlL blocking") );
+			}
+		)
+	}
+
+void ASocket::CancelIoctl()
+/**
+Cancel a pending Ioctl and notify the protocol.
+*/
+	{
+	if(IsBlockedIoctl())
+		{
+		TInt optionLevel = 0;
+		TInt optionName = 0;
+		if(!iSelectFlags)
+			{
+			optionLevel = iBlockedIoctlMsg->ReadInt(2);
+			optionName = iBlockedIoctlMsg->ReadInt(0);
+			}
+
+		CompleteIoctl(KErrCancel);
+
+		if(iSelectFlags)
+			{
+		    iSelectFlags=0;
+			}
+		else
+			{
+			__ASSERT_ALWAYS(iSSP!=NULL, Panic(ENullSap));
+		    iSSP->CancelIoctl(optionLevel, optionName);
+			}
+		}
+	}
+
+void ASocket::GetDisconnectDataL( ) const
+/**
+Get disconnect data if any is present on the socket.
+*/
+	{
+	if (CanSendDisconnectData())
+		{
+		if(iDisconnectDataError!=KErrNone)
+			{
+			SetReturn(iDisconnectDataError);
+			}
+		else if (iDisconnectData)
+			{
+			TPtr8 des=iDisconnectData->Des();
+			const_cast<ASocket*>(this)->WriteParamL(ESocketCurrentMessage,MSG_PRM(0),des);
+			}
+		else
+			{
+			SetReturn(KErrNotFound);
+			}
+		}
+	else
+		{
+		SetReturn(KErrNotSupported);
+		}
+	}
+
+static const TInt KPaddingForHeaders = 48;
+
+void ASocket::SendL(TInt aXferLenArg, TInt aAddrArg, TInt aSendByteCount, TInt aSendFlags, TBool aUseMBufs)
+/**
+ Common message service for Send, SendTo and Write.
+*/
+	{
+	if (IsBlockedWrite())
+		{
+		PanicSocketClient(EWritingAlready);
+		return;
+		}
+
+	if (!CheckRunningAndSetReturn())
+		{
+		return;
+		}
+
+	// Judge If the socket is connected during a connection-oriented service.
+	if (IsConnectionOriented() && iState != ESStateConnected)
+		{
+		LOG( ESockLog::Printf(_L("ASocket %08x SendL() KErrNotReady"), this ) );
+		SetReturn(KErrNotReady);
+		return;
+		}
+
+	if(iBlockedOperations & EWriteStopped)
+		{
+		if(aXferLenArg >= 0)
+			{
+			iXferLength() = 0;
+			WriteParamL(ESocketCurrentMessage, aXferLenArg, iXferLength);
+			}
+		SetReturn(KErrEof);
+		return;
+		}
+
+	// Set whether we are sending RMbufChain or not
+	iSendUseMBufs = aUseMBufs;
+
+	iSendByteCount=aSendByteCount;
+	iSendXferLenIdx = aXferLenArg;
+	iSendToAddrIdx = aAddrArg;
+    if (iSendToAddrIdx >= 0)
+        {
+        if(IsConnectionOriented())
+            {
+            PanicSocketClient(ECantSendToOnConnection);
+            return;
+            }
+        }
+    else    // Not ESendTo...
+        {
+        if(State() != ESStateConnected  && State() != ESStateShuttingDown && iSendToAddrIdx != ASocket::KWriteNoAddrArg)
+            {
+            LOG( ESockLog::Printf(_L("ASocket %08x SendL() 2 KErrNotReady"), this ) );
+            SetReturn(KErrNotReady);
+            return;
+            }
+        }
+	iSendFlags = aSendFlags;
+	if(iSendFlags)
+	    {
+        if(iSendFlags&KSocketInternalWriteBit)
+            {
+            SetReturn(KErrAccessDenied);
+            return;
+            }
+        if ((iSendFlags&KSockWriteUrgent) && !CanSendUrgentData())
+            {
+            SetReturn(KErrNotSupported);
+            return;
+            }
+	    }
+	__ASSERT_DEBUG(iSendData.IsEmpty(), Fault(EBufsLeftInSendData));	// no pathway should leave this populated after Write completes
+	iSendData.Free();	// but paranoia is cheap 
+
+	if(iSendByteCount<0)
+		{
+		PanicSocketClient(EBadDescriptorLength);
+		return;
+		}
+	
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+	IncludePerformanceData(-1, -1, iSendByteCount);
+#endif
+
+	if (iIsBound==EFalse)
+		{
+
+		if (State() == ESStateBinding)
+			{
+			SetReturn(KErrInUse);
+			return;
+			}
+		AutoBind();
+		}
+	iSendOffset=0;
+	DoSend(ETrue);
+	}
+
+void ASocket::DoSend(TBool aInitialRequest)
+	{
+	AMessage* msg = aInitialRequest? iCurrentMsg: iWriteMsg;
+	ASSERT(msg);
+	
+	TInt ret = KErrNone;
+	TBool completeReq = ETrue;
+	
+	if (IsStream())
+		{
+		ret = FillStreamProtocol(msg);
+
+		if(iSendByteCount > 0)
+			{
+			// Still data to write - flow-off or error
+			if(ret != KErrNone)
+				{
+				if(ret == KErrNoMBufs)
+					{
+					ret = RequestAsyncMBufAllocation(CWaitForMBufs::ECanSend, iSendByteCount);
+					}
+				if(ret != KErrNone)
+					{
+					ret = KErrNoMemory;
+					}
+				}
+			if(ret == KErrNone && (iOptions & KOptBlocking))
+				{
+				completeReq = EFalse;
+				}
+			}
+		}
+	else	// !IsStream()
+		{
+		if (aInitialRequest && ((iProtocolInfo->iMessageSize!=KSocketMessageSizeNoLimit) && (iProtocolInfo->iMessageSize!=KSocketMessageSizeUndefined) && (iSendByteCount>iProtocolInfo->iMessageSize)) ||
+					((iOptions&KOptSendBufSet) && iSendByteCount>iSendBufSize))
+			{
+			SetReturn(KErrTooBig);
+			return;
+			}
+
+		RMBufChain data;
+	   	TInt nwr = KErrNone;
+		TInt actualSendLen = 0;		// total size of data accepted by protocol upon datagram write
+		TInt actualBufSize = 0;
+		if(aInitialRequest || iSendData.IsEmpty())
+			{
+			if (iSendUseMBufs)
+				{
+				ret = msg->ReadMBuf(MSG_PRM(2),data);
+				actualSendLen = data.Length();
+				actualBufSize = data.First()->Size();
+				}
+			else
+				{
+	 			// Possible outcomes:
+	 			//	(1) We fail to create the MBuf chain with the client data:
+	 			//		(a) with KErrNoMbufs - we start an asynchronous allocation and treat it as a flow-off
+	 			//		(b) with some other -ve error code - we treat this as KErrNoMemory and complete the client
+	 			//	(2) SAP fails to write the mbuf chain:
+	 			//		(a) with KErrNoMbufs - we start an asynchronous allocation on its behalf and treat it as a flow-off
+	 			//		(b) with zero, ie flow-off: we don't complete client
+	 			//		(c) with some other -ve error code - we treat this as KErrNoMemory and complete the client
+	 			//	(3) SAP write succeeds and returns > 1 - we complete the client with KErrNone
+				// get MBuf chain immediately, copy avoiding iSendBuf if possible
+
+				ret = data.Alloc(iSendByteCount + KPaddingForHeaders, iAllocator);
+				if(ret == KErrNone)
+					{
+					RMBuf* first = data.First();
+					if(first->Size() >= (iSendByteCount + KPaddingForHeaders))
+						{
+						// Read directly into buffer
+						first->SetData(KPaddingForHeaders, iSendByteCount);
+					   	TPtr8 des(NULL, 0);
+						des.Set(first->Ptr(), iSendByteCount, iSendByteCount);
+						ret = msg->ReadDes(MSG_PRM(2),des);
+						actualSendLen = des.Length();
+						actualBufSize = actualSendLen;
+						}
+					else
+						{
+						// Have to use local descriptor to avoid multiple IPC round trips
+						TDes8* sendBuf = BorrowTemporaryBuffer(iSendByteCount);
+						if(!sendBuf)
+							{
+							// We can't allocate a buffer as big as the client so risk losing data
+							// they've indicated as precious if it overflows. Failing immediately
+							// without trying is the compatible option
+							ret = KErrNoMemory;
+							}
+						else
+							{
+							if(first->Length() > KPaddingForHeaders)
+								{
+								first->AdjustStart(KPaddingForHeaders);
+								}
+							else
+								{
+								data.TrimStart(KPaddingForHeaders);
+								}
+							ret = msg->ReadDes(MSG_PRM(2), *sendBuf);	// read failure exceedingly rare so don't bother checking return yet
+							actualSendLen = sendBuf->Length();
+							actualBufSize = actualSendLen;
+							data.CopyIn(*sendBuf);
+							}
+						}
+					}
+				}
+			}
+		else
+			{
+			// Resume with the RMBufChain we already fabricated 
+			data.Assign(iSendData);
+			if (iSendUseMBufs)
+				{
+				actualSendLen = data.Length();
+				actualBufSize = data.First()->Size();
+				}
+			else
+				{
+				actualSendLen = data.Length();
+				actualBufSize = actualSendLen;
+				}
+			}
+
+		if (ret == KErrNone)
+			{
+			// Clear the error operation mask.  If a protocol errors the socket whilst in the
+			// context of the CServProviderBase::Write(...) down call, we will see it below.
+			iErrorOperationMask = 0;
+			if (iSendToAddrIdx < 0)
+				{
+				nwr = iSSPData->Write(data, iSendFlags, NULL);
+				}
+			else
+				{
+				TSockAddr addr;
+				ret = msg->ReadDes(iSendToAddrIdx, addr);
+				if(ret == KErrNone)
+					{
+					nwr = iSSPData->Write(data, iSendFlags, &addr);
+					}
+				}
+
+			if (nwr == 0)
+				{
+				// Flow unable to accept data but not erroring
+				completeReq = EFalse;
+				iSendData.Assign(data);
+				}
+
+			if (iErrorOperationMask & (MSessionControlNotify::EErrorSend))
+				{
+				// Protocol has errored the socket.  Complete the current operation with the error.
+				// If the error is not fatal, then it is assumed to be for the current operation only,
+				// so clear down the error.
+				nwr = iError;
+				completeReq = ETrue;
+				ClearErrorIfNotFatal(); //Sets iError = 0;
+				iErrorOperationMask = 0;
+				iSendData.Free();
+				}
+
+			if(nwr < 0)
+				{
+				ret = nwr;
+				}
+			else if(iSendXferLenIdx >= 0)
+				{
+				iSendOffset = actualSendLen - data.Length();
+				}
+			if (!iSendUseMBufs)
+				{
+				// nwr > 0 == Sending using RMBufChain where we have to ensure the data is
+				// freed once the Send is succeeded
+				// Protocols must remove buffers they want to use
+				data.Free();
+				}
+			else
+				{
+				if (nwr > 0)
+					{
+					msg->InitMBuf(MSG_PRM(2));
+					}
+				}
+			}
+		if(ret != KErrNone)
+			{
+			if(ret == KErrNoMBufs)
+				{
+				ret = RequestAsyncMBufAllocation(CWaitForMBufs::ECanSend, actualBufSize);
+				if(ret != KErrNone)
+					{
+					ret = KErrNoMemory;
+					}
+				}
+			if(ret == KErrNone)
+				{
+				if(iOptions & KOptBlocking)
+					{
+					completeReq = EFalse;
+					}
+				else
+					{
+					ret = KErrWouldBlock;
+					}
+				}
+			}
+		}
+
+	if(completeReq)
+		{
+		// Write completed
+		if(iSendXferLenIdx >= 0)
+			{
+			iXferLength() = iSendOffset;
+			TInt lenRet = msg->WriteDes(iSendXferLenIdx, iXferLength);
+			if(lenRet != KErrNone && ret == KErrNone)
+				{
+				ret = lenRet;
+				}
+			}
+		// KErrBadDescriptor means that the client has already been panicked; we must
+		// avoid further completion of this message 
+		if(ret == KErrBadDescriptor)
+			{
+			iBlockedOperations&=~EBlockedWrite;
+			}
+		else
+			{
+			if(aInitialRequest)
+				{
+				SetReturn(ret);
+				}
+			else
+				{
+				CompleteWrite(ret);
+				}
+			}
+		}
+	else
+		{
+		if(aInitialRequest)
+			{
+			// Doesn't matter if the client has already been panicked; we're acquiring the now-NULL msg
+			iWriteMsg->AcquireMessage(msg);
+			SetBlockedWrite();
+			iBlockedOperations|=EWriteFlowedOff;
+			DontCompleteCurrentRequest();
+			}
+		}
+	}
+
+void ASocket::RecvL(TInt aXferLenArg, TInt aAddrArg, TInt aReadByteCount, TInt aReadFlags, TBool aUseMBufs, TInt aRecvOneOrMore)
+/**
+ Common service routine from Recv, RecvFrom and Read.
+*/
+	{
+	if (IsBlockedRead())
+		{
+		PanicSocketClient(EReadingAlready);
+		return;
+		}
+
+	if (!CheckRunningAndSetReturn())
+		{
+		return;
+		}
+
+	if (IsConnectionOriented())
+		{
+		if (State()!=ESStateConnected && State()!=ESStateShuttingDown)
+			{
+			LOG( ESockLog::Printf(_L("ASocket %08x RecvL() KErrNotReady"), this ) );
+			SetReturn(KErrNotReady);
+			return;
+			}
+		if (iIsBound==EFalse)
+			{
+			if (State() == ESStateBinding)
+    			{
+    			SetReturn(KErrInUse);
+    			return;
+				}
+			AutoBind();
+			}
+		if (aAddrArg >= 0)
+			{
+			SetReturn(KErrNotSupported);
+			return;
+			}
+		}
+
+	iRecvOneOrMore = aRecvOneOrMore;
+	if(iRecvOneOrMore && !IsStream())
+		{
+		SetReturn(KErrNotSupported);
+		return;
+		}
+
+	// Set whether we are going to receive in RMBufChain way
+	iRecvUseMBufs = aUseMBufs;
+
+	iRecByteCount=aReadByteCount;
+    if(iRecByteCount<0)
+        {
+        PanicSocketClient(EBadDescriptorLength);
+        User::Leave(KErrBadDescriptor);
+        }
+	iRecvFlags=aReadFlags;
+	if(iRecvFlags)
+	    {
+        if(iRecvFlags&KSocketInternalReadBit)
+            {
+            SetReturn(KErrAccessDenied);
+            return;
+            }
+        if (iRecvFlags&KSockReadPeek && !SupportsPeek())
+            {
+            SetReturn(KErrNotSupported);
+            return;
+            }
+	    }
+	iRecvFromAddrIdx = aAddrArg;
+	iRecvXferLenIdx=aXferLenArg;
+
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+	IncludePerformanceData(-1, iRecByteCount, -1);
+#endif
+
+	iRecOffset=0;
+	DoRecv(ETrue);
+	}
+
+void ASocket::DoRecv(TBool aInitialRequest)
+	{
+	AMessage* msg = aInitialRequest? iCurrentMsg: iReadMsg;
+
+	if(aInitialRequest || IsBlockedRead())
+		{
+		TInt errReadProtocol = KErrNone;
+		TBool completeReq = ETrue;
+	
+		if((iBlockedOperations&EReadStopped) && iDataAvailable<=0)
+			{
+			TInt ret = msg->WriteDes(MSG_PRM(2), KNullDesC8);
+			iRecOffset = 0;
+			errReadProtocol = KErrEof;
+			}
+		else if (IsStream())
+		    {
+			errReadProtocol = DrainStreamProtocol(msg);
+			if(errReadProtocol == KErrNone)
+			    {
+				if(iRecvOneOrMore && iRecOffset > 0) // i.e. data received
+                    {
+                    iRecByteCount=0;
+                    }
+				if (iRecByteCount>0) // Still data expected
+                    {
+                    if(!(iBlockedOperations&EReadStopped) || iDataAvailable>0)
+                        {
+                        if ((iOptions&KOptBlocking))
+                            {
+			    // This error condition can never be reached under the current structure. Further investigation into how other teams,
+			    // such as Bluetooth, handle memory errors in this situation is needed before restructuring this method.
+
+                            //if(errReadProtocol == KErrNoMBufs)
+                            //    {
+                            //    // Block unless request fails
+							//	errReadProtocol = RequestAsyncMBufAllocation(CWaitForMBufs::ENewData, iRecByteCount/*iRecBuf.MaxLength()*/) == KErrNone;
+							//	completeReq = errReadProtocol == KErrNone;
+                            //    }
+                            //else
+                            if(iError != KErrNone)
+                                {
+                                // Don't block as protocol is already erroring client
+								errReadProtocol = iError;
+                                // If the socket error is not fatal, then reset it so that only the current
+                                // receive operation is completed with the error (not every subsequent one).
+                                ClearErrorIfNotFatal();
+                                }
+                            else
+                                {
+                                completeReq = EFalse;
+                                }
+                            }
+                        else
+                            {
+                            errReadProtocol = KErrWouldBlock;
+                            }
+                        }
+					else
+						{
+						errReadProtocol = KErrEof;
+						}
+                    }
+			    }
+		    }
+		else
+			{	// !IsStream()
+
+			// If the previous call to Recv used the KSockReadContinuation method and left iDatagramTail empty (everything
+			// up to the end of the packet was read) then tailContinuation will be false this time round - this will cause
+			// the reading of new data from iSSP below.
+			TBool tailContinuation = (iRecvFlags & KSockReadContinuation) != 0 && !iDatagramTail.IsEmpty();
+			TBool needToBlock = !tailContinuation && iDataAvailable <= 0;
+			errReadProtocol = KErrNone;
+	
+			if(aInitialRequest)
+				{
+				//-- if we have a read from the socket with flag  KSockReadPeek set
+				//-- and if we need to block, set the NewData() recursion counter to 1.
+				//-- otherwise, reset it, it will not be checked then.
+				if(needToBlock && (iRecvFlags & KSockReadPeek))
+					{
+					iBlockOnPeekReadCnt = 1;
+					}
+				else
+					{
+					iBlockOnPeekReadCnt = 0;
+					}
+				}	
+	
+			if (!needToBlock)
+				{
+				TDes8* recBuf = BorrowTemporaryBuffer(iRecByteCount);
+				if(!recBuf)
+					{
+					// We can't allocate a buffer as big as the client so risk losing data
+					// they've indicated as precious if it overflows. Failing immediately
+					// without trying is the compatible option
+					errReadProtocol = KErrNoMemory;
+					}
+				// Only read from the provider if we can't use the previous tail
+				else if(!tailContinuation)
+					{
+					// Free it only if the chain is empty. For RMBufChain read, the receiveer must have been freed it.
+					// and we don't need to free it
+					if(!iDatagramTail.IsEmpty() && !iRecvUseMBufs)
+						{
+						iDatagramTail.Free();
+						}
+					if (iRecvFromAddrIdx < 0)
+						{
+						errReadProtocol = iSSPData->GetData(iDatagramTail, iRecByteCount | KGetDataWholeDatagram, iRecvFlags);
+						}
+					else
+						{
+						errReadProtocol = iSSPData->GetData(iDatagramTail, iRecByteCount | KGetDataWholeDatagram, iRecvFlags, &iRecvFromAddr);
+						}
+					}
+				// Protocols must either deliver the request or return an error and deliver nothing
+				//__ASSERT_DEBUG( (errReadProtocol < 0 && data.IsEmpty()), Panic(EBadDataCount));
+				TInt trimTailAmount = 0;
+				if(errReadProtocol < 0)
+					{
+					// Protocol has failed to deliver, so we'll have to block. If it's a KErrNoMBufs (a likely case) then we kick off
+					// an asynch allocation for amount and upon its completion try again. Of course we cannot know whether this is the
+					// number of mbufs that the protocol wanted but it's a good guess. If it's some other error then it's up to the
+					// protocol to tell us when to retry (by signalling with NewData(0)). If it was some error that the protocol
+					// couldn't handle at all then it should have set the error upon the socket rather than expecting us to magically
+					// "do the right thing"
+					needToBlock = ETrue;
+					}
+				else
+					{
+					if (iRecvUseMBufs)
+						{
+						// We don't trim anything, when we do a RMBufChain read with KSockReadPeek is set
+						// KSockReadPeek is upto the SAP shim
+						errReadProtocol = msg->WriteMBuf(MSG_PRM(2),iDatagramTail);
+						if(errReadProtocol == KErrNone)
+							{
+							iDatagramTail.Init();
+							// Just remove the chain that we have given back from the tail. When using MBufs the
+							// client always gets the entire datagram anyway (the datagram tail mechanism is there
+							// just so someone using a descriptor can do a continuation read if it overflows, so they
+							// don't have to use 64k buffer just in case some loony soaks them with a jumbogram).
+							// So there's no trimming done & no need to discriminate between peek & normal.
+							}
+						}
+					else
+						{
+						TPtr8 des(recBuf->MidTPtr(0, iRecByteCount));
+	
+						if (!iDatagramTail.IsEmpty())
+							{
+							// intermediate descriptor copy
+							RMBuf* first = iDatagramTail.First();
+							if(!first->Next())
+								{
+								TInt copyLen = Min(first->Length(), iRecByteCount);
+								des.Set(first->Ptr(), copyLen, copyLen);
+								}
+							else
+								{
+								iDatagramTail.CopyOut(des, 0);
+								}
+							}
+						else
+							{
+							des.SetLength(0);
+							}
+						errReadProtocol = msg->WriteDes(MSG_PRM(2),des);
+						if((errReadProtocol == KErrNone && iRecvFlags & KSockReadPeek) == 0)
+							{
+							// Note the amount of data to trim after writing it to the client
+							trimTailAmount = des.Length();
+							}
+						}
+	
+	#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+					IncludePerformanceData(trimTailAmount, -1, -1);
+	#endif
+	
+					if(errReadProtocol == KErrNone)
+						{
+						if (trimTailAmount != 0)
+							{
+							iDatagramTail.TrimStart(trimTailAmount);
+							}
+						if(iRecvXferLenIdx >= 0)
+							{
+							// Number of bytes remaining. (store for later write)
+							iRecOffset = iDatagramTail.Length();
+							}
+						if(iRecvFromAddrIdx >= 0)
+							{
+							errReadProtocol = msg->WriteDes(iRecvFromAddrIdx, iRecvFromAddr);
+							}
+						if(errReadProtocol == KErrNone && !tailContinuation)
+							{
+							// When using a non-stream based socket the value iDataAvailable refers to the number of packets available.
+							// In the case where tail continuation is in use the packet may not fully have been dealt with yet (more
+							// could be read from it next time) and so the value should not be decremented yet. This is the case even
+							// if all the data up to the end of the packet has been read (the above call to TrimStart will leave
+							// iDatagramTail empty and then on the next call of this method tailContinuation will be set to false).
+							iDataAvailable--;
+							}
+						}
+					}
+				}
+	
+			if(needToBlock)
+				{
+				if (iOptions & KOptBlocking)
+					{
+					if (errReadProtocol == KErrNoMBufs)
+						{
+						// Block unless request fails
+						needToBlock = RequestAsyncMBufAllocation(CWaitForMBufs::ENewData, iRecByteCount) == KErrNone;
+						}
+					else if (iError != KErrNone)
+                        {
+                        // Don't block as protocol is already erroring client
+                        needToBlock = EFalse;
+                        errReadProtocol = iError;
+                        // If the socket error is not fatal, then reset it so that only the current
+                        // receive operation is completed with the error (not every subsequent one).
+                        ClearErrorIfNotFatal();
+                        }
+                    else if (errReadProtocol != KErrNone)
+                        {
+                        needToBlock = EFalse;
+						}
+					completeReq = !needToBlock;
+					}
+				else
+					{
+					errReadProtocol = KErrWouldBlock;
+					}
+				}
+			}
+		
+		if(completeReq)
+			{
+			// Read completed
+			if(iRecvXferLenIdx >= 0)
+				{
+				iXferLength() = iRecOffset;
+				TInt ret = msg->WriteDes(iRecvXferLenIdx, iXferLength);
+				if(ret != KErrNone && errReadProtocol == KErrNone)
+					{
+					errReadProtocol = ret;
+					}
+				}
+			// KErrBadDescriptor means that the client has already been panicked; we must
+			// avoid further completion of this message 
+			if(errReadProtocol == KErrBadDescriptor)
+				{
+				iBlockedOperations&=~EBlockedRead;
+				}
+			else
+				{
+				if(aInitialRequest)
+					{
+					SetReturn(errReadProtocol);
+					}
+				else
+					{
+					CompleteRead(errReadProtocol);
+					}
+				}
+			}
+		else
+			{
+			if(aInitialRequest)
+				{
+				// Doesn't matter if the client has already been panicked; we're acquiring the now-NULL msg
+				iReadMsg->AcquireMessage(msg);
+				SetBlockedRead();
+				DontCompleteCurrentRequest();
+				}
+			}
+		}
+    TryToCompleteSelectIoctl();
+	}
+
+void ASocket::ListenL(TInt aQlen, TBool aConnectionData)
+/**
+Listen request service
+Listen is a dead and, clients can't do anything with the socket other than Accept after a listen.
+*/
+	{
+
+	switch (State())
+		{
+	case ESStateConnected:
+	case ESStateOpeningActive:
+	case ESStateBinding:
+		SetReturn(KErrInUse);
+		return;
+	case ESStateOpeningPassive:
+		PanicSocketClient(EAlreadyListening);
+		//lint -fallthrough
+	case ESStateShuttingDown:
+	case ESStateClosing:
+	case ESStateDead:
+		SetReturn(KErrBadHandle);
+		return;
+	case ESStateDisconnected:
+		SetReturn(KErrDisconnected);
+		return;
+	case ESStateError:
+		SetReturn(iError);
+		return;
+	case ESStateNull:
+	case ESStateAccepting:
+		PanicSocketClient(ESockBadHandle);
+		return;
+	case ESStateCreated:
+	case ESStateOpen:
+	default:
+		break;
+		}
+
+	if (!IsConnectionOriented())
+		{
+		PanicSocketClient(EListenNeedsConnection);
+		return;
+		}
+
+	if (!iIsBound)
+		{
+		SetReturn(KErrBadName);
+		return;
+		}
+
+	if(!iAcceptQ)
+		{
+		iAcceptQ = new (ELeave) CCirBuf<TAcceptQEntry>;
+		}
+	CleanupStack::PushL(iAcceptQ);
+	iAcceptQ->SetLengthL(aQlen);
+
+	// Create a second queue we can transfer the contents to if we need to remove an SAP
+	// from the middle of the ring buffer.
+	if(!iNextAcceptQ)
+		{
+		iNextAcceptQ = new (ELeave) CCirBuf<TAcceptQEntry>;
+		}
+	CleanupStack::PushL(iNextAcceptQ);
+	iNextAcceptQ->SetLengthL(aQlen);
+
+	TInt ret;
+	if (aConnectionData)
+		{
+		TDes8& xferBuf = *BorrowTemporaryBufferL(iSendBufSize);
+		xferBuf.SetLength(iSendBufSize);
+		ReadParamL(ESocketCurrentMessage, MSG_PRM(1), xferBuf);
+		ret=iSSP->PassiveOpen(aQlen, xferBuf);
+		}
+	else
+		{
+		ret=iSSP->PassiveOpen(aQlen);
+		}
+
+	if (ret==KErrNone)
+		{
+		SetState(ESStateOpeningPassive);
+		}
+	else
+		{
+		SetReturn(ret);
+		}
+
+	CleanupStack::Pop(iNextAcceptQ);
+	CleanupStack::Pop(iAcceptQ);
+	}
+
+void ASocket::Accept()
+/**
+Accept a connection on a listening socket.
+*/
+	{
+
+	if ( State()!=ESStateOpeningPassive ) // protocol may have generated an error on the accept
+	    {                    // SAP for some bizzare reason. We can't test just (State()==ESStateError)
+		                     // 'cos if reconnection iState could be whatever (see ASocket::Error)
+                             //so check if we'r listenning at all
+        SetReturn(iError != KErrNone ? iError : KErrNotReady);
+		return;
+	    }
+
+	if ( !iAcceptQ || !iNextAcceptQ )
+		{
+		PanicSocketClient(ENotListening);
+		return;
+		}
+
+	if (IsBlockedConnect())
+		{
+		PanicSocketClient(EAcceptTwice);
+		return;
+		}
+
+
+	ASocket* acceptingSocket = InitiateAcceptingSocket();
+
+	if ( !acceptingSocket ) // The acceptingSocket will be NULL if we got a panic. return here.
+		return;
+
+	if (!iAcceptQ->Count())
+		{
+		if (!(iOptions & KOptBlocking))
+			{
+			SetReturn(KErrWouldBlock);
+			return;
+			}
+
+		SetBlockedConnect();
+		DontCompleteCurrentRequest();
+		return;
+		}
+
+	// If the queue isn't empty setting the blocked connect and calling DoCompleteAccept will work it's magic - this saves us code
+	SetBlockedConnect();
+	DoCompleteAccept();
+	DontCompleteCurrentRequest();	// Don't want to complete twice.
+	}
+
+void ASocket::LocalNameL()
+/**
+Get local name for a client request
+*/
+	{
+
+	if (!CheckRunningAndSetReturn())
+		{
+		return;
+		}
+
+	if (!iIsBound)
+		{
+		SetReturn(KErrNotFound);
+		return;
+		}
+	else
+		{
+		TSockAddr addr;
+		iSSP->LocalName(addr);
+		WriteParamL(ESocketCurrentMessage,MSG_PRM(0),addr);
+		}
+
+	}
+
+void ASocket::RemoteNameL()
+/**
+Get remote name for a cleient request
+*/
+	{
+
+	if (!CheckRunningAndSetReturn())
+		{
+		return;
+		}
+
+	if (State()==ESStateConnected || State()==ESStateOpeningActive || State()==ESStateShuttingDown)
+		{
+		TSockAddr addr;
+		iSSP->RemName(addr);
+		WriteParamL(ESocketCurrentMessage,MSG_PRM(0),addr);
+		}
+	else
+		{
+		SetReturn(KErrNotFound);
+		return;
+		}
+	}
+
+void ASocket::NewData(TUint aCount)
+/**
+Called from a protocol to indicate that new data is available for reading
+
+*/
+	{
+	__ASSERT_DEBUG(State()!=ESStateDead,Panic(EBadStateUpCall));
+//	__ASSERT_DEBUG(State()!=ESStateCreated,Panic(EBadStateUpCall));		// no longer forced into shuttingdown state upon half-close
+	__ASSERT_DEBUG(State()!=ESStateClosing,Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(!(iBlockedOperations&EReadStopped),Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(State()!=ESStateError,Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(State()!=ESStateDisconnected,Panic(EBadStateUpCall));
+// zero is used in v1.5 to resume after	reneging __ASSERT_DEBUG(aCount>0,Panic(EBadDataCount));
+
+	if(aCount==KNewDataEndofData)
+		{
+		iBlockedOperations |= EReadStopped;
+		}
+	else
+		{
+		iDataAvailable+=aCount;
+		__ASSERT_DEBUG(iDataAvailable>=0,Panic(EBadDataCount));
+		}
+
+    //-- check the recursion level counter.
+    //-- if it is 0, there were no recursion entry to itself, continue.
+    //-- if it is 1, there was blocked read from socket with KSockReadPeek set, increase it and continue.
+    //-- if it is 2, it means that function has been called from itself via NewData()-> [iSSP->CetData()] -> NewData()
+    //-- return to stop the infinite recursion.
+    if(iBlockOnPeekReadCnt >0)
+        {
+        if(iBlockOnPeekReadCnt >= 2)
+            {
+            iBlockOnPeekReadCnt = 0;
+            return;
+            }
+        else
+            {
+            iBlockOnPeekReadCnt ++;
+            }
+	    }
+
+    DoRecv(EFalse);
+	}
+
+void ASocket::CanSend()
+/**
+Called from protocol to indicate new buffer space has become available
+*/
+	{
+	__ASSERT_DEBUG(State()!=ESStateDead,Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(State()!=ESStateCreated,Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(State()!=ESStateClosing,Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(State()!=ESStateShuttingDown,Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(State()!=ESStateError,Panic(EBadStateUpCall));
+	__ASSERT_DEBUG(State()!=ESStateDisconnected,Panic(EBadStateUpCall));
+
+	TBool writeflowedoff = iBlockedOperations&EWriteFlowedOff;
+	iBlockedOperations &= ~EWriteFlowedOff;
+	if(IsBlockedWrite())
+		{
+		DoSend(EFalse);
+		}
+	if(writeflowedoff && !(iBlockedOperations&EWriteFlowedOff))
+		{
+		TryToCompleteSelectIoctl();
+		}
+	}
+
+
+void ASocket::ConnectComplete()
+/**
+Called from protocol to indicate that an active open has completed
+*/
+	{
+	//__ASSERT_DEBUG(State()==ESStateOpeningActive,Panic(EBadStateUpCall));
+	if (IsConnectionOriented())
+		{
+		SetState(ESStateConnected);
+		//__ASSERT_DEBUG(IsBlockedConnect(), Panic(EUnexpectedConnect));
+		// assertion is invalid because operation could have been cancelled MarkT
+		CompleteConnect(KErrNone);
+		}
+	TryToCompleteSelectIoctl();
+	}
+
+void ASocket::ConnectComplete(const TDesC8& aConnectData)
+/**
+Called from protocol to indicate that an active open has completed with connection data
+*/
+	{
+	__ASSERT_ALWAYS(CanSendConnectData(),Panic(EUnexpectedConnectData));
+	//__ASSERT_DEBUG(IsBlockedConnect(),Panic(EUnexpectedConnect));
+	// assertion is invalid because operation could have been cancelled
+	if ( !iBlockedConnectMsg->IsNull (MSG_PRM(2)) )
+		{
+		TInt ret = iBlockedConnectMsg->WriteDes(MSG_PRM(2),aConnectData);
+		if(ret!= KErrNone)
+			{
+			return;
+			}
+		}
+	ConnectComplete();
+	}
+
+void ASocket::ConnectComplete(CSubConnectionFlowBase& anSSP)
+/**
+Called from protocol to indicate that a passive open has completed
+*/
+	{
+	__ASSERT_DEBUG(State()==ESStateOpeningPassive,Panic(EBadStateUpCall));
+	__ASSERT_ALWAYS(iAcceptQ, Panic(ENotListeningSocket));
+	__ASSERT_ALWAYS(iAcceptQ->Count()<iAcceptQ->Length(), Panic(EAcceptQueFull));
+
+	TAcceptQEntry n;
+	n.iSSP = &anSSP;
+	n.iConnectData=NULL;
+	n.iConnectDataError=KErrNone;
+	iAcceptQ->Add(&n);
+
+	DoCompleteAccept();
+	//LOG( ESockLog::Printf(_L("ASocket::ConnectComplete iAcceptQ->=%d, provider =%u)"), iAcceptQ->Count(), (void*)&anSSP ) );
+	TryToCompleteSelectIoctl();
+	}
+
+void ASocket::ConnectComplete(CSubConnectionFlowBase& anSSP,const TDesC8& aConnectData)
+/**
+Called from protocol to indicate that a passive open has completed with connection data
+*/
+	{
+	__ASSERT_ALWAYS(CanSendConnectData(),Panic(EUnexpectedConnectData));
+	__ASSERT_ALWAYS(iAcceptQ, Panic(ENotListeningSocket));
+	__ASSERT_ALWAYS(iAcceptQ->Count()<iAcceptQ->Length(), Panic(EAcceptQueFull));
+
+	TAcceptQEntry n;
+	n.iSSP = &anSSP;
+	n.iConnectDataError = KErrNone;
+	n.iConnectData=aConnectData.Alloc();
+	if(!n.iConnectData)
+		{
+		n.iConnectDataError = KErrNoMemory;
+		}
+	iAcceptQ->Add(&n);
+
+	DoCompleteAccept();
+	TryToCompleteSelectIoctl();
+	}
+
+void ASocket::DoCompleteAccept()
+/**
+Common dequeue for accept upcalls
+*/
+	{
+	__ASSERT_DEBUG(iAcceptQ->Count(),Fault(EBadAcceptQueue));
+
+	if (!IsBlockedConnect())
+		{
+		return;
+		}
+
+    TAcceptQEntry a;
+	iAcceptQ->Remove(&a);
+
+	ASocket* newCon=GetAcceptingSocket();
+	CTransportFlowShim* shimFlow = factoryobject_cast<CTransportFlowShim>(a.iSSP);
+	__ASSERT_DEBUG(shimFlow, User::Panic(KSpecAssert_ESockSSocksntsck, 6));
+
+	// The SAP is no longer owned by the listener socket.
+	shimFlow->iListenerControlNotify = NULL;
+
+	if (newCon == NULL)
+		{
+		// Delete the flow created for accept
+		shimFlow->InitDestroy();
+		CompleteConnect(KErrCancel);
+		return;
+		}
+
+	TRAPD(ret, newCon->AcceptSetupL(*this,*a.iSSP));
+	//!!!there was a defect where by deleting iSSP here the TCP PRT would crash. Steve Butler
+	//fixed it => check it snce aiSSP would be deleted had AcceptSetupL left!!!
+	if (ret != KErrNone)
+		{
+		CompleteConnect(ret);
+		return;
+		}
+/* goes into AcceptSetupL vitual fn
+	if (newCon->State()!=ESStateAccepting && newCon->State()!=ESStateNull)
+		{
+		//Session()->PanicSocketClient(iBlockedConnect,KESockClientPanic,EBadAccept);
+		CWorkerSession::PanicSocketClient(iBlockedConnect,KESockClientPanic,EBadAccept);
+		iSession->DontCompleteCurrentRequest();
+		return;
+		}
+*/
+	newCon->SetState(ESStateConnected);
+
+	if (a.iConnectData)// && iBlockedConnect.Ptr2()) checked in WriteParam
+		{
+		TPtr8 des=a.iConnectData->Des();
+		ret = iBlockedConnectMsg->WriteDes(MSG_PRM(2),des,0);
+		if(ret!= KErrNone)
+			{
+			return;
+			}
+		}
+
+	delete a.iConnectData;
+
+	// Call SecurityCheck() on the new SAP to communicate the MProvdSecurityChecker
+	// pointer to it.  It is a somewhat bizarre situation if the PRT returns an error
+	// to this as, in reality, the PRT  should not make a ConnectComplete() upcall in the
+	// first place only to fail the subsequent SecurityCheck() downcall.  The PRT should check
+	// security beforehand and, on failure, simply not call ConnectComplete().  However, if we
+	// get an error, then complete the RSocket::Accept() operation on the listening socket with
+	// the error and place the accept socket in the error state.
+	ret = newCon->SecurityCheck();
+	if (ret != KErrNone)
+		{
+		LOG( ESockLog::Printf(_L("ASocket %08x:\tDoCompleteAccept(): socket %08x returned security check error %d"), this, a.iSSP, ret ) );
+		a.iConnectDataError = ret;
+		newCon->Error(ret, MSessionControlNotify::EErrorFatal);
+		}
+
+	newCon->iSSP->Start();
+	CompleteConnect(a.iConnectDataError);
+	}
+
+void ASocket::CanClose(MSessionControlNotify::TDelete aDelete)
+/**
+Called from protocol to indicate that a graceful close has completed
+*/
+	{
+	(void)aDelete;
+
+	//__ASSERT_ALWAYS(IsBlockedClose(),Panic(EUnexpectedClose));
+	// assertion is invalid because operation could have been cancelled MarkT
+	__ASSERT_DEBUG(State()==ESStateClosing||State()==ESStateShuttingDown,Panic(EBadStateUpCall));
+
+	CompleteClose(KErrNone);
+	if (iFlowBinder)
+		{
+		iFlowBinder->Unbind();
+		}
+	// Flowbinder takes care of itself from now onwards; forget all downwards pointers
+	iSSP = NULL;
+	iSSPData = NULL;
+	iFlowBinder = NULL;
+	iServiceProvider.Close();
+/* Flow binder takes care of this SAP behaviour
+	if(aDelete==MSessionControlNotify::EDetach)
+	    {
+		iSSP = NULL;		// Stop d'tor deleting the SSP.
+		iFlowBinder = NULL;iSSPData = NULL;
+		}
+*/
+	if (State()==ESStateClosing)
+		{
+		SetState(ESStateDead);
+
+		// delete this; must not access member data after executing this statement
+	    InitiateDestruction();
+		}
+	else
+	    {
+		SetState(ESStateDead);
+		}
+
+	}
+
+void ASocket::CanClose(const TDesC8& aDisconnectData, MSessionControlNotify::TDelete aDelete)
+/**
+Called from protocol to indicate that a graceful close has completed with disconnect data
+*/
+	{
+
+	//__ASSERT_ALWAYS(IsBlockedClose(),Panic(EUnexpectedClose));
+	// assertion is invalid because operation could have been cancelled MarkT
+	// or could be non-blocking close
+	__ASSERT_ALWAYS(CanSendDisconnectData(),Panic(EUnexpectedDisconnectData));
+	TInt ret = iBlockedCloseMsg->WriteDes(MSG_PRM(2),aDisconnectData);
+	if(ret!= KErrNone)
+		{
+		return;
+		}
+	CanClose(aDelete);
+	}
+
+void ASocket::Disconnect()
+/**
+Called from protocol to indicate that a disconnect has been initiated - prob from the remote host
+*/
+	{
+	__ASSERT_ALWAYS(IsConnectionOriented(),Panic(EBadDisconnect));
+	__ASSERT_DEBUG(State()==ESStateConnected || State()==ESStateShuttingDown,Panic(EBadStateUpCall));
+
+	iDisconnectDataError=KErrNone;
+
+	SetState(CanReconnect() ? ESStateCreated : ESStateDisconnected);
+	CompleteWrite(KErrDisconnected);
+	CompleteRead(KErrDisconnected);
+	CompleteConnect(KErrDisconnected);
+	TryToCompleteSelectIoctl();
+	}
+
+void ASocket::Disconnect(TDesC8& aDisconnectData)
+/**
+Called from protocol to indicate that a disconnect has been initiated - prob from the remote host - with disconnect data
+*/
+	{
+	__ASSERT_DEBUG(IsConnectionOriented(),Panic(EBadDisconnect));
+	__ASSERT_DEBUG(State()==ESStateConnected || State()==ESStateShuttingDown,Panic(EBadStateUpCall));
+
+	Disconnect();
+	iDisconnectData=aDisconnectData.Alloc();
+	if(!iDisconnectData)
+		{
+		iDisconnectDataError = KErrNoMemory;
+		}
+	else
+		{
+		iDisconnectDataError = KErrNone;
+		}
+	}
+
+void ASocket::DisconnectFromListener(CSubConnectionFlowBase& aSSP)
+/**
+Called from protocol to indicate that a disconnect has been initiated for an SAP which has not been
+accepted yet and is waiting in the accept queue of a listening socket
+*/
+  	{
+  	#ifdef _DEBUG
+  		TBool found = EFalse;
+  	#endif
+
+  	while(iAcceptQ->Count())
+  		{
+  		// Remove the entry from the old queue.
+  		TAcceptQEntry a;
+  		iAcceptQ->Remove(&a);
+
+  		// Add it to the new queue if it is not the one we want to remove.
+  		if(a.iSSP != &aSSP)
+  			{
+  			iNextAcceptQ->Add(&a);
+  			}
+#ifdef _DEBUG
+		else
+			{
+			found = ETrue;
+			}
+#endif
+  		}
+
+  	// Swap the queues.
+  	CCirBuf<TAcceptQEntry>* temp = iNextAcceptQ;
+  	iNextAcceptQ = iAcceptQ;
+  	iAcceptQ = temp;
+
+  	__ASSERT_DEBUG(found,Panic(EBadDisconnectFromListener));
+  	}
+
+void ASocket::IoctlComplete(TDesC8 *aBuf)
+/**
+Called from protocol to indicate that an outstanding ioctl has completes
+*/
+	{
+
+	if (aBuf && !iBlockedIoctlMsg->IsNull (MSG_PRM(1)))
+		{
+		TInt ret = iBlockedIoctlMsg->WriteDes(MSG_PRM(1),*aBuf);
+		if(ret!= KErrNone)
+			{
+			return;
+			}
+		}
+	CompleteIoctl(KErrNone);
+	}
+	
+void ASocket::SetLocalNameComplete()
+/**
+Called from protocol to indicate that an outstanding Bind  has completed
+*/
+    {
+    if (State() == ESStateBinding)
+      	{
+      	// A SetLocalName or Autobind had just completed.
+    	SetState(iNextState); // Move to next state.
+    	iIsBound=ETrue;
+    	
+    	switch(iNextState)
+    		{
+		case ESStateCreated:
+		case ESStateOpen:
+			CompleteSetLocalName(KErrNone);
+			break;
+		case ESStateConnected:
+			// UDP case
+			TryToCompleteSelectIoctl();
+			CompleteConnect(KErrNone);
+			break;
+		case ESStateOpeningActive:
+			if (CanSendConnectData() && iConnectData)
+				{
+		        TDes8* sendBuf = BorrowTemporaryBuffer(KMaxStreamChunk);
+		        TInt ret;
+		        if(!sendBuf)
+		            {
+		            ret = KErrNoMemory;
+		            }
+		        else
+		            {
+		            ret = GetUserMessage(ESocketConnectMessage)->ReadDes(MSG_PRM(1), *sendBuf);
+		            }
+				if (ret == KErrNone)
+					{
+					iSSP->ActiveOpen(*sendBuf);
+					}
+				else
+					{
+					CompleteConnect(ret);
+					}
+				}
+			else
+				{
+				iSSP->ActiveOpen();
+				}
+			break;
+		default:
+			break;
+    		}
+      	}
+    }
+
+void ASocket::CancelConnect()
+	{
+	if (State()==ESStateDead)
+ 		{
+ 		PanicSocketClient(ESockBadHandle);
+ 		return;
+ 		}
+
+	CompleteConnect(KErrCancel);
+	iSSP->Shutdown(MSessionControl::EImmediate);
+
+	if (CanReconnect())
+		{
+		// Reset socket state
+		if (IsConnectionOriented())
+			{
+			SetState(ESStateCreated);
+			}
+		else
+			{
+			SetState(ESStateOpen);
+			}
+		}
+	else
+		{
+		SetState(ESStateError);
+		}
+
+	}
+
+void ASocket::CancelAccept()
+	{
+	CompleteConnect(KErrCancel);
+	}
+
+void ASocket::CancelAll()
+/**
+Cancel All pending requests
+
+*/
+	{
+	CancelIoctl();
+	CompleteWrite(KErrCancel);
+	CompleteRead(KErrCancel);
+	if (IsBlockedConnect())
+		{
+		if (State()==ESStateOpeningPassive)
+			{
+			CancelAccept();
+			}
+		else
+			{
+			CancelConnect();
+			}
+		}
+    CompleteClose(KErrCancel);
+       CompleteSetLocalName(KErrCancel);
+	}
+
+void ASocket::GetInfoL()
+/**
+Get protocol info for this socket
+
+*/
+	{
+	if (State()==ESStateNull || State()==ESStateAccepting)
+		{
+		SetReturn(KErrNotFound);
+		return;
+		}
+
+	__ASSERT_DEBUG(iProtocolInfo, User::Panic(KSpecAssert_ESockSSocksntsck, 7));
+	TPckg<TProtocolDesc> p(*iProtocolInfo);
+	WriteParamL(ESocketCurrentMessage,MSG_PRM(0),p,0);
+	}
+
+TInt ASocket::Error(TInt aError, TUint aOperationMask)
+/**
+Error up call from SSP, carries a bitmask indicating exactly which operations to signal the error on.
+*/
+	{
+#if defined(SYMBIAN_NETWORKING_LEGACY_COMPATIBILITY_SUPPORT)
+	// Support for the IP stack's just-in-time resetting of a shutdown socket's state is is provided by allowing it
+	// to notify via a pseudo-error. This is all in support of regrettable behaviour that after a shutdown TCP and UDP
+	// sockets must complete reads & writes with a different error code to all other sockets.
+	if(aOperationMask == MSessionControlNotify::EErrorLegacySupportRequest)
+		{
+		SetState((TSocketState) aError);
+		return KErrNone;
+		}
+#endif
+	if (aOperationMask == MSessionControlNotify::EErrorCompleteConnect)
+	    {
+	    CompleteConnect(aError);
+	    }
+	else
+	    {
+    	DoError(aError, aOperationMask, ETrue);
+	    }
+
+	return State() == ESStateError ? KErrGeneral : KErrNone;
+	}
+
+void ASocket::DoError(TInt aError, TUint aOperationMask, TBool /*aDeleteInterface*/)
+	{
+	__ASSERT_DEBUG(iState!=ESStateDead,Panic(EBadStateUpCall));
+//	__ASSERT_DEBUG(iState!=ESStateError,Panic(EBadStateUpCall));
+	//__ASSERT_DEBUG(iState!=ESStateDisconnected,Panic(EBadStateUpCall));
+	//__ASSERT_DEBUG(anError!=KErrNone,Panic(EBadErrorCall));
+
+	// completionMask remembers whether there were any pending operations that were not completed,
+	// and whether the error is fatal (i.e. the socket permanently returns an error).
+    TUint completionMask = aOperationMask & MSessionControlNotify::EErrorFatal;
+	if (aOperationMask & MSessionControlNotify::EErrorClose)
+		{
+		if (!CompleteClose(aError))
+			{
+			completionMask |= MSessionControlNotify::EErrorClose;
+			}
+		}
+
+	if (aOperationMask & MSessionControlNotify::EErrorRecv)
+		{
+        if (!CompleteRead(aError))
+        	{
+	        completionMask |= MSessionControlNotify::EErrorRecv;
+        	}
+		}
+
+	if (aOperationMask & MSessionControlNotify::EErrorSend)
+		{
+		if (!CompleteWrite(aError))
+			{
+	        completionMask |= MSessionControlNotify::EErrorSend;
+			}
+		}
+
+	if ((aOperationMask&MSessionControlNotify::EErrorIoctl) && !iSelectFlags)
+		{
+		CompleteIoctl(aError);
+		}
+	if (aOperationMask & MSessionControlNotify::EErrorCompleteSetLocalName)
+		{
+		CompleteSetLocalName(aError);
+		}
+
+    iError = aError;
+    if (completionMask)
+        {
+        iErrorOperationMask = aOperationMask & completionMask;
+        }
+        
+	if (State() == ESStateBinding && ((iNextState == ESStateCreated) || (iNextState == ESStateOpen)))
+		{
+		// If SetLocalName in progress then do not put the socket to
+		// a sticky error state.
+		iError = KErrNone;
+		// Reset socket state.
+		if (!IsConnectionOriented())
+			{
+			SetState(ESStateOpen);
+			}
+		else
+			{
+			SetState(ESStateCreated);
+			}
+		}
+		else
+
+	if (aOperationMask & MSessionControlNotify::EErrorConnect || aOperationMask&MSessionControlNotify::EErrorFatal)
+		{
+		CompleteConnect(aError);
+
+		// KErrNoMemory not treated as a fatal error
+		if (aError == KErrBindersInvalid || (!CanReconnect() && aError != KErrNoMemory))
+			{
+			// Fatal error
+			iError = aError;
+			SetState(ESStateError);
+			}
+		else
+			{
+			// Reset socket state
+			if (!IsConnectionOriented())
+				{
+				SetState(ESStateOpen);
+				}
+			else
+				{
+				SetState(ESStateCreated);
+				}
+			}
+		}
+
+    if (iError == KErrBindersInvalid)
+        {
+        __ASSERT_DEBUG(iFlowBinder, User::Panic(KSpecAssert_ESockSSocksntsck, 8));
+        iFlowBinder->Unbind();
+      	iFlowBinder = NULL;
+       	iSSP = NULL;
+       	iSSPData = NULL;
+       	iServiceProvider.Close();
+        }
+	TryToCompleteSelectIoctl();
+	}
+
+TInt ASocket::DrainStreamProtocol(AMessage* aMsg)
+/**
+ Drain a stream based protocol into client buffers.
+*/
+	{
+	__ASSERT_DEBUG(iDataAvailable>=0,Panic(EBadByteCount));
+	__ASSERT_DEBUG(iRecByteCount>=0,Panic(EBadByteCount));
+
+	TDes8* recBuf = NULL;
+	if(!iRecvUseMBufs)
+		{
+		TInt xferBufSize = Min((TInt) KMaxStreamChunk, Min(iDataAvailable, iRecByteCount));
+		recBuf = BorrowTemporaryBuffer(xferBufSize);
+		if(!recBuf)
+			{
+			return KErrNoMemory;
+			}
+		}
+
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+	TInt rxActual = 0;
+#endif
+
+	RMBufChain data;
+	TInt ret = KErrNone;
+	do
+		{
+        TInt xfrLen;
+        if (iRecvUseMBufs)
+			{
+			// We are using RMBufChain.	So we can read the complete data that is available
+			xfrLen = iDataAvailable;
+			}
+	     else
+			{
+			xfrLen = Min(recBuf->MaxLength(), Min(iDataAvailable, iRecByteCount));
+			}
+
+		if (xfrLen==0)
+			{
+			return KErrNone;
+			}
+
+
+		RMBufChain data;
+		ret = iSSPData->GetData(data, xfrLen, iRecvFlags);
+		if (ret == 0 && iBlockedOperations&EReadStopped)
+			{
+			/* Look for the special case, where the SSP renegs on the amount of
+			 * data available after an EStopInput Shutdown, as that can stop us
+			 * ever exiting this while loop. */
+			iDataAvailable = 0;
+			return KErrEof;
+			}
+		if(ret >= 0)
+			{
+			// Now we received something.
+			if (iRecvUseMBufs)
+				{
+				ret = aMsg->WriteMBuf(MSG_PRM(2), data );
+				// No need to delete as the write operation has taken the ownership of our RMBufChain
+				}
+			else
+				{
+				// Default assumption is multi-buf chain
+				TPtr8 des(const_cast<TUint8*>(recBuf->Ptr()), xfrLen, xfrLen);
+				if(!data.First()->Next())
+					{
+					// Actually data is all in one buf; repoint descriptor at that
+					des.Set(data.First()->Ptr(), data.First()->Length(), data.First()->Length()); 
+					}
+				else
+					{
+					data.CopyOut(des, 0);
+					}
+				xfrLen = des.Length();
+            	ret = aMsg->WriteDes(MSG_PRM(2), des, iRecOffset);
+				if ( ret == KErrNone )
+					{
+					data.Free(); // Free the chain
+					}
+				}
+            if(ret == KErrNone)
+				{
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+				rxActual += ipcLen;
+#endif
+				iRecOffset += xfrLen;
+                iDataAvailable -= xfrLen;
+				iRecByteCount -= xfrLen;
+				}
+			}
+		else if(xfrLen <= 0)
+			{
+			// Failed to read or write on this iteration; we're done
+			break;
+			}
+		} while(ret == KErrNone);
+
+#ifdef SYMBIAN_NETWORKING_PERFMETRICS
+	IncludePerformanceData(rxActual, -1, -1);
+#endif
+	return ret;
+	}
+
+TInt ASocket::FillStreamProtocol(AMessage* aMsg)
+/**
+ Fill a stream protocol from client buffers
+*/
+	{
+	__ASSERT_DEBUG(iSendByteCount>=0,Panic(EBadByteCount));
+	TPtr8 des(NULL, 0);
+	TDes8* sendBuf;
+	if(!iSendUseMBufs)
+		{
+		sendBuf = BorrowTemporaryBuffer(Min((TInt) KMaxStreamChunk, iSendByteCount));
+		if(!sendBuf)
+			{
+			return KErrNoMemory;
+			}
+		}
+	else
+		{
+		sendBuf = NULL;
+		}
+
+	RMBufChain data;
+	data.Assign(iSendData);	// pick up any flowed-off chain
+	TInt xfrLen = data.Length();
+
+	do
+		{
+		TInt err = KErrNone;
+		if(data.IsEmpty())
+			{
+			// Need to pick up more data from client
+			if (!iSendUseMBufs)
+				{
+				xfrLen = Min(sendBuf->Size(), iSendByteCount);
+				err = data.Alloc(xfrLen, iAllocator);
+				if(err == KErrNone)
+					{
+					RMBuf* first = data.First();
+					if(first->Length() >= xfrLen)
+						{
+						des.Set(first->Ptr(), xfrLen, xfrLen);
+						err = aMsg->ReadDes(MSG_PRM(2),des, iSendOffset);
+						}
+					else
+						{
+						des.Set(const_cast<TUint8*>(sendBuf->Ptr()), xfrLen, xfrLen);
+						err = aMsg->ReadDes(MSG_PRM(2), des, iSendOffset);
+						data.CopyIn(des);	// read failure exceedingly rare so don't bother checking return yet
+						}
+					if(err != KErrNone)
+						{
+						data.Free();
+						}
+					}
+				}
+			else
+				{
+				err = aMsg->ReadMBuf(MSG_PRM(2), data);
+				if(err == KErrNone)
+					{
+					xfrLen = data.Length();
+					}
+				}
+			}
+		else
+		    {
+		    xfrLen = data.Length();
+		    }
+		if(err != KErrNone)
+			{
+			// Failed getting data from the client; bail now without further disturbing the state
+			return err;
+			}
+		
+		err = iSSPData->Write(data, iSendFlags, NULL);
+		
+		// If a protocol takes only part of the chain they must update it so that we have the new head
+		__ASSERT_DEBUG(err <= 0 || err == (xfrLen - data.Length()), Panic(EBadByteCount));  
+		
+		if(err <= 0)	// protocol error or flow-off
+			{
+			if(err == 0)
+			    {
+                iSendData.Assign(data);	// keep the MBuf chain for flow-on. In future we could be cleverer and later free this when MBufs are running low
+                iBlockedOperations|=EWriteFlowedOff;
+			    }
+			else 
+			    {
+			    data.Free();
+			    }
+			return err;
+			}
+		iSendOffset += err;
+		iSendByteCount -= err;
+		} while(iSendByteCount > 0);
+
+	// We successfully completed.
+	if ( iSendUseMBufs )
+		{
+		// Protection against possible non-deletion by SAP
+		data.Free ();
+		// We have to init the RMBufChain, so that caller see that everything send
+		aMsg->InitMBuf(MSG_PRM(2));
+		}
+	return KErrNone;
+	}
+
+TBool ASocket::CheckRunningAndSetReturn()
+/**
+Check a common set of states and set the return value is required.
+*/
+{
+	switch(State())
+		{
+	case ESStateNull:
+	case ESStateAccepting:
+		PanicSocketClient(ENullSocket);
+		//lint -fallthrough
+	case ESStateDead:
+	case ESStateClosing:
+		SetReturn(KErrBadHandle);
+		return EFalse;
+	case ESStateDisconnected:
+		SetReturn(KErrDisconnected);
+		return EFalse;
+	case ESStateError:
+		SetReturn(iError);
+		return EFalse;
+	default:
+		return ETrue;
+		}
+	}
+
+/**
+Complete any outstanding read operation.
+@param aError error code with which to complete the pending operation
+@return ETrue if a pending operation was completed, else EFalse.
+*/
+TBool ASocket::CompleteRead(TInt aError)
+	{
+	if (IsBlockedRead())
+		{
+		if(iAllocAsync)
+			{
+			iAllocAsync->CancelNewData();
+			}
+		iBlockedOperations&=~EBlockedRead;
+		iReadMsg->CompleteMessage(aError);
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+   		}
+	}
+
+/**
+Complete any outstanding write operation.
+@param aError error code with which to complete the pending operation
+@return ETrue if a pending operation was completed, else EFalse.
+*/
+TBool ASocket::CompleteWrite(TInt aError)
+	{
+	if (IsBlockedWrite())
+		{
+		if(iAllocAsync)
+			{
+			iAllocAsync->CancelCanSend();
+			}
+		iBlockedOperations&=~EBlockedWrite;
+		iWriteMsg->CompleteMessage(aError);
+		iSendData.Free();
+		return ETrue;
+		}
+	else
+		{
+		return EFalse;
+		}
+	}
+
+void ASocket::CompleteConnect(TInt aError)
+	{
+	if (IsBlockedConnect())
+		{
+		iBlockedOperations&=~EBlockedConnect;
+		iBlockedConnectMsg->CompleteMessage(aError);
+		}
+	}
+
+TBool ASocket::CompleteClose(TInt aError)
+	{
+	if (IsBlockedClose())
+		{
+		iBlockedOperations&=~EBlockedClose;
+		iBlockedCloseMsg->CompleteMessage(aError);
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+
+void ASocket::CompleteIoctl(TInt aError)
+	{
+	if (IsBlockedIoctl())
+		{
+		iBlockedOperations&=~EBlockedIoctl;
+		iBlockedIoctlMsg->CompleteMessage(aError);
+//		LOG(ESockLog::Printf(KESockSessDetailTag, _L8("ASocket::CompleteIoctl completing %08x "), iBlockedIoctl.Handle()) );
+		}
+	}
+	
+void ASocket::CompleteSetLocalName( TInt aError )
+    {
+    if (IsBlockedSetLocalName())
+		{
+		// SetLocalName has completed.
+		iBlockedOperations &= ~EBlockedSetLocalName;
+		iBlockedSetLocalNameMsg->CompleteMessage(aError);
+		}
+    }	
+
+TUint ASocket::SelectConditionsReady()
+/**
+Which select conditions are ready
+*/
+    {
+
+	TUint flags=0;
+	// Exceptional condition
+	if(iError!=KErrNone)
+		{
+		flags|=KSockSelectExcept;
+		}
+
+	// Ready to read - either data or an accept is ready
+	if(iDataAvailable
+			|| ((iSelectFlags & KSockReadContinuation) != 0 && !iDatagramTail.IsEmpty())
+			|| (State()==ESStateOpeningPassive && iAcceptQ->Count())
+		    || (iBlockedOperations&EReadStopped))
+		{
+		flags|=KSockSelectRead;
+		}
+
+	// Ready to write - must be connected and cannot be blocking
+	if((State()==ESStateConnected || State()==ESStateOpen || State()==ESStateShuttingDown)
+		&& !(iBlockedOperations&EWriteFlowedOff) )
+		{
+		flags|=KSockSelectWrite;
+		}
+
+	return flags;
+    }
+
+void ASocket::TryToCompleteSelectIoctl()
+/**
+have a go at completing the select ioctl
+*/
+    {
+
+	if(iSelectFlags)
+	   {
+	   TUint ready = (iSelectFlags & SelectConditionsReady());
+	   if(ready)
+	       {
+	       TPckg<TUint> buf(ready);
+           IoctlComplete(&buf);
+	       iSelectFlags=0;
+	       }
+	   }
+    }
+
+TBool ASocket::CheckReadStopped()
+/**
+Has reading stopped
+*/
+	{
+	if((iBlockedOperations&EReadStopped) && iDataAvailable<=0)
+		{
+		TPtrC8 ptr(0,0);
+		TInt ret = iReadMsg->WriteDes(MSG_PRM(2), ptr);
+		if(iRecvXferLenIdx >= 0)
+			{
+			iXferLength() = 0;
+			ret = iReadMsg->WriteDes(iRecvXferLenIdx, iXferLength);
+			if(ret!= KErrNone)
+				{
+				return EFalse;
+				}
+			}
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+void ASocket::CommunicateOwner()
+/**
+Communicate Thread ID, Process ID and UID to SAP.
+
+*/
+	{
+	if (RequiresOwnerInfo())
+		{
+
+		TSoOwnerInfo info;
+
+		// Not using more Networking specific macro SYMBIAN_NETWORKING_UPS because this support
+		// is required by UPS functionality outside of Networking subsystem as well.
+		GetOwnerInfo(info.iProcessId, info, info.iThreadId);
+
+		iSSP->SetOption(KSOLProvider, KSoOwnerInfo, TPckgC<TSoOwnerInfo>(info));
+
+#ifdef SYMBIAN_NETWORKING_UPS
+		iSSP->SetOption(KSOLProvider, KSoSetPlatSecApi, TPckgC<const MPlatsecApiExt*>(this));
+#endif
+		}
+	}
+
+TInt ASocket::GetConnectionSocketInfo(TConnectionSocketInfo& aInfo) const
+/**
+Return information about this socket
+*/
+	{
+	__ASSERT_DEBUG(iSSP, User::Panic(KSpecAssert_ESockSSocksntsck, 10));
+
+	if(iIsBound)
+		{
+		iSSP->LocalName(aInfo.iSourceAddress);
+		}
+	else
+		{
+		return KErrNotFound;
+		}
+
+	if (State()==ESStateConnected || State()==ESStateOpeningActive || State()==ESStateShuttingDown)
+		{
+		iSSP->RemName(aInfo.iDestinationAddress);
+		}
+	else
+		{
+		return KErrNotFound;
+		}
+
+	__ASSERT_DEBUG(iProtocolInfo, User::Panic(KSpecAssert_ESockSSocksntsck, 11));
+
+	aInfo.iAddressFamily = iProtocolInfo->iAddrFamily;
+	aInfo.iProtocol = iProtocolInfo->iProtocol;
+
+	return KErrNone;
+	}
+
+TInt ASocket::RequestAsyncMBufAllocation(TInt aSignal, TUint aSize)
+	{
+	TInt ret = KErrNone;
+	if(!iAllocAsync)
+		{
+		TRAP(ret, iAllocAsync = CWaitForMBufs::NewL(this));
+		if(ret != KErrNone)
+			{
+			// This second-chance mechanism has failed; it's now reasonable just to error the client
+			Error(KErrNoMemory, aSignal == CWaitForMBufs::ECanSend? MSessionControlNotify::EErrorSend: MSessionControlNotify::EErrorRecv);
+			}
+		}
+
+	if(aSignal == CWaitForMBufs::ENewData)
+		{
+		iAllocAsync->AllocWaitAndSignalNewData(aSize);
+		}
+	else
+		{
+		if(aSignal == CWaitForMBufs::ECanSend)
+			{
+			iAllocAsync->AllocWaitAndSignalCanSend(aSize);
+			}
+		}
+
+	return ret;
+	}
+
+void ASocket::ReadParamL(TSocketMessage aMessage, TInt aSrcParamIndex,TDes8 &aDes,TInt anOffset)
+	{
+	User::LeaveIfError(GetUserMessage(aMessage)->ReadDes(aSrcParamIndex, aDes, anOffset));
+	}
+
+void ASocket::ReadParamL(TSocketMessage aMessage, TInt aSrcParamIndex, RMBufChain& aBufChain)
+	{
+	User::LeaveIfError(GetUserMessage(aMessage)->ReadMBuf(aSrcParamIndex, aBufChain));
+	}
+
+void ASocket::WriteParamL(TSocketMessage aMessage, TInt aDstParamIndex,const TDesC8& aDes,TInt anOffset)
+	{
+	User::LeaveIfError(GetUserMessage(aMessage)->WriteDes(aDstParamIndex, aDes, anOffset));
+	}
+
+void ASocket::WriteParamL(TSocketMessage aMessage, TInt aDstParamIndex, RMBufChain& aBufChain)
+	{
+	User::LeaveIfError(GetUserMessage(aMessage)->WriteMBuf(aDstParamIndex, aBufChain));
+	}
+
+AMessage* ASocket::GetUserMessage( TSocketMessage aMessage ) const
+	{
+	AMessage* msg = NULL;
+	switch (aMessage)
+		{
+			case ESocketCurrentMessage:
+			msg = iCurrentMsg;
+			break;
+
+			case ESocketReadMessage:
+			msg = iReadMsg;
+			break;
+
+			case ESocketWriteMessage:
+			msg = iWriteMsg;
+			break;
+
+			case ESocketCloseMessage:
+			msg = iBlockedCloseMsg;
+			break;
+
+			case ESocketIoCtlMessage:
+			msg = iBlockedIoctlMsg;
+			break;
+
+			case ESocketConnectMessage:
+			msg = iBlockedConnectMsg;
+			break;
+			case ESocketSetLocalNameMessage:
+			msg = iBlockedSetLocalNameMsg;
+			break;
+
+			default:
+			__ASSERT_DEBUG(0, User::Panic(KSpecAssert_ESockSSocksntsck, 12));
+		}
+	return msg;
+	}
+
+void ASocket::SetUserMessage ( TSocketMessage aMessageType, AMessage* aMessage )
+	{
+	switch (aMessageType)
+		{
+			case ESocketCurrentMessage:
+			iCurrentMsg = aMessage;
+			break;
+
+			case ESocketReadMessage:
+			iReadMsg = aMessage;
+			break;
+
+			case ESocketWriteMessage:
+			iWriteMsg = aMessage;
+			break;
+
+			case ESocketCloseMessage:
+			iBlockedCloseMsg = aMessage;
+			break;
+
+			case ESocketIoCtlMessage:
+			iBlockedIoctlMsg = aMessage;
+			break;
+
+			case ESocketConnectMessage:
+			iBlockedConnectMsg = aMessage;
+			break;
+			case ESocketSetLocalNameMessage:
+			iBlockedSetLocalNameMsg = aMessage;
+			break;
+
+			default:
+			__ASSERT_DEBUG(0, User::Panic(KSpecAssert_ESockSSocksntsck, 13));
+		}
+	}
+
+
+#ifdef SYMBIAN_NETWORKING_UPS
+TInt ASocket::GetProcessAndThreadId(TProcessId& aProcessId, TThreadId& aThreadId) const
+/**
+Retrieve the process and thread id associated with the pending request.
+*/
+	{
+	TSocketMessage msg = ESocketCurrentMessage;
+
+	if (IsBlockedConnect())
+		{
+		msg = ESocketConnectMessage;
+		}
+	else
+	if (IsBlockedWrite())
+		{
+		msg = ESocketWriteMessage;
+		}
+	if (msg != ESocketCurrentMessage || (iState == ESStateCreated || iState == ESStateOpen))
+		{
+		// Guard against an invalid current message - especially for a Connect/CancelConnect scenario
+		// whereby the socket is in the ESStateError state.  Needs revisiting.
+		return GetUserMessage(msg)->GetProcessAndThreadId(aProcessId, aThreadId);
+		}
+	else
+		{
+		return KErrUnknown;
+		}
+	}
+
+TInt AMessage::GetProcessAndThreadId(TProcessId& /*aProcessId*/, TThreadId& /*aThreadId*/) const
+	{
+	return KErrNotSupported;
+	}
+
+#endif
+