datacommsserver/esockserver/ssock/SS_SOCK.CPP
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/SS_SOCK.CPP	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,678 @@
+// 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:
+//
+
+//#include "ss_std.h"
+
+#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 "ss_sock.h"
+#include <in_sock.h>
+#include "ss_sapfactshim.h"
+#include <comms-infras/ss_nodemessages_dataclient.h>
+
+#include <comms-infras/ss_msgintercept.h>
+
+#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_ESockSSockS_SOCK, "ESockSSockS_SOCK");
+#endif
+
+
+using namespace ESock;
+using namespace Messages;
+using namespace Factories;
+using namespace Den;
+
+//
+#define MSG_PRM(prmIndex)		(prmIndex)
+
+CSocket::CSocket(CSockSession *aSession, CPlayer* aPlayer, const Den::TSubSessionUniqueId aSubSessionUniqueId, TInt aSocketType)
+	: CSockSubSession(aSession, aPlayer, aSubSessionUniqueId), ASocket(aSocketType)
+/**
+Constructor - set up default options.
+*/
+	{
+	LOG_NODE_CREATE(KESockFlowTag, CSocket)
+	}
+
+TInt CSocket::SecurityCheck()
+    {
+	return iSSP->SecurityCheck(Session());
+    }
+
+void CSocket::DontCompleteCurrentRequest()
+    {
+    CSockSubSession::DontCompleteCurrentRequest();
+    }
+
+void CSocket::SetClosing()
+    {
+    CSockSubSession::SetClosing();
+    }
+
+TBool CSocket::IsClosing()
+    {
+    return CSockSubSession::IsClosing();
+    }
+
+void CSocket::GetOwnerInfo(TProcessId& aProcId, TSoOwnerInfo& aInfo, TThreadId& aThreadId)
+    {
+    CSockSubSession::GetOwnerInfo(aProcId, aInfo.iUid, aThreadId);
+    }
+
+const RNodeInterface* CSocket::ServiceProvider() const
+    {
+    return ASocket::ServiceProvider();
+    }
+
+
+void CSocket::SetReturn(TInt aReturnValue) const
+    {
+    CSockSubSession::SetReturn(aReturnValue);
+    }
+
+ASocket* CSocket::GetAcceptingSocket()
+    {
+    CSocket* newCon=Session()->CSocketFromHandle(GetUserMessage(ESocketConnectMessage)->ReadInt(1));
+    return newCon;
+    }
+
+
+CSocket* CSocket::NewLC(TServerProtocolDesc *aServiceInfo, CSockSession *aSession, CPlayer* aPlayer, CProtocolBase* aProt, const Den::TSubSessionUniqueId aSubSessionUniqueId, TInt aSocketType)
+/**
+Common static cocreator to create all sockets.
+
+*/
+	{
+	CSocket *s = new(ELeave) CSocket(aSession, aPlayer, aSubSessionUniqueId, aSocketType);
+	CleanupStack::PushL(s);
+	s->ConstructL(aProt);
+	s->Create(aServiceInfo);
+	ESOCK_DEBUG_REGISTER_GENERAL_NODE(ESockDebug::KSocketNodeUid, s);
+	return s;
+	}
+
+
+CSocket::~CSocket()
+/**
+Socket destructor. Will ensure that the SSP (and any accept queue) is shutdown before destroying it.
+Automatically completes all outstanding requests.
+
+*/
+	{
+	// Toast anything we've got hanging around....
+	FinalCompleteAllBlockedMessages(KErrAbort);
+	LOG_NODE_DESTROY(KESockFlowTag, CSocket)
+	}
+
+void CSocket::ConstructL (CProtocolBase* aProtocol)
+	{
+	InitUserMessageL (ESocketCurrentMessage);
+	InitUserMessageL (ESocketReadMessage);
+	InitUserMessageL (ESocketWriteMessage);
+	InitUserMessageL (ESocketCloseMessage);
+	InitUserMessageL (ESocketIoCtlMessage);				
+	InitUserMessageL (ESocketConnectMessage);	
+	InitUserMessageL (ESocketSetLocalNameMessage);		
+	CSockSubSession::ConstructL(aProtocol);		
+	}
+
+void CSocket::InitiateDestruction()
+    {
+	// Remove the subsession from the session's subsession list.
+    if(iSession)
+		{
+		iSession->SubSessions().Lock();
+
+		CSubSessionIx::TSubSessionHandle handle;
+		if(iSession->SubSessions().Find(this, handle) == KErrNone)
+			{
+			iSession->PitBoss().RemoveSubSession(handle, iSession);
+			}
+		
+		iSession->SubSessions().Unlock();
+		}
+
+    ASocket::InitiateDestruction();
+	
+	if (!FlowRequestPending())
+		{
+		delete this;
+		}
+    }
+
+void CSocket::InitUserMessageL ( TSocketMessage aMessage )
+	{
+	CSocketMessage* msg = new (ELeave)CSocketMessage;
+	SetUserMessage ( aMessage, msg );
+	}
+
+
+void CSocket::FinalCompleteAllBlockedMessages(TInt aResult)
+	{
+	CompleteConnect(aResult);
+	CompleteClose(aResult);
+	CompleteRead(aResult);
+	CompleteWrite(aResult);
+	CompleteIoctl(aResult);
+	CompleteSetLocalName(aResult);
+	}
+
+void CSocket::ShutdownL()
+/**
+Terminate the protocol
+*/
+	{
+    ASocket::ShutdownL(RSocket::TShutdown(Message().Int0())/*type*/, Message().Ptr1() != NULL);
+	}
+
+TBool CSocket::CloseSocket()
+/**
+A Client has closed our RSocket - or we're being closed by the session because our client has exited
+*/
+	{
+	TBool immediate = ASocket::CloseSocket();
+	if (immediate)
+		{
+		static_cast<CPlayer&>(Player()).DeleteSocket(*this);
+		}
+	return immediate;
+	}
+
+void CSocket::ConnectL()
+/**
+Active open the socket - from a client request.
+*/
+	{
+	ASocket::ConnectL(Message().Ptr1() != NULL);
+	}
+
+//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 CSocket::SetSockOptionL()
+	{
+	TInt optionName=Message().Int0();
+	TInt optionLength=Message().GetDesLengthL(1);
+	TInt optionLevel=Message().Int2();
+
+    ASocket::SetSockOptionL(optionName, optionLength, optionLevel);
+	}
+
+void CSocket::GetSockOptionL()
+/**
+Read a socket option from us (or attempt the protocol if we don't support the option)
+
+*/
+	{
+	TInt optionName=Message().Int0();
+	TInt optionLength=SafeMessage().GetDesMaxLengthL(1);
+	TInt optionLevel=Message().Int2();
+    ASocket::GetSockOptionL(optionName, optionLength, optionLevel, Message().Ptr1() != NULL);
+	}
+
+void CSocket::IoctlL()
+/**
+Perform an Ioctl from a user request
+*/
+	{
+	TInt optionName = Message().Int0();
+	TInt optionLength = (Message().Ptr1() != NULL) ? SafeMessage().GetDesMaxLengthL(1) : 0;
+	TInt optionLevel =Message().Int2();
+    ASocket::IoctlL(optionName, optionLength, optionLevel, Message().Ptr1() != NULL);
+	}
+
+
+void CSocket::ListenL()
+/**
+Listen request service
+Listen is a dead and, clients can't do anything with the socket other than Accept after a listen.
+*/
+	{
+   	TInt qlen = Message().Int0()>0 ? Message().Int0() : 1;
+    ASocket::ListenL(qlen, Message().Ptr1() != NULL);
+	}
+
+ASocket* CSocket::InitiateAcceptingSocket()
+    {
+    // Create the accepting socket - we have to do this outside the subsessions lock
+    // because the lock does not support recursion.
+	CSocket* acceptingSocket = NULL;
+	TInt acceptingHandle = 0;
+	TRAPD(ret, acceptingSocket = static_cast<CPlayer&>(Player()).NewSocketL(EFalse, acceptingHandle));
+	if(ret != KErrNone)
+		{
+		SetReturn(ret);
+		return NULL;
+		}
+	
+	CSocket* nullSocket = NULL;	
+	TBool found = EFalse;
+
+	// Now that we have the new socket created on the Player we replace the null one with it.
+		{
+		CSubSessionIx& subSessions = iSession->SubSessions();
+		subSessions.Lock();
+
+		// Find the null socket - we do this inside the subsessions lock to ensure it cannot
+		// be orphaned until we are finished.
+		const TInt nullSocketHandle = Message().Int1();
+		nullSocket = static_cast<CSocket*>(subSessions.At(nullSocketHandle, TCFSubSessInfo::ESocket));
+		if(nullSocket)
+			{
+			if (nullSocket->State()!=ESStateNull)
+				{
+				PanicSocketClient(EAcceptTwice);
+		
+				subSessions.Unlock();
+
+				return NULL;
+				}
+			
+			found = subSessions.At(acceptingHandle, TCFSubSessInfo::ESocket) != NULL;
+			if(found)
+				{
+				LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSocket::InitiateAcceptingSocket() replacing null socket %08x with accepting socket %08x"), nullSocket, acceptingSocket) );
+				subSessions.Remove(acceptingHandle);
+				subSessions.Replace(nullSocketHandle, acceptingSocket);
+				//We need to ensure that the socket does not get accepted onto twice
+				acceptingSocket->SetState(ESStateAccepting);
+				}
+			else
+				{
+				LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSocket::InitiateAcceptingSocket() accepting socket %08x not found - the session is probably being destroyed"), acceptingSocket, nullSocket) );
+				}
+			}
+		else
+			{
+			PanicSocketClient(ESockBadHandle);
+		
+			subSessions.Unlock();
+
+			return NULL;
+			}
+		
+		subSessions.Unlock();
+		}
+	
+	// Destroy the null socket if the replacement was successful.
+	if(found)
+		{
+		RAllocator* prevAllocator = Player().PitBoss().MaybeSwitchHeap(nullSocket->Player().WorkerId());
+		LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSocket::InitiateAcceptingSocket() destroying null socket %08x"), nullSocket) );
+		nullSocket->InitiateDestruction();
+		if(prevAllocator)
+			{
+			User::SwitchAllocator(prevAllocator);
+			}
+		}
+	else
+		{
+		// Accepting socket will be deleted by session cleanup.
+		acceptingSocket = NULL;
+		SetReturn(KErrCancel);
+		}
+		
+	return acceptingSocket;
+    }
+    
+void CSocket::PanicSocketClient(TESockPanic aPanic)
+	{
+	CWorkerSubSession::PanicClient(KESockClientPanic, (TInt) aPanic);
+	}
+
+
+/** Provides a sizeable buffer for strictly temporary use, eg within current stack frame: there's only one buffer
+ * and no protocol for returning so shared use can't be detected: the intended use is for transferring data to/from 
+ * a client. 
+ * @return pointer to a buffer of at least the requested size, or NULL if this proves impossible
+ */ 
+TDes8* CSocket::BorrowTemporaryBuffer(TInt aSize)
+    {
+    return static_cast<CPlayer&>(Player()).BorrowTemporaryBuffer(aSize);
+    }
+
+/** Provides a sizeable buffer for strictly temporary use, eg within current stack frame: there's only one buffer
+ * and no protocol for returning so shared use can't be detected: the intended use is for transferring data to/from 
+ * a client. 
+ * @return Pointer to a buffer of at least the requested size
+ * @leave KErrNoMemory if the request cannot be satisfied
+ */ 
+TDes8* CSocket::BorrowTemporaryBufferL(TInt aSize)
+    {
+    return static_cast<TDes8*>(User::LeaveIfNull(static_cast<CPlayer&>(Player()).BorrowTemporaryBuffer(aSize)));
+    }
+
+void CSocket::ReferenceL()
+/**
+Get a global reference to this socket.
+*/
+	{
+	TName name;
+	ComposeSubSessionName(this, name);
+	Message().WriteL(MSG_PRM(0), name);
+	SetReturn(KErrNone);
+	}
+
+void CSocket::ProcessMessageL()
+	{
+	RSafeMessage& msg = const_cast<RSafeMessage&>(SafeMessage());
+	static_cast<CSocketMessage*>(iCurrentMsg)->SetMessage(msg);
+	// local flag to indicate processed messages
+	// cleared in the case of ESoClose - socket deletion
+	TBool processed =ETrue;
+	switch(msg.Function())
+		{
+		case ESoShutdown:
+			ShutdownL();
+			break;
+
+		case ESoClose:
+            CloseSocket();
+            processed = EFalse; // no need to reset iMessage handle
+			break;
+
+		case ESoSendToNoLength:		// flags,addr,buf
+			{
+		    TInt sendByteCount = msg.GetDesLengthL(2);
+		    TInt sendFlags = msg.Int0();   
+		    ASocket::SendL(ASocket::KNoXferLen, MSG_PRM(1), sendByteCount, sendFlags, EFalse);
+			break;
+			}
+		case ESoSendNoLength:		// flags,buflen,buf
+			{
+		    TInt sendByteCount = msg.Int1();	// sanity-checked by SendL() 
+		    TInt sendFlags = msg.Int0();   
+		    ASocket::SendL(ASocket::KNoXferLen, ASocket::KNoAddrArg, sendByteCount, sendFlags, EFalse);
+			break;
+			}
+		case ESoSendTo:				//xferlen(flags),addr,buf
+			{
+		    TInt sendByteCount = msg.GetDesLengthL(2);
+			ReadParamL(ESocketCurrentMessage,MSG_PRM(0),iXferLength);
+			TInt sendFlags = iXferLength();
+		    ASocket::SendL(MSG_PRM(0), MSG_PRM(1), sendByteCount, sendFlags, EFalse);
+			break;
+			}
+		case ESoSend:				//flags,xferlen,buf
+			{
+		    TInt sendByteCount = msg.GetDesLengthL(2);
+		    TInt sendFlags = msg.Int0();   
+		    ASocket::SendL(MSG_PRM(1), ASocket::KNoAddrArg, sendByteCount, sendFlags, EFalse);
+			break;
+			}
+		case ESoWrite:				//0,buflen,buf
+			{
+		    TInt sendByteCount = msg.Int1();	// sanity-checked by SendL() 
+		    TInt sendFlags = 0;   
+		    ASocket::SendL(ASocket::KNoXferLen, ASocket::KWriteNoAddrArg, sendByteCount, sendFlags, EFalse);
+			break;
+			}
+		case ESoRecvFromNoLength:	//flags,addr,buf
+			{
+		    TInt readByteCount = msg.GetDesMaxLengthL(2);
+		    TInt readFlags = msg.Int0();
+		    ASocket::RecvL(KNoXferLen, MSG_PRM(1), readByteCount, readFlags, EFalse, EFalse);
+			break;
+			}
+		case ESoRecvNoLength:		//flags,bufmaxlen,buf
+			{
+		    TInt readByteCount = Message().Int1();
+		    TInt readFlags = Message().Int0();
+		    ASocket::RecvL(KNoXferLen, KNoAddrArg, readByteCount, readFlags, EFalse, EFalse);
+			}
+			break;
+		case ESoRecvOneOrMoreNoLength:	//flags,bufmaxlen,buf
+			{
+		    TInt readByteCount = Message().Int1();
+		    TInt readFlags = Message().Int0();
+		    ASocket::RecvL(KNoXferLen, KNoAddrArg, readByteCount, readFlags, EFalse, ETrue);
+			}
+			break;
+		case ESoRecvOneOrMore:		//flags,xferlen,buf
+			{
+		    TInt readByteCount = msg.GetDesMaxLengthL(2);
+		    TInt readFlags = Message().Int0();
+		    ASocket::RecvL(MSG_PRM(1), KNoAddrArg, readByteCount, readFlags, EFalse, ETrue);
+			}
+			break;
+		case ESoRecvFrom:			//xferlen(flags),addr,buf
+			{
+		    TInt readByteCount = msg.GetDesMaxLengthL(2);
+			ReadParamL(ESocketCurrentMessage,MSG_PRM(0),iXferLength);
+			TInt readFlags = iXferLength();
+		    ASocket::RecvL(MSG_PRM(0), MSG_PRM(1), readByteCount, readFlags, EFalse, EFalse);
+			}
+			break;
+		case ESoRecv:				//flags,xferlen,buf
+			{
+		    TInt readByteCount = msg.GetDesMaxLengthL(2);
+		    TInt readFlags = Message().Int0();
+		    ASocket::RecvL(MSG_PRM(1), KNoAddrArg, readByteCount, readFlags, EFalse, EFalse);
+			}
+			break;
+		case ESoRead:				//0,bufmaxlen,buf
+			{
+		    TInt readByteCount = Message().Int1();
+		    ASocket::RecvL(KNoXferLen, KNoAddrArg, readByteCount, 0, EFalse, EFalse);
+			}
+			break;
+
+		case ESoConnect:
+			ConnectL();
+			break;
+
+		case ESoBind:
+			BindL();
+			break;
+
+		case ESoAccept:
+			Accept();
+			break;
+
+		case ESoListen:
+			ListenL();
+			break;
+
+		case ESoSetOpt:
+			SetSockOptionL();
+			break;
+
+		case ESoGetOpt:
+			GetSockOptionL();
+			break;
+
+		case ESoIoctl:
+			IoctlL();
+			break;
+
+		case ESoGetDiscData:
+			GetDisconnectDataL();
+			break;
+
+		case ESoGetLocalName:
+			LocalNameL();
+			break;
+
+		case ESoGetRemoteName:
+			RemoteNameL();
+			break;
+
+		case ESoCancelRecv:
+			CancelRecv();
+			break;
+
+		case ESoCancelSend:
+			CancelSend();
+			break;
+
+		case ESoCancelIoctl:
+			CancelIoctl();
+			break;
+
+		case ESoCancelConnect:
+			CancelConnect();
+			break;
+
+		case ESoCancelAccept:
+			CancelAccept();
+			break;
+
+		case ESoCancelAll:
+			CancelAll();
+			break;
+
+		case ESoSocketInfo:
+		   GetInfoL();
+			break;
+
+		case ESoReference:
+			ReferenceL();
+			break;
+
+		default:
+			SetReturn(KErrNotSupported);
+		}
+	// message for this CSocket has been processed - can reset iMessage handle
+	if (processed)
+	    {
+	    static_cast<CSocketMessage*>(iCurrentMsg)->ProcessedMessage();
+	    }
+	}
+
+void CSocket::CompleteFlowRequestMessage(TInt err)
+	{
+	LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSocket::CompleteFlowRequestMessage() socket (%08X) completing flow request message (%08X) with %d"), this, iFlowRequestMessage.Handle(), err) );
+	iFlowRequestMessage.Complete(err);
+	}
+
+// ------------------------------------------------
+TInt CSocketMessage::ReadDes(TInt aSrcParamIndex,TDes8 &aDes,TInt anOffset)
+	{
+	return iMessage.Read(aSrcParamIndex, aDes, anOffset);
+	}
+
+TInt CSocketMessage::ReadInt(TInt aSrcParamIndex)
+	{
+	TInt param = 0;
+	switch (aSrcParamIndex)
+		{
+	case 0:
+		param = iMessage.Int0();
+		break;
+		
+	case 1:
+		param = iMessage.Int1();
+		break;
+		
+	case 2:
+		param = iMessage.Int2();
+		break;
+	
+	case 3:
+		param = iMessage.Int3();
+		break;
+		
+	default:
+		__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSockS_SOCK, 1));
+		}
+	return param;
+	}
+
+TInt CSocketMessage::ReadMBuf(TInt /* aSrcParamIndex */, RMBufChain& /* aBufChain */)
+	{
+	// Currently we don't support writing into RMBufChains
+	User::Invariant();
+	return KErrNotSupported;
+	}
+
+TInt CSocketMessage::WriteDes(TInt aDstParamIndex,const TDesC8& aDes,TInt anOffset)
+	{
+	return iMessage.Write(aDstParamIndex, aDes, anOffset);
+	}
+
+TInt CSocketMessage::WriteMBuf(TInt /* aDstParamIndex */,RMBufChain& /* aBufChain */)
+	{
+	// Currently we don't support writing into RMBufChains
+	User::Invariant();
+	return KErrNotSupported;
+	}
+	
+void CSocketMessage::InitMBuf(TInt /* aParamIndex */)
+	{
+	// Currently we don't support RMBufChains
+	User::Invariant();		
+	}
+
+void CSocketMessage::CompleteMessage(TInt anError)
+	{
+	iMessage.Complete(anError);
+	}
+
+void CSocketMessage::AcquireMessage(AMessage* aMessage)
+	{
+	CSocketMessage* msg = (static_cast<CSocketMessage*>(this));
+	CSocketMessage* msg2 = (static_cast<CSocketMessage*>(aMessage));	
+	msg->SetMessage(msg2->Message());
+	}
+
+TBool CSocketMessage::IsNull (TInt aParamIndex)
+	{
+	switch (aParamIndex)	
+		{
+		case 0:
+		return (iMessage.Ptr0() == NULL);
+
+		case 1:
+		return (iMessage.Ptr1() == NULL);		
+		
+		case 2:
+		return (iMessage.Ptr2() == NULL);				
+		
+		case 3:
+		return (iMessage.Ptr3() == NULL);						
+		
+		default:
+		__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSockS_SOCK, 2));
+		}
+	return EFalse;
+	}
+
+// --------------------------------------------------------------
+
+#ifdef SYMBIAN_NETWORKING_UPS
+TInt CSocketMessage::GetProcessAndThreadId(TProcessId& aProcessId, TThreadId& aThreadId) const
+	{
+	return ASockSubSessionPlatsecApiExt::GetProcessAndThreadIdFromRMessage(Message(), aProcessId, aThreadId);
+	}
+#endif