--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/ss_roles.cpp Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,1920 @@
+// Copyright (c) 2005-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+#include "ss_roles.h"
+
+#include <e32base.h>
+#include <ss_glob.h>
+#include <comms-infras/ss_log.h>
+#include <es_ini.h>
+#include <cfthread.h>
+#include <rsshared.h> // logging tags
+#include "ss_subconn.h"
+#include <comms-infras/ss_tiermanagerutils.h>
+#include <ss_sock.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <es_sock_internal.h>
+#endif
+#include "SS_rslv.H"
+#include "SS_conn.H"
+#include <comms-infras/ss_subconnprov.h>
+#include <comms-infras/ss_connprov.h>
+#include <comms-infras/ss_sapshim.h>
+#include <comms-infras/idquerynetmsg.h>
+
+#include <comms-infras/nifprvar.h> //for KNifEntireConnectionSubConnectionId
+#include <elements/responsemsg.h> //CResponseMsg
+#include "ss_connectionsession.h"
+#include "ss_flowrequest.h"
+#include "ss_msgs.h"
+#include <ecom/ecom.h>
+#include <ecom/implementationproxy.h>
+
+#include "ss_connectionserver.h"
+#include "ss_tierthreadmap.h"
+
+#include <comms-infras/ss_nodemessages_internal_esock.h>
+#ifdef SYMBIAN_ZERO_COPY_NETWORKING
+#include <comms-infras/commsbufpondop.h>
+#else
+#include <es_mbman.h>
+#endif // SYMBIAN_ZERO_COPY_NETWORKING
+
+
+
+#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_rls, "ESockSSocks_rls.");
+#endif
+
+using ESock::MProviderSelector;
+using ESock::ISelectionNotify;
+
+#define MSG_PRM(prmIndex) (prmIndex)
+using namespace NetInterfaces;
+
+using namespace NetInterfaces;
+using namespace ESock;
+using namespace Messages;
+using namespace Den;
+using namespace CommsFW;
+
+#include <cs_subconparams.h>
+
+
+
+//
+// CPlayer
+//
+
+CPlayer* CPlayer::NewL(CWorkerThread* aOwnerThread, TPlayerRole aPlayerRole)
+ {
+ CPlayer* self = new(ELeave) CPlayer(aOwnerThread, aPlayerRole);
+ return self;
+ }
+
+/**
+The Player destructor doesn't have much to do as a lot of the cleanup is done during the
+normal shutdown routines. Here the Player merely deletes all sub-sessions it owns.
+*/
+CPlayer::~CPlayer()
+ {
+ // The object container is stored as a packed array, so working backwards through it avoids invalidating
+ // the iterator when removing entries (and as a bonus is more efficient)
+ LOG(ESockLog::Printf(KESockBootingTag, _L8("CPlayer::~CPlayer()")));
+ iTransferBuffer.Close();
+ }
+
+CPlayer::CPlayer(CWorkerThread* aOwnerThread, TPlayerRole aPlayerRole)
+: CCommonPlayer(aOwnerThread, aPlayerRole)
+ {
+ LOG(ESockLog::Printf(KESockBootingTag, _L8("CPlayer::CPlayer()")));
+ }
+
+CSockSubSession* CPlayer::SubSession(const Den::TSubSessionUniqueId& aSubSessionUniqueId) const
+ {
+ return static_cast<CSockSubSession*>(CCommonPlayer::SubSession(aSubSessionUniqueId));
+ }
+
+CSockSession* CPlayer::CurrentSession() const
+ {
+ return static_cast<CSockSession*>(CCommonPlayer::Session());
+ }
+
+CWorkerThread& CPlayer::WorkerThread() const
+ {
+ return static_cast<CWorkerThread&>(CCommonPlayer::WorkerThread());
+ }
+
+/**
+Check whether the Player is ready to shut down and if so, tells the owning Worker Thread
+*/
+TBool CPlayer::IsPlayerShutdownComplete()
+ {
+ CSockManData* globals = SockManGlobals::Get();
+ // Basic reason: we have no subsessions or protocol families remaining open
+ TBool shutdownComplete = globals->iNumFamilies == 0;
+ LOG_STMT(TBool dataThreadShutdownPending = EFalse;)
+ if(shutdownComplete)
+ {
+ // But it could be that we're providing management services and have a data thread still bound; if so we hold-off from shutdown
+ // until the data thread completes its own shutdown. Being relatively dumb it certainly can't survive without us.
+ if(!HasDataPlane() && !SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EDataPlane)).IsNull())
+ {
+ shutdownComplete = EFalse;
+ LOG_STMT(dataThreadShutdownPending = ETrue;)
+ }
+ }
+
+ LOG(ESockLog::Printf(KESockBootingTag, _L8("CPlayer::MaybeSetPlayerShutdownComplete(), shutdownComplete = %d [#subSess=%d, numFam=%d, dataPending=%d]"),
+ shutdownComplete, SubSessions().Count(), globals->iNumFamilies, dataThreadShutdownPending) );
+
+ if(globals->iNumFamilies)
+ {
+ // Help them figure out what (might be) blocking shutdown
+#ifdef __FLOG_ACTIVE
+ TProtocolManagerLogger::LogLoadedInfo();
+#endif
+ }
+
+ return shutdownComplete;
+ }
+
+/**
+Called directly by the PitBoss to get protocol information.
+@note Index is 1-based for legacy reasons.
+*/
+TInt CPlayer::ProtocolInfo(TUint aIndex, TProtocolDesc& aProtocol)
+ {
+ // This could be optimised, eg to remember the last found position in case caller is iterating from 1..n protocols (since the
+ // code here also iterates that gives O2 complexity). However, it is likely that this is a seldom-used function
+ if((aIndex > SockManGlobals()->iNumProtocols) || aIndex<1)
+ {
+ return KErrNotSupported;
+ }
+
+ // Simply iterate along the queue aIndex times
+ TSglQueIter<CProtocolRef> i(*SockManGlobals()->iProtocols);
+
+ while(--aIndex)
+ {
+ i++;
+ }
+
+ aProtocol=((CProtocolRef*)i)->Info();
+
+ return KErrNone;
+ }
+
+/**
+Write a handle back to Ptr3 of the current message
+*/
+TInt CPlayer::WriteSubSessionHandle(TInt aHandle)
+ {
+ TPckgC<TInt> pH(aHandle);
+ return SafeMessage().Write(MSG_PRM(3),pH);
+ }
+
+void CPlayer::CommsApiExtBindIfaceL(const RMessage2& aMessage, CSockSubSession& aSubSession)
+ {
+ aSubSession.CommsApiExtBindIfaceL(aMessage);
+ }
+
+void CPlayer::CommsApiExtIfaceSendReceiveL(const RMessage2& aMessage, CSockSubSession& aSubSession)
+ {
+ aSubSession.CommsApiExtIfaceSendReceiveL(aMessage);
+ }
+
+void CPlayer::CloseExtensionInterface(const RMessage2& aMessage, CSockSubSession& aSubSession)
+ {
+ aSubSession.CloseExtensionInterface(aMessage);
+ }
+
+/**
+Called from a socket to delete it
+Removing a socket has the side effect of Close()ing it.
+*/
+void CPlayer::DeleteSocket(CSocket& aSocket)
+ {
+ aSocket.InitiateDestruction();
+ }
+
+
+
+MShimControlClient* CPlayer::CSubConnectionProviderFromHandleL(ESock::CConnection& /*aConnection*/, TSubConnectionUniqueId /*aSubConnectionUniqueId*/)
+ {//this is a very link shim specific function to send a message to the shim connection provider factory
+ LOG( ESockLog::Printf(_L("CPlayer %08x:\tCSubConnectionProviderFromHandleL() KErrNotReady"), this) );
+ User::Leave(KErrNotReady);
+ return NULL;
+ }
+
+/**
+ Process the client message forwarded from the Dealer. For subsession-Close commands
+ the Dealer provides the subsession pointer explicitly as it has already been removed from
+ the index.
+*/
+void CPlayer::DoProcessMessageL(const RSafeMessage& aMessage, Den::CWorkerSubSession* aSubSession)
+ {
+ LOG(
+ TBuf8<64> messBuf;
+ ESockLog::IPCMessName((TSockMess) aMessage.Function(), messBuf);
+ ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tProcessMessageL: session=%08x, subsess=%08x, Message(%08x) [%S]"), Session(), aSubSession, aMessage.Handle(), &messBuf);
+ );
+
+ switch (aMessage.Function())
+ {
+ case ESoCreateNull:
+ {
+ TInt dummyHandle;
+ NewSocketL(ETrue, dummyHandle);
+ break;
+ }
+
+// case ESSNumProtocols:
+// NumProtocols();
+// break;
+ case ESSProtocolInfo:
+ ProtocolInfo();
+ break;
+
+ case ESSProtocolInfoByName:
+ ProtocolInfoByName();
+ break;
+
+ case ESSProtocolStart:
+ LoadProtocolL(aMessage.Int0(),aMessage.Int1(),aMessage.Int2());
+ break;
+
+ case ESSProtocolStop:
+ UnLoadProtocolL(aMessage.Int0(),aMessage.Int1(),aMessage.Int2());
+ break;
+
+// socket messages
+ case ESoCreate:
+ NewSocketDefaultL();
+ break;
+
+ case ESoCreateWithConnection:
+ NewSocketWithConnectionL();
+ break;
+
+ case ESoCreateWithSubConnection:
+ NewSocketWithSubConnectionL();
+ break;
+
+ case ESoTransfer:
+ __ASSERT_DEBUG(aSubSession->Type().iType == TCFSubSessInfo::ESocket, User::Panic(KSpecAssert_ESockSSocks_rls, 2)); // Dealer does all of the validation for us
+ TransferSocketL(static_cast<CSocket*>(aSubSession));
+ break;
+
+// Host resolver message types
+ case EHRCreate:
+ NewHostResolverDefaultL(aMessage.Int0(),aMessage.Int1());
+ break;
+
+ case EHRCreateWithConnection:
+ NewHostResolverWithConnectionL(aMessage.Int0(),aMessage.Int1(), aMessage.Int2());
+ break;
+
+// Service resolver message types
+ case ESRCreate:
+ NewServiceResolverL(aMessage.Int0(),aMessage.Int1(),aMessage.Int2());
+ break;
+
+// Net database message types
+ case ENDCreate:
+ NewNetDatabaseL(aMessage.Int0(),aMessage.Int1());
+ break;
+
+ // Connection Messages
+ case ECNCreate:
+ {
+ NewConnectionL();
+ break;
+ }
+ case ECNCreateWithName:
+ {
+ NewConnectionWithNameL(static_cast<CSockSubSession*>(aSubSession));
+ break;
+ }
+/*
+ case ESCPSStop:
+ case ESCPSProgressNotification:
+ case ESCPSCancelProgressNotification:
+ case ESCPSDataTransferred:
+ case ESCPSDataTransferredCancel:
+ case ESCPSDataSentNotificationRequest:
+ case ESCPSDataSentNotificationCancel:
+ case ESCPSDataReceivedNotificationRequest:
+ case ESCPSDataReceivedNotificationCancel:
+ case ESCPSIsSubConnectionActiveRequest:
+ case ESCPSIsSubConnectionActiveCancel:
+ case ESCPSGetSubConnectionInfo:
+ {
+ __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 3));
+ ESock::CConnection* cn = static_cast<ESock::CConnection*>(aSubSession);
+ TSubConnectionUniqueId subConnectionUniqueId = aMessage.Function() != ESCPSGetSubConnectionInfo ? static_cast<TSubConnectionUniqueId>(aMessage.Int0()) : KNifEntireConnectionSubConnectionId;
+ MShimControlClient* sc = CSubConnectionProviderFromHandleL(*cn, subConnectionUniqueId);
+ if (!sc)
+ {
+ LOG( ESockLog::Printf(_L("CPlayer %08x:\tProcessMessageL() ESCPS...... KErrNotReady"), this) );
+ User::Leave(KErrNotReady);
+ }
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocks_rls, 4));
+ //@TODO service RConnection sub-connection oriented calls
+ //iComplete = CSubConnection::ServiceL(*sc,aMessage);
+
+ break;
+ }
+*/
+ case ESCCreate:
+ {
+ LOG( ESockLog::Printf(KESockSubConnectionTag, _L8("CSubConnection %08x\tESCCreate aMessage %08x"), this, &SafeMessage()) );
+ ESock::CSubConnection* sc = NewSubConnectionWithConnectionL();
+ __ASSERT_DEBUG(sc, User::Panic(KSpecAssert_ESockSSocks_rls, 5));
+ //If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed on leave
+ //The activity also takes ownership of the CSubConnection for the duration of the activity for cleanup purposes
+ sc->CMMSockSubSession::ReceivedL(ESCCreate, ESock::TCFInternalEsock::TSubSess(ESCCreate,SafeMessage()).CRef());
+ break;
+ }
+
+ case ECommsApiExtBindIface:
+ __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 6));
+ CommsApiExtBindIfaceL(aMessage, static_cast<CSockSubSession&>(*aSubSession));
+ break;
+
+ case ECommsApiExtIfaceSend:
+ case ECommsApiExtIfaceSendReceive:
+ __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 7));
+ CommsApiExtIfaceSendReceiveL(aMessage, static_cast<CSockSubSession&>(*aSubSession));
+ break;
+
+ case ECommsApiExtIfaceClose:
+ {
+ CloseExtensionInterface(aMessage, static_cast<CSockSubSession&>(*aSubSession));
+ break;
+ }
+
+ default:
+ __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 8));
+
+ aSubSession->ProcessMessageL();
+
+ break;
+ }
+
+ // Message handlers can change the state of the iMessage if they want to hold onto the message.
+ // They can also write a return value to iReturn.
+ if (iComplete)
+ {
+ LOG(ESockLog::Printf(KESockServerTag, _L8("CPlayer:\tProcessMessageL, session=%08x, RMessage2::Complete (%08x) with %d."), Session(), aMessage.Handle(), iReturn) );
+ aMessage.Complete(Return());
+ }
+
+ //This is a normal return so we do no longer need the reference
+ SetSession(NULL);
+ }
+
+/**
+Get info for a protocol by index.
+*/
+void CPlayer::ProtocolInfo()
+ {
+ TProtocolDesc prot;
+ TInt ret=0;
+ TInt localIndex = static_cast<CPitBoss&>(PitBoss()).GetLocalProtocolIndex(SafeMessage().Int1());
+ if((ret=ProtocolInfo(localIndex,prot))==KErrNone)
+ {
+ TPckgC<TProtocolDesc> p(prot);
+ ret = SafeMessage().Write(MSG_PRM(0),p);
+ }
+ SetReturn(ret);
+ }
+
+/**
+Get protocol info by name.
+*/
+void CPlayer::ProtocolInfoByName()
+ {
+ TProtocolName name;
+ TServerProtocolDesc prot;
+ TInt ret=0;
+
+ ret = SafeMessage().Read(MSG_PRM(1),name);
+
+ if((ret=ProtocolInfo(name, prot))==KErrNone)
+ {
+ TPckgC<TProtocolDesc> p(prot);
+ ret = SafeMessage().Write(MSG_PRM(0),p);
+ }
+ SetReturn(ret);
+ }
+
+/**
+Find a protocol by name - no wildcard support.
+*/
+TInt CPlayer::ProtocolInfo(const TDesC &aName, TServerProtocolDesc &aProtocol)
+ {
+ TSglQueIter<CProtocolRef> i(*SockManGlobals::Get()->iProtocols);
+
+ // Run the queue looking for a match.
+ do
+ {
+ if(((CProtocolRef *)i)->Info().iName.CompareF(aName)==0)
+ {
+ aProtocol=((CProtocolRef*)i)->Info();
+ return KErrNone;
+ }
+ i++;
+ }
+ while((CProtocolRef *)i);
+
+ return KErrNotFound;
+ }
+
+
+/**
+The socket reference is the object name preceded by the Worker's id and a space. This is
+intended as an opaque cookie for use with socket transfer.
+*/
+void CPlayer::TransferSocketL(CSocket* aSocket)
+ {
+ __ASSERT_DEBUG(&aSocket->Player() == this, User::Panic(KSpecAssert_ESockSSocks_rls, 9));
+
+ TInt id;
+ TInt ret;
+
+ {
+ ProtocolManager::TransferSocketL(aSocket, this);
+ aSocket->CancelAll();
+
+ CurrentSession()->SubSessions().Lock();
+
+ ret = PitBoss().AddSubSession(aSocket, CurrentSession(), id);
+ aSocket->SetUniqueId(PitBoss().NextSubSessionUniqueId());
+
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ if(ret == KErrNone)
+ {
+ {
+ aSocket->Session()->SubSessions().Lock();
+
+ // Remove from original session
+ CSubSessionIx& srcSubSessions = aSocket->Session()->SubSessions();
+ TInt oldIndex;
+ VERIFY_RESULT(srcSubSessions.Find(aSocket, oldIndex), KErrNone);
+ PitBoss().RemoveSubSession(oldIndex, static_cast<CSockSession*>(aSocket->Session()));
+
+ aSocket->Session()->SubSessions().Unlock();
+ }
+
+ aSocket->SetSessionProxy(NULL);
+ aSocket->SetSession(CurrentSession());
+ aSocket->SetSessionProxy(CurrentSessionProxyL());
+ ret = WriteSubSessionHandle(id);
+ if (ret != KErrNone)
+ {
+ aSocket->InitiateDestruction(); // this should leave socket (almost) dead; we're not trying to reverse the transfer
+ }
+ if(ret == KErrNone && aSocket->RequiresOwnerInfo())
+ {
+ // store information about the client that created this socket
+ aSocket->StoreOwnerInfo();
+ aSocket->CommunicateOwner();
+ }
+ }
+ if(ret != KErrNone)
+ {
+ User::Leave(ret);
+ }
+ }
+
+/**
+Create a new empty socket to be used for accept.
+We need to make empty sockets just to get a valid handle to accept into.
+*/
+CSocket* CPlayer::NewSocketL(TBool aCompleteClientRequest, TInt& aHandle)
+ {
+ LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer::NewSocketL(null sock)")) );
+
+ CSocket *sp = NULL;
+ TInt ret;
+
+ {
+
+ // Create a new socket and add it our list of subsessions
+ sp = CSocket::NewLC(
+ NULL,
+ CurrentSession(),
+ this,
+ 0,
+ PitBoss().NextSubSessionUniqueId(),
+ KUndefinedSockType);
+
+ SubSessions().AppendL(sp);
+ CleanupStack::Pop();
+
+ // Now add the new socket, itself a subsession, to the global store
+ CurrentSession()->SubSessions().Lock();
+ ret = PitBoss().AddSubSession(sp, CurrentSession(), aHandle);
+ if(ret == KErrNone)
+ {
+ if(aCompleteClientRequest)
+ {
+ ret = WriteSubSessionHandle(aHandle);
+ }
+ if(ret != KErrNone)
+ {
+ PitBoss().RemoveSubSession(aHandle, CurrentSession());
+ }
+ }
+
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ if(ret != KErrNone)
+ {
+ sp->InitiateDestruction();
+ User::Leave(ret);
+ }
+
+ return sp;
+ }
+
+/**
+Create a new socket on this session for normal Open. The Player adds the new socket to
+the session owned by the dealer (uses explicitly locked access).
+*/
+CSocket* CPlayer::NewSocketL(TUint aAddrFamily, TUint aSocketType, TUint aProtocol)
+ {
+ LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tNewSocketL(family=%d, type=%d, protocol=%d"), aAddrFamily, aSocketType, aProtocol) );
+
+ CSocket* sp = NULL;
+ TInt ret;
+
+ {
+
+ // Look up the protocol for which we are creating a socket
+ CProtocolRef* protocolReference = ProtocolManager::FindProtocolL(aAddrFamily, aSocketType, aProtocol);
+
+ // Create a new socket and add it our list of subsessions
+ sp = CSocket::NewLC(
+ &(protocolReference->Info()),
+ CurrentSession(),
+ this,
+ protocolReference->Protocol(),
+ PitBoss().NextSubSessionUniqueId(),
+ aSocketType);
+
+ SubSessions().AppendL(sp);
+ CleanupStack::Pop();
+
+ CurrentSession()->SubSessions().Lock();
+ TInt id;
+ ret = PitBoss().AddSubSession(sp, CurrentSession(), id);
+ if(ret == KErrNone)
+ {
+ ret = WriteSubSessionHandle(id);
+ if(ret != KErrNone)
+ {
+ // V1 ESock didn't remove after failure, but did for the other overload of NewSocketL().
+ // Believed to have been in error
+ PitBoss().RemoveSubSession(id, CurrentSession());
+ }
+ }
+
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ if(sp->RequiresOwnerInfo())
+ {
+ // store information about the client that created this socket, to
+ // communicate to the flow once we're bound
+ sp->StoreOwnerInfo();
+ }
+
+ if(ret != KErrNone)
+ {
+ sp->InitiateDestruction();
+ User::Leave(ret);
+ }
+
+ return sp;
+ }
+
+/**
+Create a new socket on this session for normal Open. The Player adds the new socket to
+the session owned by the dealer (uses explicitly locked access).
+*/
+void CPlayer::NewSocketDefaultL()
+ {
+ TUint aAddrFamily = SafeMessage().Int0();
+ TUint aSocketType = SafeMessage().Int1();
+ TUint aProtocol = SafeMessage().Int2();
+
+ LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tNewSocketDefaultL(family=%d, type=%d, protocol=%d"), aAddrFamily, aSocketType, aProtocol) );
+ CSocket* s = NewSocketL(aAddrFamily, aSocketType, aProtocol);
+
+ TFlowParams flowParams(
+ aAddrFamily,
+ aSocketType,
+ aProtocol,
+ TFlowParams::EImplicit,
+ CurrentSessionProxyL());
+
+ //requesting a lower flow by throwing a self-dispatcher (TCFImplicitFlowRequest) through the
+ //fence (onto the control plane). TCFImplicitFlowRequest assumes no preexiting stack (hence implicit)
+ //and it will select and start a suitable stack based on the default access point.
+ //That stack will be interrogated for a suitable flow (flowParams), which will be returned back
+ //to the sender (socket) with TBindTo
+ RClientInterface::OpenPostMessageClose(s->Id(), //socket is the sender
+ SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ETierMgrPlane)), //phoney recipient - we only care the recipient is on the control plane so that this message is dispatched on the correct thread
+ TCFImplicitFlowRequest(s->UniqueId(), flowParams));
+
+ s->SetFlowRequestPending(ETrue);
+ s->AdoptFlowRequestMessage(SafeMessage());
+
+ DontCompleteCurrentRequest();
+ }
+
+/**
+Create a new socket on this session for normal Open
+*/
+void CPlayer::NewSocketWithConnectionL()
+ {
+ // If we don't host the data plane then the request was forwarded to us to determine which data thread shall create the socket
+ if(!HasDataPlane())
+ {
+ Messages::TNodeId flowFC = SockManGlobals()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EDataPlane));
+ __ASSERT_DEBUG(!flowFC.IsNull(), User::Panic(KSpecAssert_ESockSSocks_rls, 10));
+ TPlayerForwardRequestMsg msg(SafeMessage(), TPlayerForwardRequestMsg::NormalCreationFlag());
+ WorkerThread().PostMessage(flowFC.Thread(), msg);
+ DontCompleteCurrentRequest();
+ return;
+ }
+
+ TPckgBuf<TSockOpen> argPkg;
+ SafeMessage().ReadL(MSG_PRM(0),argPkg);
+
+ //!!PS remember the race conditions in case someone closes connection in control thread
+ //(Lock on the sub-session queue should persist over the code accessing cn*
+ CSocket* s = NewSocketL(argPkg().iAddrFamily, argPkg().iSockType, argPkg().iProtocol);
+
+ // Send the flow request message to the connection plane
+ TFlowParams flowParams(
+ argPkg().iAddrFamily,
+ argPkg().iSockType,
+ argPkg().iProtocol,
+ TFlowParams::EExplicitConnection,
+ CurrentSessionProxyL());
+
+ //requesting a lower flow by throwing a self-dispatcher (TCFConnFlowRequest) through the
+ //fence (onto the control plane). TCFConnFlowRequest will interrogate the connection (argPkg().iHandle)
+ //for its default subconnection and the subconnection for a suitable (flowParams) flow.
+ //The flow will be returned back to the sender (socket) with TBindTo.
+ RClientInterface::OpenPostMessageClose(s->Id(), //socket is the sender
+ SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EConnPlane)), //phoney recipient - we only care the recipient is on the control plane, so that this message will be dispatched on a correct thread.
+ TCFConnFlowRequest(s->UniqueId(), *CurrentSession(), argPkg().iHandle, flowParams));
+
+ s->SetFlowRequestPending(ETrue);
+ s->AdoptFlowRequestMessage(SafeMessage());
+
+ DontCompleteCurrentRequest();
+ }
+
+/**
+Create a new socket on this session for normal Open.
+*/
+void CPlayer::NewSocketWithSubConnectionL()
+ {
+ // If we don't host the data plane then the request was forwarded to us to determine which data thread shall create the socket
+ if(!HasDataPlane())
+ {
+ Messages::TNodeId flowFC = SockManGlobals()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EDataPlane));
+ __ASSERT_DEBUG(!flowFC.IsNull(), User::Panic(KSpecAssert_ESockSSocks_rls, 11));
+ TPlayerForwardRequestMsg msg(SafeMessage(), TPlayerForwardRequestMsg::NormalCreationFlag());
+ WorkerThread().PostMessage(flowFC.Thread(), msg);
+ DontCompleteCurrentRequest();
+ return;
+ }
+
+ TPckgBuf<TSockOpen> argPkg;
+ SafeMessage().ReadL(MSG_PRM(0),argPkg);
+
+ LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tNewSocketWithSubConnectionL(family=%d, type=%d, protocol=%d"), argPkg().iAddrFamily, argPkg().iSockType, argPkg().iProtocol) );
+ CSocket* s = NewSocketL(argPkg().iAddrFamily, argPkg().iSockType, argPkg().iProtocol);
+
+ // Send the flow request message to the connection plane
+ TFlowParams flowParams(
+ argPkg().iAddrFamily,
+ argPkg().iSockType,
+ argPkg().iProtocol,
+ TFlowParams::EExplicitSubConnection,
+ CurrentSessionProxyL());
+
+ //requesting a lower flow by throwing a self-dispatcher (TCFSubConnFlowRequest) through the
+ //fence (onto the control plane). TCFConnFlowRequest will interrogate the subconnection (argPkg().iHandle)
+ //for a suitable (flowParams) flow. The flow will be returned back to the sender (socket) with TBindTo.
+ RClientInterface::OpenPostMessageClose(s->Id(), //socket is the sender
+ SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ESubConnPlane)), //phoney recipient - we only care the recipient is on the control plane so that this message is dispatched on the correct thread
+ TCFSubConnFlowRequest(s->UniqueId(), *CurrentSession(), argPkg().iHandle, flowParams));
+
+ s->SetFlowRequestPending(ETrue);
+ s->AdoptFlowRequestMessage(SafeMessage());
+
+ DontCompleteCurrentRequest();
+ }
+
+/**
+Create a new host resolver for this session.
+*/
+CHostResolver* CPlayer::NewHostResolverL(TUint anAddrFamily,TUint aProtocol)
+ {
+ CHostResolver* h = NULL;
+ TInt ret;
+
+ {
+
+ h=ProtocolManager::NewHostResolverL(anAddrFamily,aProtocol, this, PitBoss().NextSubSessionUniqueId());
+
+ TInt id;
+ CurrentSession()->SubSessions().Lock();
+ ret = PitBoss().AddSubSession(h, CurrentSession(), id);
+ if(ret == KErrNone)
+ {
+ ret = WriteSubSessionHandle(id);
+ if(ret != KErrNone)
+ {
+ PitBoss().RemoveSubSession(id, CurrentSession());
+ }
+ }
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ if(ret != KErrNone)
+ {
+ h->InitiateDestruction();
+ User::Leave(ret);
+ }
+
+ if(h->RequiresOwnerInfo())
+ {
+ // store information about the client that created this host resolver
+ h->StoreOwnerInfo();
+ }
+
+ return (h);
+ }
+
+/**
+Create a new host resolver for this session.
+*/
+void CPlayer::NewHostResolverDefaultL(TUint aAddrFamily,TUint aProtocol)
+ {
+ CHostResolver* h = NewHostResolverL(aAddrFamily, aProtocol);
+
+ // Send the flow parameters to the tier manager plane
+ TFlowParams flowParams(
+ aAddrFamily,
+ KUndefinedSockType,
+ aProtocol,
+ TFlowParams::EImplicit,
+ CurrentSessionProxyL(),
+ EFalse);
+
+ //requesting a lower flow by throwing a self-dispatcher (TCFImplicitFlowRequest) through the
+ //fence (onto the control plane). TCFImplicitFlowRequest assumes no preexiting stack (hence implicit)
+ //and it will select and start a suitable stack based on the default access point.
+ //That stack will be interrogated for a suitable flow (flowParams), which will be returned back
+ //to the sender (host resolver) with TBindTo
+ RClientInterface::OpenPostMessageClose(h->Id(), //socket is the sender
+ SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ETierMgrPlane)), //phoney recipient - we only care the recipient is on the control plane so that this message is dispatched on the correct thread
+ TCFImplicitFlowRequest(h->UniqueId(), flowParams));
+
+ h->SetFlowRequestPending(ETrue);
+ h->AdoptFlowRequestMessage(SafeMessage());
+
+ DontCompleteCurrentRequest();
+ }
+
+/**
+Create a new host resolver for this session.
+*/
+void CPlayer::NewHostResolverWithConnectionL(TUint aAddrFamily, TUint aProtocol, TInt aHandle)
+ {
+ CHostResolver* h = NewHostResolverL(aAddrFamily, aProtocol);
+
+ // Send the flow parameters to the tier manager plane
+ TFlowParams flowParams(
+ aAddrFamily,
+ KUndefinedSockType,
+ aProtocol,
+ TFlowParams::EExplicitConnection,
+ CurrentSessionProxyL(),
+ EFalse);
+
+ //requesting a lower flow by throwing a self-dispatcher (TCFConnFlowRequest) through the
+ //fence (onto the control plane). TCFConnFlowRequest will interrogate the connection (aHandle)
+ //for its default subconnection and the subconnection for a suitable (flowParams) flow.
+ //The flow will be returned back to the sender (socket) with TBindTo.
+ RClientInterface::OpenPostMessageClose(h->Id(), //socket is the sender
+ SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EConnPlane)), //phoney recipient - we only care the recipient is on the control plane, so that this message will be dispatched on a correct thread.
+ TCFConnFlowRequest(h->UniqueId(), *CurrentSession(), aHandle, flowParams));
+
+ h->SetFlowRequestPending(ETrue);
+ h->AdoptFlowRequestMessage(SafeMessage());
+
+ DontCompleteCurrentRequest();
+ }
+
+
+/**
+Create a new service resolver for this session.
+*/
+void CPlayer::NewServiceResolverL(TUint anAddrFamily,TUint aSocketType,TUint aProtocol)
+ {
+ CServiceResolver* r = NULL;
+ TInt ret;
+
+ {
+
+ r=ProtocolManager::NewServiceResolverL(anAddrFamily, aSocketType, aProtocol, this, PitBoss().NextSubSessionUniqueId());
+
+ TInt id;
+ CurrentSession()->SubSessions().Lock();
+ ret = PitBoss().AddSubSession(r, CurrentSession(), id);
+ if(ret == KErrNone)
+ {
+ ret = WriteSubSessionHandle(id);
+ if(ret != KErrNone)
+ {
+ PitBoss().RemoveSubSession(id, CurrentSession());
+ }
+ }
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ if (ret != KErrNone)
+ {
+ delete r;
+ User::Leave(ret);
+ }
+ }
+
+/**
+Create a new net database for this session.
+*/
+void CPlayer::NewNetDatabaseL(TUint anAddrFamily,TUint aProtocol)
+ {
+ CNetDatabase* n = NULL;
+ TInt ret;
+
+ {
+
+ n=ProtocolManager::NewNetDatabaseL(anAddrFamily, aProtocol, this, PitBoss().NextSubSessionUniqueId());
+
+ TInt id;
+ CurrentSession()->SubSessions().Lock();
+ ret = PitBoss().AddSubSession(n, CurrentSession(), id);
+ if(ret == KErrNone)
+ {
+ ret = WriteSubSessionHandle(id);
+ if(ret != KErrNone)
+ {
+ PitBoss().RemoveSubSession(id, CurrentSession());
+ }
+ }
+
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ if (ret!=KErrNone)
+ {
+ delete n;
+ User::Leave(ret);
+ }
+ }
+
+/**
+Create a new socket on this session for normal Open.
+*/
+CSubConnection* CPlayer::NewSubConnectionWithConnectionL()
+ {
+ TPckgBuf<TSubConnOpen> argPkg;
+ SafeMessage().ReadL(MSG_PRM(0),argPkg);
+
+ ESock::CConnection* cn=static_cast<CSockSession*>(CurrentSession())->CConnectionFromHandle(argPkg().iHandle);
+ if (!cn)
+ {
+ PanicClient(KESockClientPanic, ESockBadHandle);
+ return NULL;
+ }
+
+ if (!cn->ServiceProvider())
+ {
+ LOG( ESockLog::Printf(_L("CPlayer %08x:\tNewSubConnectionWithConnectionL() KErrNotReady"), this) );
+ User::Leave(KErrNotReady);
+ }
+
+ return NewSubConnectionL(*cn);
+ }
+
+/**
+Create a new sub-connection for this session.
+*/
+CSubConnection* CPlayer::NewSubConnectionL(ESock::CConnection& aConnection)
+ {
+ ESock::CSubConnection* subconn = NULL;
+ TInt ret;
+
+ {
+
+ subconn = ESock::CSubConnection::NewL(aConnection, this, PitBoss().NextSubSessionUniqueId());
+ ret = SubSessions().Append(subconn);
+ if(ret == KErrNone)
+ {
+ CurrentSession()->SubSessions().Lock();
+ TInt id;
+ TInt ret = PitBoss().AddSubSession(subconn, CurrentSession(), id);
+ if(ret == KErrNone)
+ {
+ ret = WriteSubSessionHandle(id);
+ if(ret != KErrNone)
+ {
+ PitBoss().RemoveSubSession(id, CurrentSession());
+ }
+ }
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ }
+
+ if (ret!=KErrNone)
+ {
+ delete subconn;
+ User::Leave(ret);
+ }
+
+ return subconn;
+ }
+
+void CPlayer::NewConnectionL()
+ {
+ TUint family = SafeMessage().Int0();
+ TUid tierId = TierManagerUtils::MapTierIdsL(TUid::Uid(family), 0);
+ ESock::CConnection* conn = ESock::CConnection::NewLC(static_cast<CSockSession*>(CurrentSession()), this, tierId, PitBoss().NextSubSessionUniqueId());
+ SetupNewConnectionL(conn);
+ CleanupStack::Pop(conn);
+ }
+
+void CPlayer::NewConnectionWithNameL(CSockSubSession* aSubSession)
+ {
+ // The passed subsession is the original to base the creation off
+ __ASSERT_DEBUG(aSubSession->Type().iType == TCFSubSessInfo::EConnection, User::Panic(KSpecAssert_ESockSSocks_rls, 12)); // Dealer does all of the validation for us
+
+ CConnection& origConn = static_cast<CConnection&>(*aSubSession);
+ // Police the clone open request against the security policy stored applied to the original RConnection
+ User::LeaveIfError(origConn.CheckCloneOpenPolicy(SafeMessage()));
+ ESock::CConnection* conn = ESock::CConnection::NewLC(static_cast<CSockSession*>(CurrentSession()), this, origConn, PitBoss().NextSubSessionUniqueId());
+ SetupNewConnectionL(conn);
+ CleanupStack::Pop(conn);
+ }
+
+/**
+Handle creation of a new connection for this session
+*/
+void CPlayer::SetupNewConnectionL(CConnection* aConn)
+ {
+ TInt ret;
+
+ {
+
+ SubSessions().AppendL(aConn);
+ TInt id;
+ CurrentSession()->SubSessions().Lock();
+ ret = PitBoss().AddSubSession(aConn, CurrentSession(), id);
+ if(ret == KErrNone)
+ {
+ ret = WriteSubSessionHandle(id);
+ if(ret != KErrNone)
+ {
+ PitBoss().RemoveSubSession(id, CurrentSession());
+ }
+ }
+
+ CurrentSession()->SubSessions().Unlock();
+ }
+
+ if(ret!=KErrNone)
+ {
+ User::Leave(ret);
+ }
+
+ // store information about the client that created this connection
+ // note that CConnections should always store their owner info
+ aConn->StoreOwnerInfo();
+ }
+
+CCommonSessionProxy* CPlayer::DoCreateSessionProxyL(CWorkerSession* aSession)
+ {
+ return CSockSessionProxy::NewL(aSession, *this);
+ }
+
+void CPlayer::LoadProtocolL(TUint anAddrFamily,TUint aSocketType,TUint aProtocol)
+ {
+ ProtocolManager::LoadProtocolL(anAddrFamily,aSocketType,aProtocol,this);
+ }
+
+/**
+ Find the protocol, check it is not referenced and delete it
+*/
+void CPlayer::UnLoadProtocolL(TUint anAddrFamily,TUint aSocketType,TUint aProtocol)
+ {
+ ProtocolManager::UnLoadProtocolL(anAddrFamily, aSocketType, aProtocol,this);
+ }
+
+/** 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* CPlayer::BorrowTemporaryBuffer(TInt aSize)
+ {
+ if(iTransferBuffer.Size() < aSize)
+ {
+ if(iTransferBuffer.ReAlloc(aSize) != KErrNone)
+ {
+ return NULL;
+ }
+ }
+ iTransferBuffer.SetMax(); // indicate whole of buffer available when used for MBuf CopyOut() - in general overwrite not append is expected since it's a temporary buffer
+ return &iTransferBuffer;
+ }
+
+
+#ifdef _DEBUG
+TBool CPlayer::RunPostBootChecks()
+ {
+ CWorkerThread& owner = WorkerThread();
+ if(owner.DefaultOptimalDealer())
+ {
+ // Now that booting is completed verify that all protocols can be created via this dealer, ie that
+ // our worker thread is bound to all of the necessary players
+ TWorkerId host;
+ for(TInt idx = 1; owner.PitBoss().GetWorkerForProtocol(idx, host); ++idx)
+ {
+ if(!owner.PeerReachable(host))
+ {
+ RDebug::Printf("ERROR worker %d is DefaultOptimalDealer but can't reach worker #%d for protocol #%d", owner.WorkerId(), host, idx);
+ LOG(ESockLog::Printf(KESockBootingTag, _L("ERROR worker %d is DefaultOptimalDealer but can't reach worker #%d for protocol #%d"), owner.WorkerId(), host, idx));
+ Panic(EMisconfigured);
+ }
+ }
+ }
+ return ETrue;
+ }
+#endif
+
+//
+// CSockSessionProxy
+//
+CSockSessionProxy* CSockSessionProxy::NewL(CWorkerSession* aSockSession, CPlayer& aPlayer)
+ {
+ CSockSessionProxy* self = new(ELeave) CSockSessionProxy(aSockSession, aPlayer);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CSockSessionProxy::CSockSessionProxy(CWorkerSession* aSockSession, CPlayer& aPlayer)
+: CCommonSessionProxy(aSockSession, aPlayer)
+ {
+ LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\tCSockSessionProxy(), iSockSession %08x"), this, Session()) );
+ }
+
+void CSockSessionProxy::ConstructL()
+ {
+ iProtocols=new(ELeave) CArrayFixFlat<CProtocolBase *>(16);
+ }
+
+CSockSessionProxy::~CSockSessionProxy()
+ {
+ LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\t~CSockSessionProxy(), iSockSession %08x"), this, Session()) );
+ if(iProtocols)
+ {
+ for (TInt i=0;i<iProtocols->Count();i++)
+ {
+ LOG(
+ CProtocolBase* p = iProtocols->operator[](i);
+ const TDesC& tag(p->Tag());
+ ESockLog::Printf(KESockSessDetailTag, _L("CSockSessionProxy %08x:\t~CSockSessionProxy(): closing protocol %08x '%S'"), this, p, &tag)
+ );
+
+ iProtocols->operator[](i)->Close();
+ }
+ iProtocols->Delete(0,iProtocols->Count());
+ delete iProtocols;
+ }
+ }
+
+void CSockSessionProxy::AddProtocolL(CProtocolBase* aProtocol)
+ {
+ LOG(
+ const TDesC& tag(aProtocol->Tag());
+ ESockLog::Printf(KESockSessDetailTag, _L("CSockSessionProxy %08x:\tAddProtocolL(aProtocol %08x '%S'), iSockSession %08x"), this, aProtocol, &tag, Session());
+ );
+ for(TInt i=0;i<iProtocols->Count();i++)
+ {
+ if (iProtocols->operator[](i)==aProtocol)
+ {
+ return;
+ }
+ }
+
+ iProtocols->AppendL(aProtocol);
+ aProtocol->Open();
+ }
+
+void CSockSessionProxy::RemoveProtocolL(CProtocolBase* aProtocol)
+ {
+ LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\tRemoveProtocolL(), iSockSession %08x"), this, Session()) );
+
+ CProtocolBase* p=0;
+ TInt j;
+ for(j=0;j<iProtocols->Count();j++)
+ {
+ if (iProtocols->operator[](j)==aProtocol)
+ {
+ p=iProtocols->operator[](j);
+ break;
+ }
+ }
+ if(!p)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ // in the absence of checking this protocol is not specifically referenced
+ // check no resources are referenced
+ if(Session()->SubSessions().ActiveCount())
+ {
+ User::Leave(KErrInUse);
+ }
+
+ p->Close();
+ iProtocols->Delete(j);
+ iProtocols->Compress();
+ }
+
+//
+// CPitBoss
+//
+
+CPitBoss* CPitBoss::NewL(CWorkerThread* aOwnerThread)
+ {
+ CPitBoss* self = new(ELeave) CPitBoss(aOwnerThread);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CPitBoss::~CPitBoss()
+ {
+ // Delete the list of removed protocols
+ TProtocolPairing* pair = iDeadPairHead;
+ while(pair)
+ {
+ TProtocolPairing* nextPair = pair->iNextDead;
+ delete pair;
+ pair = nextPair;
+ }
+ pair = iProtocolPairHead;
+ while(pair)
+ {
+ TProtocolPairing* nextPair = pair->iNextPair;
+ delete pair;
+ pair = nextPair;
+ }
+ delete iCompleteEskList;
+ }
+
+
+CPitBoss::CPitBoss(CWorkerThread* aOwnerThread)
+: CCommonPitBoss(aOwnerThread)
+ {
+ }
+
+void CPitBoss::ConstructL()
+ {
+ iCompleteEskList = new(ELeave) CommsFW::COwnEntryList(6);
+ iCompleteEskList->UniqueWildScanAcrossDrivesL(KEsockIniFileDir, KEsockWildCard);
+ CommsFW::COwnEntryList *noBackupEskList = new(ELeave) CommsFW::COwnEntryList(32);
+ CleanupStack::PushL(noBackupEskList);
+ noBackupEskList->UniqueWildScanAcrossDrivesL(KEsockNoBackupDir, KEsockWildCard);
+ iCompleteEskList->AddL(*noBackupEskList);
+ iPropertyKey=RootServer::KUidC32StartPropertyKey;
+ CleanupStack::PopAndDestroy(noBackupEskList);
+ CCommonPitBoss::ConstructL();
+ }
+
+TBool CPitBoss::GetWorkerForProtocol(TUint aAddrFamily, TUint aSockType, TUint aProtocol, TWorkerId& aWorker) const
+ {
+#ifdef _DEBUG
+ aWorker = TWorkerThreadPublicInfo::ENullWorkerId; // ensure arg is polluted, lest caller ignore return value
+#endif
+ TProtocolPairing* pair = FindProtocolPairing(aAddrFamily, aSockType, aProtocol);
+ if(pair)
+ {
+ aWorker = pair->iWorkerId;
+ return aWorker != TWorkerThreadPublicInfo::ENullWorkerId;
+ }
+ return EFalse;
+ }
+
+void CPitBoss::DoFreeWorkerReferences(TWorkerId aWorkerId)
+{
+ LOG(ESockLog::Printf(_L("CPitBoss::DoFreeWorkerReferences(%d)"), aWorkerId) );
+#if defined _DEBUG && !defined(ESOCKV3_TEMPORARY_PAIN_RELIEF)
+ // The RootServer normally checks the heap for leaks when the module unloads
+ // but for ESOCK modules this is commonly too early, since the PitBoss holds
+ // its reference open until the cleanup completes. Hence here we check for
+ // remaining allocations if we hold the last reference and if no thread
+ // which used it died involuntarily
+ RCFSharedHeap& heap = static_cast<RCFSharedHeap&>(*WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iHeap);
+ TInt leakCount = heap.Count(); // make it accessible for conditional breakpoints
+ LOG(ESockLog::Printf(_L8("~~~CPitBoss::FreeWorkerReferences heap(%08x).AccessCount()==%d, cell count=%d"), (TUint) &heap, heap.AccessCount(), leakCount));
+ if(!iForsakenHeapList.IsForsaken(&heap))
+ {
+ if(heap.AccessCount() <= 2) // Oddity: where does the other count come from, ie why not "1" when RS has already closed? And who does close it later?
+ {
+ if(leakCount > 0)
+ {
+ LOG(ESockLog::Printf(_L8("(log recorded under tags \"%S\" \"%S\" - you may need to enable these)"), &RootServer::KLogSubSysRSModule, &RootServer::KLogRSLeakTag));
+ heap.LogAllocatedCells(RootServer::KLogSubSysRSModule, RootServer::KLogRSLeakTag);
+
+ RProperty pubsub;
+ TInt res = pubsub.Attach(RootServer::KUidCommsProcess, RootServer::KUidCommsModuleLeakCounter);
+ //No nead for cleanup stack, cannot leave before Close
+ if (res == KErrNone)
+ {
+ TInt count;
+ res =pubsub.Get(count);
+ if (res == KErrNone)
+ {
+ count += heap.Count();
+ res =pubsub.Set(count);
+ }
+ }
+ pubsub.Close();
+ if (res != KErrNone)
+ {
+ __CFLOG_1(RootServer::KLogSubSysRSModule, RootServer::KLogRSLeakTag, _L8("Unable to report leaks. Error: %d"), res);
+ }
+ // As much as anything this log line is here to make it apparent that the breakpoint above was hit
+ LOG(ESockLog::Printf(_L8("--- end of leaked cell log")));
+ }
+ }
+ }
+
+#else
+ // Preventing unused variable warnings.
+ (void)aWorkerId;
+#endif
+}
+
+TBool CPitBoss::GetWorkerForProtocol(TUint aIndex, TWorkerId& aWorker) const
+ {
+#ifdef _DEBUG
+ aWorker = TWorkerThreadPublicInfo::ENullWorkerId; // ensure arg is polluted, lest caller ignore return value
+#endif
+ if (aIndex == 0)
+ {
+ return EFalse; // protocol indices are 1-based
+ }
+
+ /* Move pointer to protocol@index or end of list */
+ TProtocolPairing* pair = iProtocolPairHead;
+ TUint i = 1;
+ while(pair)
+ {
+ // This function only exists to support the client ability to retrieve a protocol by index, and they're only
+ // interested in externally accessible protocols. So we skip magic ones. See also CPitBoss::GetNumProtocols()
+ if(pair->iSockType < KReservedSockTypesBase)
+ {
+ if(i == aIndex)
+ {
+ break;
+ }
+ ++i;
+ }
+ pair = pair->iNextPair;
+ }
+
+ if(pair)
+ {
+ aWorker = pair->iWorkerId;
+ return aWorker != TWorkerThreadPublicInfo::ENullWorkerId;
+ }
+ return EFalse;
+ }
+
+TBool CPitBoss::GetWorkerForProtocolByName(const TProtocolName& aName, TWorkerId& aWorker) const
+ {
+#ifdef _DEBUG
+ aWorker = TWorkerThreadPublicInfo::ENullWorkerId; // ensure arg is polluted, lest caller ignore return value
+#endif
+ for(TProtocolPairing* pair = iProtocolPairHead; pair != NULL; pair = pair->iNextPair)
+ {
+ // Match the name (case insensitive)
+ if(aName.CompareF(pair->iName) == 0)
+ {
+ aWorker = pair->iWorkerId;
+ return aWorker != TWorkerThreadPublicInfo::ENullWorkerId;
+ }
+ }
+ return EFalse;
+ }
+
+/**
+Return worker which can accept a NULL Socket. Default favours a specific worker, but
+if it is not installed return the first real worker in the list. This algorithmn could change
+or default selection be made configurable.
+@param aWorker Id of the worker which can accept a NULL socket. Unchanged if none found.
+*/
+TBool CPitBoss::GetWorkerForNullSocket(TWorkerId& aWorker) const
+ {
+ TBool found=EFalse;
+ //First check if SMS WAP Worker is available by looking up heap pointer
+ if(WorkerDataGlobals().WorkerPresent(TCFWorkerThreadPublicInfo::ESmsWapPlayerThread))
+ {
+ aWorker=TCFWorkerThreadPublicInfo::ESmsWapPlayerThread;
+ found=ETrue;
+ }
+ else if(iProtocolPairHead && iProtocolPairHead->iWorkerId>0) // Take first worker in list
+ {
+ // Scan for the first valid worker (not all entries are for real protocols and some have null worker ids)
+ for(TProtocolPairing* pair = iProtocolPairHead; !found && pair != NULL; pair = pair->iNextPair)
+ {
+ if(pair->iWorkerId != TWorkerThreadPublicInfo::ENullWorkerId)
+ {
+ aWorker = pair->iWorkerId;
+ found = ETrue;
+ }
+ }
+ }
+ return found;
+ }
+
+/**
+Return the number of known protocols. Counts by walking through the short list, so
+not a super fast operation but very rarely called. Implement threadsafe (if needed) counters
+on a rainy day.
+*/
+TUint CPitBoss::GetNumProtocols()
+ {
+ TUint num=0;
+ // Count pairings that represent real protocols. The top range of sock types are reserved for internal trickery
+ for(TProtocolPairing* pair = iProtocolPairHead; pair!=NULL; pair=pair->iNextPair)
+ {
+ if(pair->iSockType < KReservedSockTypesBase)
+ {
+ num++;
+ }
+ }
+ return num;
+ }
+
+
+TBool CPitBoss::GetWorkerForTier(TInt aTierId, TWorkerId& aWorker) const
+ {
+ return GetWorkerForProtocol(KTierEntryProxyAddrFam, KTierEntryProxySockType, aTierId, aWorker);
+ }
+
+
+/**
+Lookup a entry with the specified characteristics in the list of protocol pairings.
+@see CPitBoss::TProtocolPairing
+*/
+CPitBoss::TProtocolPairing* CPitBoss::FindProtocolPairing(TUint aAddrFamily, TUint aSockType, TUint aProtocol) const
+ {
+ TProtocolPairing* pair = iProtocolPairHead;
+ while(pair)
+ {
+ if(pair->iAddrFamily == aAddrFamily &&
+ (pair->iSockType == KUndefinedSockType || aSockType == KUndefinedSockType || pair->iSockType == aSockType) &&
+ (pair->iProtocol == KUndefinedProtocol || aProtocol == KUndefinedProtocol || pair->iProtocol == aProtocol))
+ {
+ LOG( ESockLog::Printf(KESockSessDetailTag, _L("CPitBoss::FindProtocolPairing() - [aAddrFamily=%08x] [aSockType=%08x] [aProtocol=%08x] found '%S' W%d"),
+ aAddrFamily, aSockType, aProtocol, &pair->iName, pair->iWorkerId));
+ return pair;
+ }
+ pair = pair->iNextPair;
+ }
+
+ LOG( ESockLog::Printf(KESockSessDetailTag, _L("CPitBoss::FindProtocolPairing() - [aAddrFamily=%08x] [aSockType=%08x] [aProtocol=%08x] - no match"),
+ aAddrFamily, aSockType, aProtocol));
+ return NULL;
+ }
+
+/**
+Given session preferences, see if the Player supporting those protocol
+characteristics has its own Dealer.
+*/
+TBool CPitBoss::FindOptimalDealer(const TSessionPref& aPref, CCommonWorkerDealer*& aDealer)
+ {
+ TBool found=EFalse;
+ if(aPref.iAddrFamily == KUndefinedAddressFamily && aPref.iProtocol == KUndefinedProtocol)
+ {
+ // Client is asking for the default optimal dealer - if this isn't (yet) known then we quickly fail the request rather than possibly
+ // waiting for boot to complete, which might disrupt carefully tuned boot orders - we're better off foregoing the mild optimisation
+ if(iDefaultOptimalDealer != Den::TWorkerThreadPublicInfo::EMainThread)
+ {
+ found = CCommonPitBoss::FindOptimalDealer(iDefaultOptimalDealer, aDealer);
+ }
+ }
+ else
+ {
+ const TProtocolPairing* pair=FindProtocolPairing(aPref.iAddrFamily, KUndefinedSockType, aPref.iProtocol);
+ if(pair)
+ {
+ found = CCommonPitBoss::FindOptimalDealer(pair->iWorkerId, aDealer);
+ }
+ }
+ return found;
+ }
+
+CPitBoss::TProtocolPairingOwner::TProtocolPairingOwner()
+: iHead(NULL)
+ {
+ }
+
+void CPitBoss::TProtocolPairingOwner::Append(TProtocolPairing* aNode)
+ {
+ if(iHead == NULL)
+ {
+ iHead = aNode;
+ }
+ else
+ {
+ TProtocolPairing* curr = iHead;
+ TProtocolPairing* prev;
+ do
+ {
+ prev = curr;
+ curr = curr->iNextPair;
+ }
+ while(curr != NULL);
+ prev->iNextPair = aNode;
+ }
+ }
+
+void CPitBoss::TProtocolPairingOwner::Release()
+ {
+ TProtocolPairing* curr = iHead;
+ while(curr != NULL)
+ {
+ TProtocolPairing* next = curr->iNextPair;
+ delete curr;
+ curr = next;
+ }
+ iHead = NULL;
+ }
+
+
+void CPitBoss::AddProtocolToListL(TUint aAddrFamily, TUint aSockType, TUint aProtocol, const TProtocolName& aName, TWorkerId aWorker, TProtocolPairingOwner& aList)
+ {
+ TProtocolPairing* pair = new(ELeave) TProtocolPairing;
+ pair->iAddrFamily = aAddrFamily;
+ pair->iSockType = aSockType;
+ pair->iProtocol = aProtocol;
+ pair->iName = aName;
+ pair->iWorkerId = aWorker;
+ pair->iNextDead = NULL;
+ pair->iNextPair = NULL;
+ aList.Append(pair);
+ }
+
+void CPitBoss::IncorporateProtocolListL(TProtocolPairingOwner& aList)
+ {
+ LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss::IncorporateProtocolList(%08x)"), &aList) );
+ // Only safe from the main thread; thread race below
+ __ASSERT_DEBUG(iOwnerThread->IsMainThread(), User::Panic(KSpecAssert_ESockSSocks_rls, 14));
+
+#ifdef _DEBUG
+ // In UDEB check whether any pair entry already exists - if so that's a serious config mistake and we panic the miscreant diagnostically
+ // In UREL we just ignore this possibility and let things limp on as best they can
+ TProtocolPairing* curr = aList.iHead;
+ while(curr != NULL)
+ {
+ LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: Adding protocol %S [fam,sock,prot]=[%x,%x,%x] for W%d"), &curr->iName, curr->iAddrFamily, curr->iSockType, curr->iProtocol, curr->iWorkerId) );
+ TProtocolPairing* existing = FindProtocolPairing(curr->iAddrFamily, curr->iSockType, curr->iProtocol);
+ if(existing)
+ {
+ LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: already present as protocol %S for W%d"), &existing->iName, existing->iWorkerId) );
+ LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: Killing misconfigured W%d. To fix this look at the lists of .ESK files logged earlier for the two workers and ensure only one loads the protocol"), curr->iWorkerId) );
+ WorkerDataGlobals().PanicWorker(curr->iWorkerId, KESockProtocolPanic, ECorruptIniData);
+ User::Leave(KErrAlreadyExists);
+ }
+ curr = curr->iNextPair;
+ }
+#endif
+ aList.Append(iProtocolPairHead);
+ NETWORKING_ATOMIC(iProtocolPairHead = aList.iHead); // atomic write of new ptr is guaranteed; it's ok to link it in before the worker ids are set
+ // as any competing protocol lookups will politely fail
+ }
+
+
+/**
+When a worker thread dies (e.g. during shutdown) the PitBoss will discover and use this method to
+remove the protocol pairings for that particular worker.
+*/
+void CPitBoss::RemoveProtocolPairingsForWorker(TWorkerId aWorkerId)
+ {
+ LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss::RemoveProtocolPairingsForWorker(%d)"), aWorkerId) );
+ TProtocolPairing* pair = iProtocolPairHead;
+ TProtocolPairing* prevLive = NULL;
+ while(pair)
+ {
+ if(pair->iWorkerId == aWorkerId)
+ {
+ LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: Removing protocol %S [fam,sock,prot]=[%x,%x,%x] for W%d"), &pair->iName, pair->iAddrFamily, pair->iSockType, pair->iProtocol, pair->iWorkerId) );
+ if(prevLive)
+ {
+ NETWORKING_ATOMIC(prevLive->iNextPair = pair->iNextPair); // atomic write of new ptr is guaranteed
+ }
+ else
+ {
+ NETWORKING_ATOMIC(iProtocolPairHead = pair->iNextPair); // atomic write of new ptr is guaranteed
+ }
+ pair->iNextDead = iDeadPairHead;
+ NETWORKING_ATOMIC(iDeadPairHead = pair); // atomic write of new ptr is guaranteed
+ }
+ else
+ {
+ prevLive = pair;
+ }
+ pair = pair->iNextPair;
+ }
+ }
+
+void CPitBoss::AddTierPairingToListL(TInt aTierUid, const TDesC& aTierName, TWorkerId aWorker, TProtocolPairingOwner& aList)
+ {
+ AddProtocolToListL(KTierEntryProxyAddrFam, KTierEntryProxySockType, aTierUid, aTierName, aWorker, aList);
+ }
+
+const CommsFW::COwnEntryList* CPitBoss::GetCompleteList()
+ {
+ return iCompleteEskList;
+ }
+
+/**
+Used during binding when the PitBoss receives a introduction response message from a worker.
+The PitBoss will set-up housekeeping datastructures for the worker and add the supported
+protocols to its list of protocol pairings.
+@see TWorkerMsg::EMainIntroductionResp
+*/
+void CPitBoss::DoProcessWorkerIntroductionL(const TWorkerIntroductionMsg& aMsg)
+ {
+ // Now populate the protocol pairing list
+ TProtocolPairingOwner pairList;
+ CleanupReleasePushL(pairList);
+ const TWorkerThreadPublicInfo& msgInfo = aMsg.WorkerInfo();
+ CPlayer* player=static_cast<CPlayer*>(GetPlayer(aMsg));
+
+ if(player)
+ {
+ TProtocolDesc prot;
+ for(TUint protNum = 1; player->ProtocolInfo(protNum, prot) == KErrNone; ++protNum)
+ {
+ AddProtocolToListL(prot.iAddrFamily, prot.iSockType, prot.iProtocol, prot.iName, msgInfo.iWorkerId, pairList);
+ }
+
+ // Add proxy protocol pairings for any special roles
+ if(player->HasTierResolver())
+ {
+#ifdef _DEBUG
+ TWorkerId alternateTierResolverWorker;
+ __ASSERT_DEBUG(!GetWorkerForPlayerRole(KPlayerRoleTierResolver, alternateTierResolverWorker), User::Panic(KSpecAssert_ESockSSocks_rls, 15));
+#endif
+ _LIT(KTierResolverDesc, "TierResolver");
+ AddPlayerRolePairingL(KPlayerRoleTierResolver, KTierResolverDesc, msgInfo.iWorkerId, pairList);
+ }
+ }
+ IncorporateProtocolListL(pairList);
+ CleanupStack::Pop(&pairList);
+
+ TBuf8<TWorkerIntroductionMsg::KMaxIntroductionInfoSize> introInfo;
+ aMsg.IntroductionInfo(introInfo);
+ TPckgBuf<TBool> defaultOptDealer;
+ defaultOptDealer.Copy(introInfo.LeftTPtr(defaultOptDealer.MaxSize()));
+ if(defaultOptDealer())
+ {
+ if(iDefaultOptimalDealer == Den::TWorkerThreadPublicInfo::EMainThread)
+ {
+ iDefaultOptimalDealer = msgInfo.iWorkerId;
+ }
+ else
+ {
+ LOG(ESockLog::Printf(KESockBootingTag, _L("ERROR worker %d claiming DefaultOptimalDealer after worker %d already did so"), msgInfo.iWorkerId, iDefaultOptimalDealer));
+#ifdef _DEBUG
+ RDebug::Printf("ERROR worker %d claiming DefaultOptimalDealer after worker %d already did so", msgInfo.iWorkerId, iDefaultOptimalDealer);
+ Panic(EMisconfigured);
+#endif
+ }
+ }
+ }
+
+/**
+The PitBoss monitors the Comms Configurator sequence level and when the core components
+have been configured (this includes ESock) this method is called to delete any data structures
+used only during startup of ESock.
+@see CConfigurationLevelMonitor
+@see CPitBoss::iPendingIntroResponses
+*/
+void CPitBoss::DoOnCPMsConfigured()
+ {
+ // We can now delete the shared ESK data and enable simulated failure for the main thread (if configured)
+ if(iPendingIntroResponses == 0)
+ {
+ delete iCompleteEskList;
+ iCompleteEskList = NULL;
+ }
+ if(iLoadTierMappingPhase == EDealerRequest)
+ {
+ // Was awaiting boot completion to find the tier resolver
+ SendLoadTierMappingRequest();
+ }
+ }
+
+/**
+If a worker dies the PitBoss will call this method. It will clean up the housekeeping datastructures
+related to the worker and it will spawn the RedShirt thread which will try to delete the workers own
+data structures. It is a best effort attempt that doesn't guarantee to free up all the dead workers memory
+and the RedShirt could be PANICed by the kernel, which is why a short lived seperate thread is doing it.
+*/
+void CPitBoss::DoOnPeerDeath(TWorkerId aWorkerId)
+ {
+ // If worker ran a Player all its protocol pairings are now dead. We can't know whether the thread actually
+ // did run a Player as (presuming it exited cleanly) it cleaned up, but it's adequately cheap & a rare case
+ RemoveProtocolPairingsForWorker(aWorkerId);
+ }
+
+struct ESockThreadStartupInfo
+ {
+#ifdef SYMBIAN_ZERO_COPY_NETWORKING
+ RCommsBufPond iCommsBufPond;
+#else
+ CMBufManager* iMBufManager;
+#endif // SYMBIAN_ZERO_COPY_NETWORKING
+
+ TAny* iModuleArgs;
+ __CFLOG_STMT(CCFLogIf* iCFLogIf;)
+ };
+
+TInt RESockCleanupThreadFunction(TAny* aStartupInfo)
+/**
+Intermediate function which masquerades as the main thread function in order to
+perform some specific actions for the new thread in the correct context before
+calling the new thread's actual main thread function.
+The thread must be resumed after being created or the startup info structure
+cannot be deleted by the thread and will be leaked
+@param aStartupInfo structure containing pointers to MBufMger and CFlog.
+@see RCFThread::ThreadStartupInfo
+@internalComponent
+*/
+ {
+ ESockThreadStartupInfo* startInfo = reinterpret_cast<ESockThreadStartupInfo*>(aStartupInfo);
+#ifdef SYMBIAN_ZERO_COPY_NETWORKING
+ TCommsBufPondTLSOp tls(startInfo->iCommsBufPond);
+ tls.Set();
+#else
+ startInfo->iMBufManager->SetContext();
+#endif // SYMBIAN_ZERO_COPY_NETWORKING
+
+
+ __CFLOG_STMT( startInfo->iCFLogIf->SetContext(); )
+ __CFLOG_OPEN;
+
+ TInt result = CCommonWorkerThread::PostMortemCleanupThreadEntry(startInfo->iModuleArgs);
+
+ __CFLOG_CLOSE;
+ delete startInfo;
+
+ return result;
+ };
+
+TInt CPitBoss::DoCreateRedShirt(RThread& aRedShirt, CommsFW::TWorkerId aWorkerId, Den::CCommonWorkerThread& aDeadWorker)
+ {
+ // Get the heap to assign to the red shirt thread and switch to it so we
+ // can allocate the thread startup info structure.
+ RAllocator* heap = WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iHeap;
+ RHeap* prevHeap = User::SwitchHeap(heap);
+
+ // We must not pass the thread a structure allocated on the stack because it
+ // will go out of scope before the caller calls RThread::Resume so we create
+ // it dynamically in the thread's heap.
+ // The thread is responsible for deleting the structure when it no longer
+ // needs it. For this reason, if the thread is successfully created the
+ // caller MUST resume the thread and allow it to run or else it will be
+ // leaked.
+ ESockThreadStartupInfo* startupInfo = new ESockThreadStartupInfo;
+ User::SwitchHeap(prevHeap);
+
+ TInt err = KErrNone;
+
+ if( startupInfo )
+ {
+ startupInfo->iModuleArgs = &aDeadWorker;
+#ifdef SYMBIAN_ZERO_COPY_NETWORKING
+ startupInfo->iCommsBufPond = TCommsBufPondTLSOp::Get();
+ if(startupInfo->iCommsBufPond.IsNull())
+ {
+ err = KErrNotFound;
+ }
+#else
+ startupInfo->iMBufManager = CMBufManager::Context();
+ if(startupInfo->iMBufManager == NULL)
+ {
+ err = KErrNotFound;
+ }
+#endif // SYMBIAN_ZERO_COPY_NETWORKING
+
+ // Check to make sure the logger is available.
+ #ifdef __CFLOG_ACTIVE
+ else
+ {
+ __CFLOG_STMT(startupInfo->iCFLogIf = CCFLogIf::Context());
+ if(!startupInfo->iCFLogIf)
+ {
+ RDebug::Print( _L( "RCFThread::Create - the log interface was not found. This normally means that the logging version of commsfw.dll has been mixed with a stub version of cflog.dll. See CommsDebugUtility How-To Document FAQ section for details on enabling logging in a release build." ));
+
+ err = KErrNotFound;
+ }
+ }
+ #endif
+
+ if(err == KErrNone)
+ {
+ err = aRedShirt.Create(KNullDesC, RESockCleanupThreadFunction, 8192, static_cast<RHeap*>(heap), startupInfo);
+ }
+ // If any error occured, delete the startup info structure.
+ if(err != KErrNone)
+ {
+ prevHeap = User::SwitchHeap(heap);
+ delete startupInfo;
+ User::SwitchHeap(prevHeap);
+ }
+ }
+ else
+ {
+ err = KErrNoMemory;
+ CleanupStack::Pop(startupInfo);
+ }
+
+ return err;
+ }
+
+/**
+Converts pit boss's protocol index to the local index
+The pit boss maintains a global list of protocols while each worker thread
+maintains its own list. Obviously the local list is shorter than the global list
+This function takes the Pitboss list index and comes back with one that is
+applicable to the local list
+@param aPitBossIndex the index to the pit boss's protocol list NB starts at 1
+@returns the index to the worker thread's list of protocols, -1 if not found
+*/
+TInt CPitBoss::GetLocalProtocolIndex(TInt aPitBossIndex) const
+ {
+ __ASSERT_DEBUG(aPitBossIndex > 0, User::Panic(KSpecAssert_ESockSSocks_rls, 16));
+ TInt workers[TWorkerThreadPublicInfo::EMaxWorkerThreadId];
+ Mem::FillZ(workers,sizeof(workers));
+
+ TInt lastBox = 0;
+ TProtocolPairing* pair = iProtocolPairHead;
+
+ TInt i = 0;
+ while(i < aPitBossIndex)
+ {
+ __ASSERT_DEBUG(pair, User::Panic(KSpecAssert_ESockSSocks_rls, 17));
+ if(pair->iSockType < KReservedSockTypesBase)
+ {
+ lastBox = pair->iWorkerId - 1;
+ __ASSERT_DEBUG(lastBox < TWorkerThreadPublicInfo::EMaxWorkerThreadId, User::Panic(KSpecAssert_ESockSSocks_rls, 18));
+ ++(workers[lastBox]);
+ ++i;
+ }
+ pair = pair->iNextPair;
+ }
+
+ TInt ret = workers[lastBox];
+ return ret > 0 ? ret : -1;
+ }
+
+void CPitBoss::RequestLoadTierMapping()
+ {
+ if(iLoadTierMappingPhase == EStart)
+ {
+ if(ModuleConfigurationComplete())
+ {
+ SendLoadTierMappingRequest();
+ }
+ else
+ {
+ iLoadTierMappingPhase = EDealerRequest;
+ }
+ }
+ }
+
+void CPitBoss::SendLoadTierMappingRequest()
+ {
+ TWorkerId worker;
+ if(GetWorkerForPlayerRole(KPlayerRoleTierResolver, worker))
+ {
+ TWorkerLoadTierMappings msg;
+ WorkerThread().PostMessage(worker, msg);
+ iLoadTierMappingPhase = EResolverRequested;
+ }
+ else
+ {
+ LOG(ESockLog::Printf(_L8("CPitBoss::SendLoadTierMappingRequest() *** NO TIER RESOLVER CONFIGURED *** ")));
+ __ASSERT_DEBUG(0, Panic(EMisconfigured)); // configuration is so broken that leaving user in ignorance is probably unhelpful
+ TRAP_IGNORE(OnTierMappingLoadedL(NULL, TWorkerThreadPublicInfo::ENullWorkerId)); // without the resolver's help all we can do is fail the tier requests
+ }
+ }
+
+void CPitBoss::PopulateAndAddProtocolPairListL(TProtocolName& tierDesc, RTierThreadMap* map)
+ {
+ TProtocolPairingOwner pairList;
+ CleanupReleasePushL(pairList);
+
+ for(TInt i = map->Count() - 1; i >=0; --i)
+ {
+ const TTierMapEntry& entry = (*map)[i];
+
+#ifdef _DEBUG
+ tierDesc.Format(_L("#!#! Tier %08x"), entry.iUid); // make protocol pairing record self-descriptive for debugging
+#endif
+ AddTierPairingToListL(entry.iUid, tierDesc, entry.iWorker, pairList);
+ }
+ IncorporateProtocolListL(pairList);
+
+ CleanupStack::Pop(&pairList);
+ }
+
+void CPitBoss::OnTierMappingLoadedL(const TWorkerTierMappingsLoaded* aMappingMsg, TWorkerId aSenderId)
+ {
+ __ASSERT_DEBUG(iLoadTierMappingPhase == EResolverRequested, User::Panic(KSpecAssert_ESockSSocks_rls, 19));
+ TProtocolName tierDesc;
+
+ LOG(TInt numAdded = (aMappingMsg && aMappingMsg->TierMap())? aMappingMsg->TierMap()->Count(): 0);
+ if (aMappingMsg && aMappingMsg->TierMap())
+ {
+ RTierThreadMap* map = const_cast<RTierThreadMap*>(aMappingMsg->TierMap());
+
+ TRAPD(err, PopulateAndAddProtocolPairListL(tierDesc, map));
+
+ // THeapSwitcher is not leave-safe and must be destroyed by going out of scope only.
+ // Our leave implementation does not guarantee that stack objects will be destroyed
+ // during a leave and although the current ARM implementation does do this because it
+ // uses the C++ exception handling mechanism internally, x86gcc does not support this.
+ {
+ THeapSwitcher switcher(*this, aSenderId);
+
+ map->Close();
+ delete map;
+ }
+
+ if (err)
+ {
+ User::Leave(err);
+ }
+ }
+
+ iLoadTierMappingPhase = EComplete;
+
+ LOG(ESockLog::Printf(_L8("CPitBoss::OnTierMappingLoadedL() - %d tier entries added"), numAdded));
+ // And tell all of the workers that tier mappings are ready for digestion
+ BroadcastConfigurationComplete(ETierMapping);
+ }
+