--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/accessoryservices/remotecontrolfw/server/src/server.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,3470 @@
+// Copyright (c) 2004-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:
+// Remote Control server implementation.
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include <remcon/remcontargetselectorplugin.h>
+#include <remcon/remcontargetselectorplugininterface.h>
+#include <remcon/remconbearerinterface.h>
+#include <remcon/remconbearerbulkinterface.h>
+#include "server.h"
+#include "session.h"
+#include "serversecuritypolicy.h"
+#include "utils.h"
+#include "bearermanager.h"
+#include "messagequeue.h"
+#include "convertermanager.h"
+#include "remconmessage.h"
+#include "connections.h"
+#include "connectionhistory.h"
+#include "messagerecipients.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCON_SERVER);
+#endif
+
+PANICCATEGORY("server");
+
+#ifdef __FLOG_ACTIVE
+#define LOGSESSIONS LogSessions()
+#define LOGREMOTES LogRemotes()
+#define LOGCONNECTIONHISTORYANDINTEREST LogConnectionHistoryAndInterest()
+#define LOGOUTGOINGCMDPENDINGTSP LogOutgoingCmdPendingTsp()
+#define LOGOUTGOINGNOTIFYCMDPENDINGTSP LogOutgoingNotifyCmdPendingTsp()
+#define LOGOUTGOINGRSPPENDINGTSP LogOutgoingRspPendingTsp()
+#define LOGOUTGOINGPENDINGSEND LogOutgoingPendingSend()
+#define LOGOUTGOINGSENT LogOutgoingSent()
+#define LOGINCOMINGCMDPENDINGADDRESS LogIncomingCmdPendingAddress()
+#define LOGINCOMINGNOTIFYCMDPENDINGADDRESS LogIncomingNotifyCmdPendingAddress()
+#define LOGINCOMINGNOTIFYCMDPENDINGREADDRESS LogIncomingNotifyCmdPendingReAddress()
+#define LOGINCOMINGPENDINGDELIVERY LogIncomingPendingDelivery()
+#define LOGINCOMINGDELIVERED LogIncomingDelivered()
+#else
+#define LOGSESSIONS
+#define LOGREMOTES
+#define LOGCONNECTIONHISTORYANDINTEREST
+#define LOGOUTGOINGCMDPENDINGTSP
+#define LOGOUTGOINGNOTIFYCMDPENDINGTSP
+#define LOGOUTGOINGRSPPENDINGTSP
+#define LOGOUTGOINGPENDINGSEND
+#define LOGOUTGOINGSENT
+#define LOGINCOMINGCMDPENDINGADDRESS
+#define LOGINCOMINGNOTIFYCMDPENDINGADDRESS
+#define LOGINCOMINGNOTIFYCMDPENDINGREADDRESS
+#define LOGINCOMINGPENDINGDELIVERY
+#define LOGINCOMINGDELIVERED
+#endif // __FLOG_ACTIVE
+
+TInt BulkMain(TAny* aParam);
+
+CRemConServer* CRemConServer::NewLC()
+ {
+ LOG_STATIC_FUNC;
+ CRemConServer* self = new(ELeave) CRemConServer();
+ CleanupStack::PushL(self);
+ // StartL is where the kernel checks that there isn't already an instance
+ // of the same server running, so do it before ConstructL.
+ self->StartL(KRemConServerName);
+ self->ConstructL();
+ return self;
+ }
+
+CRemConServer::~CRemConServer()
+ {
+ LOG_FUNC;
+
+ delete iBearerManager;
+ delete iShutdownTimer;
+
+ // There should be no watcher as there should be no bulk thread running
+ ASSERT_DEBUG(!iBulkThreadWatcher);
+
+ iSessionsLock.Wait();
+ iSessions.Close();
+ iSessionsLock.Close();
+
+ // Destroy TSP before iIncomingPendingAddress in case the TSP is
+ // addressing a message on it at the time.
+ // The TSP should not be handling outgoing commands or responses as all the sessions
+ // have gone, and they clean up their outgoing messages when they close.
+ ASSERT_DEBUG(!iTspHandlingOutgoingCommand);
+ ASSERT_DEBUG(!iTspHandlingOutgoingResponse);
+ ASSERT_DEBUG(!iTspHandlingOutgoingNotifyCommand);
+ // We can't assert anything about iTspAddressingIncomingCommand- it isn't
+ // interesting.
+ delete iTsp;
+
+ delete iOutgoingCmdPendingTsp;
+ delete iOutgoingNotifyCmdPendingTsp;
+ delete iOutgoingRspPendingTsp;
+ delete iOutgoingRspPendingSend;
+ delete iOutgoingPendingSend;
+ delete iOutgoingSent;
+ delete iIncomingCmdPendingAddress;
+ delete iIncomingNotifyCmdPendingAddress;
+ delete iIncomingNotifyCmdPendingReAddress;
+ delete iIncomingPendingDelivery;
+ delete iIncomingDelivered;
+
+ delete iMessageRecipientsList;
+
+ iTspConnections.Reset();
+ iTspIncomingCmdClients.Reset();
+ iTspIncomingNotifyCmdClients.Reset();
+
+ delete iConverterManager;
+
+ // Clean up the connection information (must be done after the bearer
+ // manager is destroyed).
+ LOGREMOTES;
+ LOGCONNECTIONHISTORYANDINTEREST;
+ delete iConnectionHistory;
+
+ iSession2ConnHistory.Close();
+
+ // This is the odd ECOM code for cleaning our session. NB This must be
+ // done AFTER destroying all the other things in this thread which use
+ // ECOM!
+ if ( iEcom )
+ {
+ iEcom->Close();
+ }
+ REComSession::FinalClose();
+ }
+
+CRemConServer::CRemConServer()
+ : CPolicyServer(CActive::EPriorityHigh, KRemConServerPolicy),
+ iTspConnections(_FOFF(TRemConAddress, iLink)),
+ iTspIncomingCmdClients(_FOFF(TClientInfo, iLink)),
+ iTspIncomingNotifyCmdClients(_FOFF(TClientInfo, iLink2)),
+ iTspIf4Stub(*this)
+ {
+ LOG_FUNC;
+ // NB CRemConServer uses CActive::EPriorityHigh to help it get priority
+ // over other AOs in its thread. (The fact that it's added to the AS
+ // before anything else helps too.) This is so that client requests are
+ // not blocked by other AOs in the thread being very busy. This relies of
+ // course on the cooperation of the other AOs running in RemCon's thread
+ // over which we have no control (e.g. those in externally-supplied
+ // bearers or the Target Selector Plugin). In Symbian OS, it's the best we
+ // can do.
+
+ // This is needed for BC reasons, as the TUint32 padding in TClientInfo is now replaced with
+ // a second TSglQueLink. Therefore in order to maintain BC we need these two classes
+ // to be the same size.
+ __ASSERT_COMPILE(sizeof(TUint32) == sizeof(TSglQueLink));
+ }
+
+void CRemConServer::ConstructL()
+ {
+ LOG_FUNC;
+ // Open ECOM session.
+ iEcom = &(REComSession::OpenL());
+ LEAVEIFERRORL(iSessionsLock.CreateLocal());
+
+ iShutdownTimer = CPeriodic::NewL(CActive::EPriorityStandard);
+
+ // Make the connection history holder before creating the bearer manager,
+ // as some bearers might call the bearer manager back synchronously with a
+ // new connection, and we need iConnectionHistory to be able to handle
+ // that.
+ iConnectionHistory = CConnectionHistory::NewL();
+
+ // Make the queues before making the bearer manager because otherwise a
+ // 'connection up' which is indicated synchronously with
+ // CBearerManager::NewL will blow us up (we address some of the queues
+ // when that happens).
+ iOutgoingCmdPendingTsp = CMessageQueue::NewL();
+ iOutgoingNotifyCmdPendingTsp = CMessageQueue::NewL();
+ iOutgoingRspPendingTsp = CMessageQueue::NewL();
+ iOutgoingRspPendingSend = CMessageQueue::NewL();
+ iOutgoingPendingSend = CMessageQueue::NewL();
+ iOutgoingSent = CMessageQueue::NewL();
+ iIncomingCmdPendingAddress = CMessageQueue::NewL();
+ iIncomingNotifyCmdPendingAddress = CMessageQueue::NewL();
+ iIncomingNotifyCmdPendingReAddress = CMessageQueue::NewL();
+ iIncomingPendingDelivery = CMessageQueue::NewL();
+ iIncomingDelivered = CMessageQueue::NewL();
+
+ iMessageRecipientsList = CMessageRecipientsList::NewL();
+
+ // Make bearer manager. This makes the bearers, and connects them up to
+ // the event handler.
+ iBearerManager = CBearerManager::NewL(*this);
+
+ // We must load the bearers before the TSP as the TSP loader checks
+ // whether there are any bearers with interface V2
+ ASSERT_ALWAYS(!iTspIf);
+
+ iConverterManager = CConverterManager::NewL();
+
+ LoadTspL();
+
+ LOGREMOTES;
+ LOGCONNECTIONHISTORYANDINTEREST;
+ }
+
+CSession2* CRemConServer::NewSessionL(const TVersion& aVersion,
+ const RMessage2& aMessage) const
+ {
+ LOG(KNullDesC8);
+ LOG_FUNC;
+ LOG3(_L("\taVersion = (%d,%d,%d)"), aVersion.iMajor, aVersion.iMinor, aVersion.iBuild);
+
+ // Version number check...
+ TVersion v(KRemConSrvMajorVersionNumber,
+ KRemConSrvMinorVersionNumber,
+ KRemConSrvBuildNumber);
+
+ if ( !User::QueryVersionSupported(v, aVersion) )
+ {
+ LEAVEIFERRORL(KErrNotSupported);
+ }
+
+ CRemConServer* ncThis = const_cast<CRemConServer*>(this);
+
+ CRemConSession* sess = NULL;
+ ASSERT_DEBUG(iBearerManager);
+ TRAPD(err, sess = CRemConSession::NewL(*ncThis,
+ *iBearerManager,
+ aMessage,
+ (ncThis->iSessionId)++)
+ );
+ if ( err != KErrNone )
+ {
+ // Session creation might have failed- if it has we need to check if
+ // we need to shut down again.
+ const_cast<CRemConServer*>(this)->StartShutdownTimerIfNoSessionsOrBulkThread();
+ LEAVEIFERRORL(err);
+ }
+
+ LOG1(_L("\tsess = 0x%08x"), sess);
+ return sess;
+ }
+
+void CRemConServer::StartShutdownTimerIfNoSessionsOrBulkThread()
+ {
+ LOG_FUNC;
+ iSessionsLock.Wait();
+ if ( iSessions.Count() == 0 && !iBulkThreadOpen)
+ {
+ LOG(_L("\tno remaining sessions- starting shutdown timer"));
+ // Should have been created during our construction.
+ ASSERT_DEBUG(iShutdownTimer);
+ // Start the shutdown timer. It's actually a CPeriodic- the first
+ // event will be in KShutdownDelay microseconds' time.
+ // NB The shutdown timer might already be active, in the following
+ // case: this function is being called by NewSessionL because there
+ // was a failure creating a new session, BUT this function had already
+ // been called by the session's destructor (i.e. the failure was in
+ // the session's ConstructL, NOT its new(ELeave)). To protect against
+ // KERN-EXEC 15 just check for if the timer is already active.
+ if ( !iShutdownTimer->IsActive() )
+ {
+ iShutdownTimer->Start(KShutdownDelay,
+ // Delay of subsequent firings (will not happen because we kill
+ // ourselves after the first).
+ 0,
+ TCallBack(CRemConServer::TimerFired, this)
+ );
+ }
+ else
+ {
+ LOG(_L("\tshutdown timer was already active"));
+ }
+ }
+ iSessionsLock.Signal();
+ }
+
+TInt CRemConServer::TimerFired(TAny* aThis)
+ {
+ LOG_STATIC_FUNC
+ static_cast<void>(aThis);
+
+#if defined(__FLOG_ACTIVE) || defined(_DEBUG)
+ CRemConServer* self = static_cast<CRemConServer*>(aThis);
+ // We should have sent 'this' to this callback.
+ ASSERT_DEBUG(self);
+ LOG1(_L8("\tauto shutdown- terminating the server [0x%08x]"), self);
+#endif // __FLOG_ACTIVE || _DEBUG
+
+ // Stop our Active Scheduler. This returns the flow of execution to after
+ // the CActiveScheduler::Start call in the server startup code, and
+ // terminates the server.
+ CActiveScheduler::Stop();
+
+ return KErrNone;
+ }
+
+void CRemConServer::InitialiseBulkServerThreadL()
+ {
+ LOG_FUNC
+ // Set up the configuration of the thread
+ iBulkServerThread.SetPriority(EPriorityLess);
+
+ iBulkThreadWatcher = new(ELeave) CBulkThreadWatcher(*this);
+ CleanupDeleteAndNullPushL(iBulkThreadWatcher);
+
+ // Create the communication between the servers.
+ LEAVEIFERRORL(iBulkServerMsgQueue.CreateLocal(2)); // only ever two outstanding messages
+ CleanupClosePushL(iBulkServerMsgQueue); // member variable, but closing again should be fine.
+
+ // Load the server pointer (for TClientInfo info)
+ TBulkServerMsg ctrlMsg;
+ ctrlMsg.iType = EControlServer;
+ ctrlMsg.iData = this;
+ iBulkServerMsgQueue.SendBlocking(ctrlMsg); // this should not block as there is enough room in queue.
+
+ // Load the bearer manager pointer
+ TBulkServerMsg manMsg;
+ manMsg.iType = EBearerManager;
+ manMsg.iData = iBearerManager;
+ iBulkServerMsgQueue.SendBlocking(manMsg); // this should not block as there is enough room in queue.
+
+ TRequestStatus stat;
+ iBulkServerThread.Rendezvous(stat);
+
+ // Mark bulk server thread ready to run
+ iBulkServerThread.Resume();
+ User::WaitForRequest(stat); // wait for start or death
+
+ // we can't use the 'exit reason' if the server panicked as this
+ // is the panic 'reason' and may be '0' which cannot be distinguished
+ // from KErrNone
+ TInt err = (iBulkServerThread.ExitType() == EExitPanic) ? KErrServerTerminated : stat.Int();
+ LEAVEIFERRORL(err);
+
+ // Everything appears to be running...so watch the thread until it dies...
+ iBulkThreadWatcher->StartL();
+
+ CleanupStack::Pop(2, &iBulkThreadWatcher); // iBulkServerMsgQueue, iBulkThreadWatcher
+ }
+
+
+TInt CRemConServer::BulkServerRequired()
+ {
+ LOG_FUNC
+ // If the bulk server is required then try to create it
+ TThreadFunction bulkServerThreadFunction(BulkMain);
+ _LIT(KBulkServerThreadName, "RemConBulkServerThread");
+ const TInt KMaxBulkServerThreadHeapSize = 0x100000;
+
+ TInt err = KErrNone;
+ if(!iBulkThreadOpen)
+ {
+ err = iBulkServerThread.Create(KBulkServerThreadName, bulkServerThreadFunction, KDefaultStackSize, KMinHeapSize, KMaxBulkServerThreadHeapSize, &iBulkServerMsgQueue, EOwnerThread);
+ if(err == KErrNone)
+ {
+ TRAP(err, InitialiseBulkServerThreadL());
+ if(err == KErrNone)
+ {
+ iBulkThreadOpen = ETrue;
+ }
+ }
+ }
+ return err;
+ }
+
+TInt CRemConServer::ClientOpened(CRemConSession& aSession)
+ {
+ LOG_FUNC;
+ LOG1(_L("\t&aSession = 0x%08x"), &aSession);
+ LOGSESSIONS;
+
+ // Register the session by appending it to our array, and also making an
+ // item for it in the record of which points in the connection history
+ // sessions are interested in.
+ iSessionsLock.Wait();
+ TInt ret = iSessions.Append(&aSession);
+ if ( ret == KErrNone )
+ {
+ TSessionPointerToConnectionHistory item;
+ item.iSessionId = aSession.Id();
+ item.iIndex = 0; // there is always at least one item in the connection history
+ ret = iSession2ConnHistory.Append(item);
+ if ( ret != KErrNone )
+ {
+ iSessions.Remove(iSessions.Count() - 1);
+ }
+ }
+ iSessionsLock.Signal();
+
+ if ( ret == KErrNone )
+ {
+ // Should have been created during our construction.
+ ASSERT_DEBUG(iShutdownTimer);
+ iShutdownTimer->Cancel();
+ }
+
+ LOGSESSIONS;
+ LOG1(_L("\tret = %d"), ret);
+ return ret;
+ }
+
+// this function is called by the session when the session type is set
+void CRemConServer::ClientTypeSet(CRemConSession& aSession)
+ {
+ LOG_FUNC;
+ LOG1(_L("\t&aSession = 0x%08x"), &aSession);
+ LOGSESSIONS;
+
+ /* When a client (session) has its type set (controller or target) then
+ it will still have a bearer uid of NullUid. In this case we want to
+ update any bearers which now have a controller or target count moving
+ (from 0) to 1. */
+
+ /* tell the bearer manager that someones set a client type
+ The bearer manager maintains controller and target counts for all bearers
+ and will tell bearers when they need to know things have changed */
+ ASSERT_DEBUG(iBearerManager);
+ iBearerManager->ClientTypeSet(aSession.Type() == ERemConClientTypeController);
+
+ LOGSESSIONS;
+ }
+
+// this function is called by the session when the client has registered its features
+void CRemConServer::TargetClientAvailable(CRemConSession& aSession)
+ {
+ LOG_FUNC;
+ LOG1(_L("\t&aSession = 0x%08x"), &aSession);
+ LOGSESSIONS;
+
+ ASSERT_DEBUG(iBearerManager);
+ iBearerManager->TargetClientAvailable(aSession.Id(), aSession.PlayerType(), aSession.PlayerSubType(), aSession.Name());
+
+ LOGSESSIONS;
+ }
+
+// this function is called by the session when the client has registered its features
+void CRemConServer::ControllerClientAvailable()
+ {
+ LOG_FUNC;
+ LOGSESSIONS;
+
+ ASSERT_DEBUG(iBearerManager);
+ iBearerManager->ControllerClientAvailable();
+
+ LOGSESSIONS;
+ }
+
+// this function is called by the session when it goes connection oriented
+void CRemConServer::ClientGoConnectionOriented(CRemConSession& aSession, TUid aUid)
+ {
+ LOG_FUNC;
+ LOG1(_L("\t&aSession = 0x%08x"), &aSession);
+ LOGSESSIONS;
+
+ (void)&aSession; // get rid of unused warning.
+
+ ASSERT_DEBUG(aSession.Type() == ERemConClientTypeController);
+
+ /* now tell the bearer manager that someones went connection oriented
+ The bearer manager maintains controller and target counts for all bearers
+ and will tell bearers when they need to know things have changed */
+ ASSERT_DEBUG(iBearerManager);
+ iBearerManager->ClientConnectionOriented(aUid);
+
+ LOGSESSIONS;
+ }
+
+// this is called by the session when the client goes connectionless
+void CRemConServer::ClientGoConnectionless(CRemConSession& aSession, TUid aUid)
+ {
+ LOG_FUNC;
+ LOG1(_L("\t&aSession = 0x%08x"), &aSession);
+ LOGSESSIONS;
+
+ (void)&aSession; // get rid of unused warning.
+
+ ASSERT_DEBUG(aSession.Type() == ERemConClientTypeController);
+ /* now tell the bearer manager that someones went connection less
+ The bearer manager maintains controller and target counts for all bearers
+ and will tell bearers when they need to know things have changed */
+ ASSERT_DEBUG(iBearerManager);
+ iBearerManager->ClientConnectionless(aUid);
+
+ LOGSESSIONS;
+ }
+
+// called by session when session is closed.
+void CRemConServer::ClientClosed(CRemConSession& aSession, TUid aUid)
+ {
+ LOG_FUNC;
+ LOG1(_L("\t&aSession = 0x%08x"), &aSession);
+ LOGSESSIONS;
+
+ iSessionsLock.Wait();
+ // Find this session in the array and remove it (if it's there).
+ const TUint sessCount = iSessions.Count();
+ for ( TUint ii = 0 ; ii < sessCount ; ++ii )
+ {
+ if ( iSessions[ii] == &aSession )
+ {
+ // We've found the session in our array.
+
+ // 1. Remove the session from our array.
+ iSessions.Remove(ii);
+
+ // 2. Tell the bearers about the session going away, if it was the
+ // last controller or last target.
+ // If the session hasn't already set its type, then it doesn't
+ // count (we won't have told the bearers about it to begin with).
+ // The bearer manager maintains controller and target counts for all bearers
+ // and will tell bearers when they need to know things have changed */
+ if ( aSession.Type() != ERemConClientTypeUndefined )
+ {
+ ASSERT_DEBUG(iBearerManager);
+ iBearerManager->ClientClosed(aSession.Type() == ERemConClientTypeController, aUid, aSession.Id());
+ }
+
+ // 3. Remove queued messages belonging to this session that:
+ // (a) are outgoing, awaiting access to the TSP
+ // (OutgoingPendingTsp, OutgoingNotifyPendingTsp),
+ // (b) are outgoing, awaiting a bearer connection
+ // (OutgoingPendingSend),
+ // (c) have been sent (OutgoingSent)
+ // (d) are pending delivery to this session
+ // (IncomingPendingDelivery)
+ // (e) have been delivered to this session and are awaiting
+ // responses (IncomingDelivered).
+ TSglQueIter<CRemConMessage>& cmdIter = OutgoingCmdPendingTsp().SetToFirst();
+ CRemConMessage* msg;
+ TBool first = ETrue;
+ while ( ( msg = cmdIter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSession.Id() )
+ {
+ // If the message is currently being worked on by the
+ // TSP, cancel the TSP before destroying it.
+ if ( iTspHandlingOutgoingCommand && first )
+ {
+ ASSERT_DEBUG(iTspIf);
+ iTspIf->CancelOutgoingCommand();
+ iTspHandlingOutgoingCommand = EFalse;
+ }
+ OutgoingCmdPendingTsp().RemoveAndDestroy(*msg);
+ }
+ first = EFalse;
+ }
+
+ cmdIter = OutgoingNotifyCmdPendingTsp().SetToFirst();
+ first = ETrue;
+ while ( ( msg = cmdIter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSession.Id() )
+ {
+ // If the message is currently being worked on by the
+ // TSP, cancel the TSP before destroying it.
+ if ( iTspHandlingOutgoingNotifyCommand && first )
+ {
+ ASSERT_DEBUG(iTspIf3);
+ iTspIf3->CancelOutgoingNotifyCommand();
+ iTspHandlingOutgoingNotifyCommand = EFalse;
+ }
+ OutgoingNotifyCmdPendingTsp().RemoveAndDestroy(*msg);
+ }
+ first = EFalse;
+ }
+
+ if ( aSession.Type() == ERemConClientTypeTarget )
+ {
+ // Remove the clients from the DeliveredMessageClients list
+ ASSERT_DEBUG(iMessageRecipientsList);
+ TSglQueIter<CMessageRecipients>& messageRecipientsIter = iMessageRecipientsList->Iter();
+
+ messageRecipientsIter.SetToFirst();
+ CMessageRecipients* message;
+ while ((message = messageRecipientsIter++) != NULL)
+ {
+ message->RemoveAndDestroyClient(aSession.ClientInfo());
+ if (message->Clients().IsEmpty())
+ {
+ iMessageRecipientsList->Messages().Remove(*message);
+ // Inform bearer that it won't be getting a response
+
+ // First we need to find the command - it could be in
+ // OutgoingRspPendingTsp, IncomingDelivered or IncomingPendingDelivery
+
+ CRemConMessage* msg;
+
+ msg = OutgoingRspPendingTsp().Message(message->TransactionId());
+
+ if (!msg)
+ {
+ msg = IncomingDelivered().Message(message->TransactionId());
+ }
+ if (!msg)
+ {
+ msg = IncomingPendingDelivery().Message(message->TransactionId());
+ }
+
+ if(msg)
+ {
+ // As this is the last message with this transaction ID, it should have this session ID
+ ASSERT_DEBUG(msg->SessionId() == aSession.Id());
+
+ // Now we've found the message, we can pass the reject to the bearer
+ // Send reject to the bearer
+ SendReject(msg->Addr(), msg->InterfaceUid(), msg->OperationId(), msg->TransactionId());
+ }
+ delete message;
+ }
+ TSglQueIter<CRemConMessage>& rspIter = OutgoingRspPendingTsp().SetToFirst();
+
+ CRemConMessage* msg;
+ TBool first = ETrue;
+ while ( ( msg = rspIter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSession.Id() )
+ {
+ // If the message is currently being worked on by the
+ // TSP, cancel the TSP before destroying it.
+ if (iTspIf2 && iTspHandlingOutgoingResponse && first )
+ {
+ iTspIf2->CancelOutgoingResponse();
+ iTspHandlingOutgoingResponse = EFalse;
+ }
+ OutgoingRspPendingTsp().RemoveAndDestroy(*msg);
+ }
+ first = EFalse;
+ }
+
+ }
+ }
+
+ TSglQueIter<CRemConMessage>& sendIter = OutgoingPendingSend().SetToFirst();
+ while ( ( msg = sendIter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSession.Id() )
+ {
+ if (msg->MsgType() == ERemConResponse)
+ {
+ SendReject(msg->Addr(), msg->InterfaceUid(), msg->OperationId(), msg->TransactionId());
+ }
+ OutgoingPendingSend().RemoveAndDestroy(*msg);
+ }
+ }
+
+ OutgoingSent().RemoveAndDestroy(aSession.Id());
+
+ TSglQueIter<CRemConMessage>& pendingDeliveryIter = IncomingPendingDelivery().SetToFirst();
+ while ( ( msg = pendingDeliveryIter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSession.Id() )
+ {
+ if (msg->MsgType() == ERemConNotifyCommand)
+ {
+ SendReject(msg->Addr(), msg->InterfaceUid(), msg->OperationId(), msg->TransactionId());
+ }
+ IncomingPendingDelivery().RemoveAndDestroy(*msg);
+ }
+ }
+
+ TSglQueIter<CRemConMessage>& deliveredIter = IncomingDelivered().SetToFirst();
+ while ( ( msg = deliveredIter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSession.Id() )
+ {
+ if (msg->MsgType() == ERemConNotifyCommand)
+ {
+ SendReject(msg->Addr(), msg->InterfaceUid(), msg->OperationId(), msg->TransactionId());
+ }
+ IncomingDelivered().RemoveAndDestroy(*msg);
+ }
+ }
+
+ break;
+ } // End found session in our array
+ }
+ iSessionsLock.Signal();
+
+ // Also remove its record from the connection history record.
+ const TUint count = iSession2ConnHistory.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ if ( iSession2ConnHistory[ii].iSessionId == aSession.Id() )
+ {
+ iSession2ConnHistory.Remove(ii);
+ UpdateConnectionHistoryAndPointers();
+ break;
+ }
+ }
+
+ StartShutdownTimerIfNoSessionsOrBulkThread();
+
+ LOGSESSIONS;
+ }
+
+TBool CRemConServer::TargetClientWithSameProcessId(TProcessId aProcId) const
+ {
+ LOG_FUNC;
+ LOG1(_L("\taProcId = %d"), static_cast<TUint>(aProcId));
+
+ TBool ret = EFalse;
+
+ const CRemConSession* const sess = TargetSession(aProcId);
+ if ( sess )
+ {
+ ret = ETrue;
+ }
+
+ LOG1(_L("\tret = %d"), ret);
+ return ret;
+ }
+
+#ifdef __FLOG_ACTIVE
+void CRemConServer::LogSessions() const
+ {
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ LOG1(_L("\tNumber of sessions = %d"), count);
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const session = iSessions[ii];
+ ASSERT_DEBUG(session);
+ LOG5(_L("\t\tsession %d [0x%08x], Id = %d, Type = %d, ProcessId = %d"),
+ ii,
+ session,
+ session->Id(),
+ session->Type(),
+ static_cast<TUint>(session->ClientInfo().ProcessId())
+ );
+ }
+ iSessionsLock.Signal();
+ }
+
+void CRemConServer::LogRemotes() const
+ {
+ // Called from dtor- this may not have been made yet.
+ if ( iConnectionHistory )
+ {
+ CConnections& conns = iConnectionHistory->Last();
+ conns.LogConnections();
+ }
+ }
+
+void CRemConServer::LogConnectionHistoryAndInterest() const
+ {
+ LOG(_L("Logging connection history and interest in it"));
+ if ( iConnectionHistory )
+ {
+ iConnectionHistory->LogConnectionHistory();
+
+ const TUint count = iSession2ConnHistory.Count();
+ LOG1(_L("\tNumber of sessions = %d"), count);
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ const TSessionPointerToConnectionHistory& interest = iSession2ConnHistory[ii];
+ LOG3(_L("\t\tinterest %d, iSessionId = %d, iIndex = %d"),
+ ii,
+ interest.iSessionId,
+ interest.iIndex
+ );
+ }
+ }
+ }
+#endif // __FLOG_ACTIVE
+
+void CRemConServer::MrctspoDoOutgoingNotifyCommandAddressed(TRemConAddress* aConnection, TInt aError)
+ {
+ LOG(KNullDesC8());
+ LOG_FUNC;
+ LOG1(_L("\taError = %d"), aError);
+ LOGOUTGOINGNOTIFYCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+
+ ASSERT_DEBUG(iTspHandlingOutgoingNotifyCommand);
+ iTspHandlingOutgoingNotifyCommand = EFalse;
+
+ CRemConMessage& msg = OutgoingNotifyCmdPendingTsp().First();
+ ASSERT_DEBUG(msg.Addr().IsNull());
+ CRemConSession* const sess = Session(msg.SessionId());
+ // Session closure removes messages from the outgoing queue and cancels
+ // the TSP request if relevant. If sess is NULL here, then this processing
+ // has gone wrong.
+ ASSERT_DEBUG(sess);
+
+ sess->SendError() = KErrNone;
+ if ( (aError != KErrNone) || !aConnection)
+ {
+ sess->SendError() = aError;
+ sess->CompleteSendNotify();
+ }
+ else
+ {
+ // Message addressed OK.
+ if ( aConnection != NULL )
+ {
+ TBool sync = EFalse;
+ TRAPD(err, SendCmdToRemoteL(msg, *aConnection, sync));
+ if ( err || sync )
+ {
+ sess->SendError() = err;
+ sess->CompleteSendNotify();
+ }
+
+ delete aConnection;
+ aConnection = NULL;
+ }
+ }
+
+ // We've now finished with the addressed message, so destroy it.
+ OutgoingNotifyCmdPendingTsp().RemoveAndDestroy(msg);
+
+ // Check for more notify commands to address.
+ if ( !OutgoingNotifyCmdPendingTsp().IsEmpty() )
+ {
+ LOG(_L8("\tmore outgoing notify commands awaiting TSP..."));
+ TspOutgoingNotifyCommand();
+ }
+
+ LOGOUTGOINGNOTIFYCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+ }
+
+void CRemConServer::MrctspoDoOutgoingCommandAddressed(TInt aError)
+ {
+ LOG(KNullDesC8());
+ LOG_FUNC;
+ LOG1(_L("\taError = %d"), aError);
+ LOGOUTGOINGCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+
+ ASSERT_DEBUG(iTspHandlingOutgoingCommand);
+ iTspHandlingOutgoingCommand = EFalse;
+
+ // If aError is KErrNone,
+ // Remove the addressed message from the iOutgoingPendingTsp queue.
+ // Send the command to the requested bearer(s), putting items on the
+ // iOutgoingSent queue to await responses
+ // Complete the controller client's message.
+
+ // Any error at any point during the above should roll back everything
+ // (apart from removing the original message from iOutgoingPendingTsp)
+ // and error the sending controller.
+
+ // Finally, check iOutgoingPendingTsp for more commands to give to
+ // the TSP.
+
+ // The head item, currently being dealt with, is always at index 0.
+ // NB This msg will be destroyed by the end of the function, and copies
+ // taken to add to iOutgoingSent.
+ // Note that if the client went away while the address request was
+ // outstanding, this item will still be on this queue because we protect
+ // it (see ClientClosed).
+ CRemConMessage& msg = OutgoingCmdPendingTsp().First();
+ // Check that the message isn't addressed already. If this fails, it's
+ // possible that the TSP has called OutgoingCommandAddressed in response
+ // to a PermitOutgoingCommand request.
+ ASSERT_DEBUG(msg.Addr().IsNull());
+ CRemConSession* const sess = Session(msg.SessionId());
+ // Session closure removes messages from the outgoing queue and cancels
+ // the TSP request if relevant. If sess is NULL here, then this processing
+ // has gone wrong.
+ ASSERT_DEBUG(sess);
+ // The number of remotes the command was sent to.
+ sess->NumRemotes() = 0;
+ sess->SendError() = KErrNone;
+ if ( aError != KErrNone )
+ {
+ sess->SendError() = aError;
+ sess->NumRemotesToTry() = 0;
+ }
+ else
+ {
+ // Message addressed OK.
+ // Work out how many remotes the TSP said to send to.
+ TSglQueIter<TRemConAddress> iter(iTspConnections);
+ while ( iter++ )
+ {
+ ++sess->NumRemotesToTry();
+ }
+ iter.SetToFirst();
+ // Try to connect and send a message to each specified remote.
+ TRemConAddress* conn;
+ while ( ( conn = iter++ ) != NULL )
+ {
+ LOG2(_L("\tsending message to remote [0x%08x] BearerUid = 0x%08x"),
+ conn, conn->BearerUid());
+
+ // We send to as many of the remotes as we can. We remember
+ // how many remotes got sent to successfully, and complete the
+ // client's request with either KErrNone or _one of_ the
+ // errors that were raised.
+ TBool sync = EFalse;
+ TRAPD(err, SendCmdToRemoteL(msg, *conn, sync));
+ if ( err || sync )
+ {
+ // We have finished trying to process this (copy of this)
+ // message, so we can adjust our 'remotes' counter /
+ // completion error.
+ if ( err == KErrNone )
+ {
+ ++sess->NumRemotes();
+ }
+ else
+ {
+ sess->SendError() = err;
+ }
+ --sess->NumRemotesToTry();
+ }
+ // else we didn't actually make a send attempt because conn was
+ // down. This particular message will undergo an actual
+ // (bearer-level) send attempt later on when the connection comes
+ // up. For now, however, we cannot legally complete the client's
+ // request.
+
+ iTspConnections.Remove(*conn);
+ delete conn;
+ } // End while
+ } // End if TSP addressed command OK
+ if ( sess->NumRemotesToTry() == 0 )
+ {
+ sess->CompleteSend();
+ }
+
+ // We've now finished with the addressed message, so destroy it.
+ OutgoingCmdPendingTsp().RemoveAndDestroy(msg);
+
+ // Check for more commands to address.
+ if ( !OutgoingCmdPendingTsp().IsEmpty() )
+ {
+ LOG(_L("\tmore outgoing commands awaiting TSP..."));
+ TspOutgoingCommand();
+ }
+
+ LOGOUTGOINGCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+ }
+
+void CRemConServer::MrctspoDoOutgoingCommandPermitted(TBool aIsPermitted)
+ {
+ LOG(KNullDesC8());
+ LOG_FUNC;
+ LOG1(_L("\taIsPermitted = %d"), aIsPermitted);
+ LOGOUTGOINGCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+
+ ASSERT_DEBUG(iTspHandlingOutgoingCommand);
+ iTspHandlingOutgoingCommand = EFalse;
+
+ // If aIsPermitted is EFalse, complete the sending session with
+ // KErrPermissionDenied and destroy the message. Otherwise try to send the
+ // message and complete the sending session. If it sent OK, move the
+ // message to the 'outgoing sent' queue.
+ // At the end, check the 'pending TSP' queue again.
+ // The head item, currently being dealt with, is always at index 0.
+ // Note that if the client went away while the address request was
+ // outstanding, this item will still be on this queue because we protect
+ // it (see ClientClosed).
+ CRemConMessage& msg = OutgoingCmdPendingTsp().First();
+ // Check that the message is addressed already. If this fails, it's
+ // possible that the TSP has called OutgoingCommandPermitted in response
+ // to a AddressOutgoingCommand request.
+ ASSERT_DEBUG(!msg.Addr().IsNull());
+ CRemConSession* const sess = Session(msg.SessionId());
+ // Session closure removes messages from the outgoing queue and cancels
+ // the TSP request if relevant. If sess is NULL here, then this processing
+ // has gone wrong.
+ ASSERT_DEBUG(sess);
+ TInt err = KErrPermissionDenied;
+ if ( aIsPermitted )
+ {
+ TBool sync = EFalse;
+ TRAP(err, SendCmdToRemoteL(msg, msg.Addr(), sync));
+ if ( err || sync )
+ {
+ // We made a send attempt at the bearer level. Complete the
+ // client's message according to err.
+ --sess->NumRemotesToTry();
+ sess->NumRemotes() = ( err == KErrNone ) ? 1 : 0;
+ sess->SendError() = err;
+ sess->CompleteSend();
+ }
+ // else the message is waiting until a bearer-level connection
+ // comes up. Only then can we complete the client's message.
+ }
+ else
+ {
+ // The send wasn't permitted, so complete the client's message.
+ // This was a connection-oriented send, so we know the number of
+ // remotes it was sent to is 0.
+ --sess->NumRemotesToTry();
+ sess->NumRemotes() = 0;
+ sess->SendError() = KErrPermissionDenied;
+ sess->CompleteSend();
+ }
+
+ // We've now finished with the message, so destroy it.
+ OutgoingCmdPendingTsp().RemoveAndDestroy(msg);
+
+ // Check for more commands to give to the TSP.
+ if ( !OutgoingCmdPendingTsp().IsEmpty() )
+ {
+ LOG(_L("\tmore outgoing commands awaiting TSP..."));
+ TspOutgoingCommand();
+ }
+
+ LOGOUTGOINGCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+ }
+
+void CRemConServer::MrctspoDoOutgoingNotifyCommandPermitted(TBool aIsPermitted)
+ {
+ LOG(KNullDesC8());
+ LOG_FUNC;
+ LOG1(_L("\taIsPermitted = %d"), aIsPermitted);
+ LOGOUTGOINGCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+
+ ASSERT_DEBUG(iTspHandlingOutgoingNotifyCommand);
+ iTspHandlingOutgoingNotifyCommand = EFalse;
+
+ // If aIsPermitted is EFalse, complete the sending session with
+ // KErrPermissionDenied and destroy the message. Otherwise try to send the
+ // message and complete the sending session. If it sent OK, move the
+ // message to the 'outgoing sent' queue.
+ // At the end, check the 'pending TSP' queue again.
+ // The head item, currently being dealt with, is always at index 0.
+ // Note that if the client went away while the address request was
+ // outstanding, this item will still be on this queue because we protect
+ // it (see ClientClosed).
+ CRemConMessage& msg = OutgoingNotifyCmdPendingTsp().First();
+ // Check that the message is addressed already. If this fails, it's
+ // possible that the TSP has called OutgoingCommandPermitted in response
+ // to a AddressOutgoingCommand request.
+ ASSERT_DEBUG(!msg.Addr().IsNull());
+ CRemConSession* const sess = Session(msg.SessionId());
+ // Session closure removes messages from the outgoing queue and cancels
+ // the TSP request if relevant. If sess is NULL here, then this processing
+ // has gone wrong.
+ ASSERT_DEBUG(sess);
+ TInt err = KErrPermissionDenied;
+ if ( aIsPermitted )
+ {
+ TBool sync = EFalse;
+ TRAP(err, SendCmdToRemoteL(msg, msg.Addr(), sync));
+ if ( err || sync )
+ {
+ sess->SendError() = err;
+ sess->CompleteSendNotify();
+ }
+ // else the message is waiting until a bearer-level connection
+ // comes up. Only then can we complete the client's message.
+ }
+ else
+ {
+ sess->SendError() = KErrPermissionDenied;
+ sess->CompleteSendNotify();
+ }
+
+ // We've now finished with the message, so destroy it.
+ OutgoingNotifyCmdPendingTsp().RemoveAndDestroy(msg);
+
+ // Check for more commands to give to the TSP.
+ if ( !OutgoingNotifyCmdPendingTsp().IsEmpty() )
+ {
+ LOG(_L("\tmore outgoing commands awaiting TSP..."));
+ TspOutgoingNotifyCommand();
+ }
+
+ LOGOUTGOINGCMDPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+ }
+
+void CRemConServer::MrctspoDoOutgoingResponsePermitted(TBool aIsPermitted)
+ {
+ LOG_FUNC;
+ LOGOUTGOINGRSPPENDINGTSP;
+ ASSERT_DEBUG(iTspHandlingOutgoingResponse);
+ iTspHandlingOutgoingResponse = EFalse;
+ ASSERT_DEBUG(iOutgoingRspPendingTsp);
+ CRemConMessage& msg = iOutgoingRspPendingTsp->First();
+
+ iOutgoingRspPendingTsp->Remove(msg);
+
+ CRemConSession* const sess = Session(msg.SessionId());
+ // Session closure removes messages from the outgoing queue and cancels
+ // the TSP request if relevant. If sess is NULL here, then this processing
+ // has gone wrong.
+ ASSERT_DEBUG(sess);
+
+ if (aIsPermitted)
+ {
+ ASSERT_DEBUG(iMessageRecipientsList);
+ iMessageRecipientsList->RemoveAndDestroyMessage(msg.TransactionId());
+ CompleteSendResponse(msg, *sess); // Ownership of msg is always taken
+ }
+ else
+ {
+ CMessageRecipients* messageClients = iMessageRecipientsList->Message(msg.TransactionId());
+ if (messageClients)
+ {
+ messageClients->RemoveAndDestroyClient(sess->ClientInfo()); // Remove the current client info from the list
+ if (messageClients->Clients().IsEmpty())
+ {
+ iMessageRecipientsList->RemoveAndDestroyMessage(msg.TransactionId());
+ // The bearer won't be getting a response
+
+ SendReject(msg.Addr(), msg.InterfaceUid(), msg.OperationId(), msg.TransactionId());
+ }
+ }
+ --sess->NumRemotesToTry();
+ sess->SendError() = KErrNone;
+ if (sess->NumRemotesToTry() == 0)
+ {
+ sess->CompleteSend();
+ }
+ delete &msg;
+ }
+ if (!iOutgoingRspPendingTsp->IsEmpty())
+ {
+ PermitOutgoingResponse();
+ }
+ LOGOUTGOINGRSPPENDINGTSP;
+ }
+
+void CRemConServer::MrctspoDoIncomingNotifyAddressed(TClientInfo* aClientInfo, TInt aError)
+ {
+ LOG_FUNC;
+ LOG(KNullDesC8());
+ LOG1(_L("\taError = %d"), aError);
+ LOGINCOMINGNOTIFYCMDPENDINGADDRESS;
+ LOGINCOMINGNOTIFYCMDPENDINGREADDRESS;
+ LOGINCOMINGDELIVERED;
+
+ // Send the command to the requested target client, and remove the
+ // addressed message from the iIncomingNotifyCmdPendingAddress queue. Any error at
+ // any point should be ignored- just complete as much as we can.
+ // Then check iIncomingPendingAddress for more commands to give to the
+ // TSP.
+
+ ASSERT_DEBUG(iTspAddressingIncomingNotifyCommand || iTspReAddressingIncomingNotifyCommands);
+
+ if (iTspAddressingIncomingNotifyCommand)
+ {
+ iTspAddressingIncomingNotifyCommand = EFalse;
+ if (!iTspDropIncomingNotifyCommand)
+ {
+ // We know that the queue is not empty because we put something on the
+ // queue to call AddressIncomingNotifyCommand, which results in one call to this
+ // function, which is the only place where messages are removed from the
+ // queue.
+ CRemConMessage& msg = IncomingNotifyCmdPendingAddress().First();
+ TBool cmdDelivered = EFalse;
+
+ // If the TSP errored, can't complete to any clients.
+ if ( aError == KErrNone && aClientInfo)
+ {
+ LOG1(_L("\t\tprocess ID %d"), static_cast<TUint>(aClientInfo->ProcessId()));
+ // Get the corresponding session.
+ CRemConSession* const sess = TargetSession(aClientInfo->ProcessId());
+ // NB The set of open sessions may have changed while the request
+ // was out on the TSP. If the TSP indicates a session that has
+ // gone away, then ignore that session.
+ if ( sess )
+ {
+ TRAPD(err, DeliverCmdToClientL(msg, *sess));
+ if (err == KErrNone)
+ {
+ cmdDelivered = ETrue;
+ }
+ // If we couldn't deliver an instance of the command to a
+ // target, there's not much we can do.
+ }
+ }
+
+ if (!cmdDelivered)
+ {
+ // The command wasn't delivered to any clients
+
+ // The command wasn't delivered to any clients
+ // Tell bearer it won't be getting a response
+
+ SendReject(msg.Addr(), msg.InterfaceUid(), msg.OperationId(), msg.TransactionId());
+ }
+
+
+ // Destroy the message we've just dealt with.
+ IncomingNotifyCmdPendingAddress().RemoveAndDestroy(msg);
+ }
+ iTspDropIncomingNotifyCommand = EFalse;
+ if ( !IncomingNotifyCmdPendingAddress().IsEmpty() )
+ {
+ LOG(_L("\tmore incoming commands awaiting addressing..."));
+ AddressIncomingNotifyCommand();
+ }
+ }
+ else
+ {
+ if (!iTspDropIncomingNotifyCommand)
+ {
+ CRemConMessage& msg = IncomingNotifyCmdPendingReAddress().First();
+ if(aError == KErrNone && aClientInfo)
+ {
+ LOG1(_L("\t\tprocess ID %d"), static_cast<TUint>(aClientInfo->ProcessId()));
+ // Get the corresponding session.
+ CRemConSession* const sess = TargetSession(aClientInfo->ProcessId());
+ if (sess)
+ {
+ if (sess->Id() == msg.SessionId())
+ {
+ // Don't do anything - it's already on IncomingDelivered
+ }
+ else
+ {
+ // Remove the original message from IncomingDelivered
+ CRemConMessage* deliveredMsg = NULL;
+ TSglQueIter<CRemConMessage> iter = IncomingDelivered().SetToFirst();
+ while ((deliveredMsg = iter++) != NULL)
+ {
+ if (deliveredMsg->TransactionId() == msg.TransactionId())
+ {
+ // We need to update the subtype now, in case the client has sent an interim response while the notify
+ // was being readdressed.
+ msg.MsgSubType() = deliveredMsg->MsgSubType();
+ // Deliver to the client
+ TRAPD(err, DeliverCmdToClientL(msg, *sess));
+ if (err == KErrNone)
+ {
+ // Only remove the current message if the delivery to the new client suceeded.
+ IncomingDelivered().RemoveAndDestroy(*deliveredMsg);
+ }
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ SendReject(msg.Addr(), msg.InterfaceUid(), msg.OperationId(), msg.TransactionId());
+ }
+ }
+ IncomingNotifyCmdPendingReAddress().RemoveAndDestroy(msg);
+ }
+
+ iTspDropIncomingNotifyCommand = EFalse;
+
+ if ( !IncomingNotifyCmdPendingReAddress().IsEmpty() )
+ {
+ LOG(_L("\tmore incoming commands awaiting readdressing..."));
+ ReAddressIncomingNotifyCommand();
+ }
+ else
+ {
+ iTspReAddressingIncomingNotifyCommands = EFalse;
+ if ( !IncomingNotifyCmdPendingAddress().IsEmpty() )
+ {
+ LOG(_L("\tmore incoming commands awaiting addressing..."));
+ AddressIncomingNotifyCommand();
+ }
+ }
+ }
+ LOGINCOMINGNOTIFYCMDPENDINGADDRESS;
+ LOGINCOMINGNOTIFYCMDPENDINGREADDRESS;
+ LOGINCOMINGDELIVERED;
+ }
+
+void CRemConServer::MrctspoDoReAddressNotifies()
+ {
+ LOG_FUNC;
+ LOGINCOMINGNOTIFYCMDPENDINGREADDRESS;
+ LOGINCOMINGDELIVERED;
+ ASSERT_DEBUG(iTspReAddressingIncomingNotifyCommands == EFalse && iTspAddressingIncomingNotifyCommand == EFalse);
+ TSglQueIter<CRemConMessage> iter = IncomingDelivered().SetToFirst();
+ CRemConMessage* deliveredMsg;
+ while ((deliveredMsg = iter++) != NULL)
+ {
+ if (deliveredMsg->MsgType() == ERemConNotifyCommand)
+ {
+ CRemConMessage* newMsg = NULL;
+ TRAPD(err, newMsg = CRemConMessage::CopyL(*deliveredMsg));
+ if (err == KErrNone)
+ {
+ IncomingNotifyCmdPendingReAddress().Append(*newMsg);
+ }
+ // If we couldn't copy the message, there isn't much we can do now.
+ }
+ }
+ if (!IncomingNotifyCmdPendingReAddress().IsEmpty())
+ {
+ iTspReAddressingIncomingNotifyCommands = ETrue;
+ ReAddressIncomingNotifyCommand();
+ }
+ LOGINCOMINGNOTIFYCMDPENDINGREADDRESS;
+ }
+
+void CRemConServer::MrctspoDoIncomingCommandPermitted(TBool aIsPermitted)
+ {
+ LOG_FUNC
+
+ MrctspoDoIncomingCommandAddressed(aIsPermitted ? KErrNone : KErrAccessDenied);
+ }
+
+void CRemConServer::MrctspoDoIncomingNotifyPermitted(TBool aIsPermitted)
+ {
+ LOG_FUNC
+
+ if(aIsPermitted)
+ {
+ TClientInfo* clientInfo = ClientIdToClientInfo(IncomingNotifyCmdPendingAddress().First().Client());
+ MrctspoDoIncomingNotifyAddressed(clientInfo, KErrNone);
+ }
+ else
+ {
+ MrctspoDoIncomingNotifyAddressed(NULL, KErrAccessDenied);
+ }
+ }
+
+void CRemConServer::TspOutgoingCommand()
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(iTspIf);
+ ASSERT_DEBUG(iTspHandlingOutgoingCommand == EFalse);
+ // For TSPs which complete this request synchronously this will become
+ // recursive, but the depth is not expected to be great (== number of
+ // messages awaiting access to the TSP).
+
+ // Work out whether the next command to deal with is awaiting (a)
+ // addressing or (b) permission.
+ // The head item is at index 0. This function should only be called if the
+ // queue is not empty.
+ CRemConMessage& msg = OutgoingCmdPendingTsp().First();
+ CRemConSession* const sess = Session(msg.SessionId());
+ // The session should exist- if it closed after asking to send this
+ // message, then the message should have been removed from the outgoing
+ // pending TSP queue at that time.
+ ASSERT_DEBUG(sess);
+ iTspHandlingOutgoingCommand = ETrue;
+ if ( msg.Addr().IsNull() )
+ {
+ // Null address means it's awaiting an address.
+ // Check the array of outgoing addresses is ready for this new request
+ // on the TSP.
+ ASSERT_DEBUG(iTspConnections.IsEmpty());
+ ASSERT_DEBUG(iBearerManager);
+ iTspIf->AddressOutgoingCommand(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ sess->ClientInfo(),
+ iTspConnections,
+ iBearerManager->BearerSecurityPolicies());
+ }
+ else
+ {
+ // Non-null address means it's awaiting permission to send.
+ sess->NumRemotesToTry() = 1;
+ iTspIf->PermitOutgoingCommand(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ sess->ClientInfo(),
+ msg.Addr());
+ }
+ }
+
+void CRemConServer::TspOutgoingNotifyCommand()
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(iTspIf3);
+ ASSERT_DEBUG(iTspHandlingOutgoingNotifyCommand == EFalse);
+ // For TSPs which complete this request synchronously this will become
+ // recursive, but the depth is not expected to be great (== number of
+ // messages awaiting access to the TSP).
+
+ // Work out whether the next command to deal with is awaiting (a)
+ // addressing or (b) permission.
+ // The head item is at index 0. This function should only be called if the
+ // queue is not empty.
+ CRemConMessage& msg = OutgoingNotifyCmdPendingTsp().First();
+ CRemConSession* const sess = Session(msg.SessionId());
+ // The session should exist- if it closed after asking to send this
+ // message, then the message should have been removed from the outgoing
+ // pending TSP queue at that time.
+ ASSERT_DEBUG(sess);
+ iTspHandlingOutgoingNotifyCommand = ETrue;
+ if ( msg.Addr().IsNull() )
+ {
+ ASSERT_DEBUG(iBearerManager);
+
+ iTspIf3->AddressOutgoingNotify(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ sess->ClientInfo(),
+ iBearerManager->BearerSecurityPolicies());
+ }
+ else
+ {
+ // Non-null address means it's awaiting permission to send.
+ sess->NumRemotesToTry() = 1;
+ iTspIf3->PermitOutgoingNotifyCommand(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ sess->ClientInfo(),
+ msg.Addr());
+ }
+ }
+
+void CRemConServer::AddressIncomingCommand()
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(iTspIf);
+ ASSERT_DEBUG(iTspAddressingIncomingCommand == EFalse);
+ // For TSPs which complete this request synchronously this will become
+ // recursive, but the depth is not expected to be great (== number of
+ // messages awaiting addressing).
+
+ // There are two possibilities here, either the bearer has already provided
+ // us with an address, in which case we just provide the TSP the command
+ // for information, and to give it the opportunity to reject the command,
+ // or we don't have an address, in which case we ask the TSP for one
+
+ // This function should only be called if we know this queue is not
+ // empty.
+ CRemConMessage& msg = IncomingCmdPendingAddress().First();
+ iTspIncomingCmdClients.Reset();
+ iTspAddressingIncomingCommand = ETrue;
+
+ if(msg.Client() == KNullClientId)
+ {
+ // Prepare the array of target process IDs for the TSP.
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const sess = iSessions[ii];
+ ASSERT_DEBUG(sess);
+ if ( sess->Type() == ERemConClientTypeTarget )
+ {
+ iTspIncomingCmdClients.AddLast(sess->ClientInfo());
+ }
+ }
+ iSessionsLock.Signal();
+
+ iTspIf->AddressIncomingCommand(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ iTspIncomingCmdClients);
+ }
+ else
+ {
+ iTspIncomingCmdClients.AddLast(*ClientIdToClientInfo(msg.Client()));
+ ASSERT_DEBUG(iTspIf4);
+ iTspIf4->PermitIncomingCommand(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ *iTspIncomingCmdClients.First());
+ }
+ }
+
+void CRemConServer::AddressIncomingNotifyCommand()
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(iTspIf2);
+ ASSERT_DEBUG(iTspAddressingIncomingNotifyCommand == EFalse);
+ // For TSPs which complete this request synchronously this will become
+ // recursive, but the depth is not expected to be great (== number of
+ // messages awaiting addressing).
+
+ // There are two possibilities here, either the bearer has already provided
+ // us with an address, in which case we just provide the TSP the command
+ // for information, and to give it the opportunity to reject the command,
+ // or we don't have an address, in which case we ask the TSP for one
+
+ // This function should only be called if we know this queue is not
+ // empty
+ CRemConMessage& msg = IncomingNotifyCmdPendingAddress().First();
+ iTspIncomingNotifyCmdClients.Reset();
+ iTspAddressingIncomingNotifyCommand = ETrue;
+
+ if(!FindDuplicateNotify(msg))
+ {
+ if(msg.Client() == KNullClientId)
+ {
+ // Prepare the array of target process IDs for the TSP.
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const sess = iSessions[ii];
+ ASSERT_DEBUG(sess);
+ if ( sess->Type() == ERemConClientTypeTarget )
+ {
+ iTspIncomingNotifyCmdClients.AddLast(sess->ClientInfo());
+ }
+ }
+ iSessionsLock.Signal();
+
+ // Only send the notify to the TSP if there isn't an identical one on either incomingpendingdelivery or incomingdelivered
+ iTspIf2->AddressIncomingNotify(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ iTspIncomingNotifyCmdClients);
+ }
+ else
+ {
+ iTspIncomingNotifyCmdClients.AddLast(*ClientIdToClientInfo(msg.Client()));
+ ASSERT_DEBUG(iTspIf4);
+ iTspIf4->PermitIncomingNotify(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ *iTspIncomingNotifyCmdClients.First());
+ }
+ }
+ else
+ {
+ // Otherwise, we can call IncomingNotifyAddressed with NULL, and it will be rejected back to the bearer
+ MrctspoDoIncomingNotifyAddressed(NULL, KErrArgument);
+ }
+ }
+
+void CRemConServer::ReAddressIncomingNotifyCommand()
+ {
+ LOG_FUNC;
+ LOGINCOMINGNOTIFYCMDPENDINGREADDRESS;
+ ASSERT_DEBUG(iTspIf2);
+ ASSERT_DEBUG(iTspReAddressingIncomingNotifyCommands);
+ // For TSPs which complete this request synchronously this will become
+ // recursive, but the depth is not expected to be great (== number of
+ // messages awaiting addressing).
+ // Prepare the array of target process IDs for the TSP.
+ iTspIncomingNotifyCmdClients.Reset();
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const sess = iSessions[ii];
+ ASSERT_DEBUG(sess);
+ if ( sess->Type() == ERemConClientTypeTarget )
+ {
+ iTspIncomingNotifyCmdClients.AddLast(sess->ClientInfo());
+ }
+ }
+ iSessionsLock.Signal();
+
+ // This function should only be called if we know this queue is not
+ // empty.
+ CRemConMessage& msg = IncomingNotifyCmdPendingReAddress().First();
+ iTspIf2->AddressIncomingNotify(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ iTspIncomingNotifyCmdClients);
+ }
+
+
+void CRemConServer::PermitOutgoingResponse()
+ {
+ LOG_FUNC;
+ LOGOUTGOINGRSPPENDINGTSP;
+
+ ASSERT_DEBUG(iTspHandlingOutgoingResponse == EFalse);
+ ASSERT_DEBUG(!OutgoingRspPendingTsp().IsEmpty());
+ while (!iTspHandlingOutgoingResponse && !OutgoingRspPendingTsp().IsEmpty())
+ {
+ CRemConMessage& msg = OutgoingRspPendingTsp().First();
+ CRemConSession* session = Session(msg.SessionId());
+ // The session should exist- if it closed after asking to send this
+ // message, then the message should have been removed from the outgoing
+ // pending TSP queue at that time.
+ ASSERT_DEBUG(session);
+ ASSERT_DEBUG(iMessageRecipientsList);
+ CMessageRecipients* message = iMessageRecipientsList->Message(msg.TransactionId());
+
+ if (message) // If we aren't returned a client list, this means that the message has been delivered elsewhere
+ {
+ iTspHandlingOutgoingResponse = ETrue;
+ if (iTspIf2)
+ {
+ iTspIf2->PermitOutgoingResponse(
+ msg.InterfaceUid(),
+ msg.OperationId(),
+ session->ClientInfo(),
+ message->ConstIter()
+ );
+ }
+ else
+ {
+ OutgoingResponsePermitted(ETrue);
+ }
+ }
+ else
+ {
+ session->NumRemotes() = 0;
+ --session->NumRemotesToTry();
+ session->SendError() = KErrNone;
+ session->CompleteSend();
+ OutgoingRspPendingTsp().RemoveAndDestroy(msg);
+ }
+ }
+ LOGOUTGOINGRSPPENDINGTSP;
+ }
+
+void CRemConServer::SendCmdToRemoteL(const CRemConMessage& aMsg, const TRemConAddress& aConn, TBool& aSync)
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(
+ (aMsg.MsgType() == ERemConCommand)
+ || (aMsg.MsgType() == ERemConNotifyCommand)
+ );
+
+
+ // Populate aSync immediately in case the function leaves.
+ aSync = EFalse;
+ TConnectionState conState = ConnectionState(aConn);
+ if ( conState == EConnected)
+ {
+ aSync = ETrue;
+ }
+
+ // Take a copy of the message and set the right address.
+ CRemConMessage* newMsg = CRemConMessage::CopyL(aMsg);
+ newMsg->Addr() = aConn;
+ CleanupStack::PushL(newMsg);
+ ASSERT_DEBUG(iBearerManager);
+
+ // If we're connected (and not mid-connect/disconnect) we can send immediately,
+ // otherwise we queue and try to bring up the connection.
+ switch ( conState )
+ {
+ case EConnected:
+ {
+ // We have a connection to send over. Try to send it.
+ LEAVEIFERRORL(iBearerManager->Send(*newMsg));
+ // If Send worked, then the bearer has taken ownership of the
+ // message's data.
+ newMsg->OperationData().Assign(NULL);
+ CLEANUPSTACK_POP1(newMsg);
+ OutgoingSent().Append(*newMsg);
+ break;
+ }
+ case EDisconnected:
+ {
+ // No connection. Try to bring one up. If we can't then destroy the
+ // new message and leave.
+ CLEANUPSTACK_POP1(newMsg);
+ // We need to put the message on the queue before trying to connect
+ // because the connect confirmation might come back synchronously.
+ OutgoingPendingSend().Append(*newMsg);
+ TInt err = iBearerManager->Connect(newMsg->Addr());
+ if ( err != KErrNone )
+ {
+ OutgoingPendingSend().RemoveAndDestroy(*newMsg);
+ aSync = ETrue;
+ LEAVEIFERRORL(err); // will destroy newMsg
+ }
+ break;
+ }
+ case EConnecting:
+ case EDisconnecting:
+ {
+ // Just queue if connection is coming up or going down.
+ //
+ // If connection is coming up, the message will be
+ // sent when ConnectConfirm fires.
+ //
+ // If connection is going down: When CBearerManager gets
+ // the DisconnectConfirm it calls us back at RemoveConnection,
+ // whereat we will reconnect the bearer that was mid-disconnect;
+ // the message will be sent when that completes.
+ CLEANUPSTACK_POP1(newMsg);
+ OutgoingPendingSend().Append(*newMsg);
+ break;
+ }
+ default:
+ {
+ DEBUG_PANIC_LINENUM;
+ break;
+ }
+ }
+
+ LOG1(_L("\taSync = %d"), aSync);
+ }
+
+void CRemConServer::DeliverCmdToClientL(const CRemConMessage& aMsg, CRemConSession& aSess)
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG((aMsg.MsgType() == ERemConCommand) || (aMsg.MsgType() == ERemConNotifyCommand));
+ // Take a copy of the message and set the right session ID (important to
+ // set the selected session's ID because this is how we match up the
+ // client's response, if aMsg is a command).
+ CRemConMessage* const newMsg = CRemConMessage::CopyL(aMsg);
+ newMsg->SessionId() = aSess.Id();
+ LEAVEIFERRORL(DeliverMessageToClient(*newMsg, aSess));
+ }
+
+TInt CRemConServer::DeliverMessageToClient(CRemConMessage& aMsg, CRemConSession& aSess)
+ {
+ LOG_FUNC;
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+ TInt err = KErrNone;
+
+ // First off check if the client supports this
+ if(!aSess.SupportedMessage(aMsg))
+ {
+ err = KErrArgument;
+
+ // 'Take ownership' of it by destroying it- it's finished with.
+ delete &aMsg;
+ }
+ else if ( aSess.CurrentReceiveMessage().Handle() )
+ {
+ // If the client can take the message now put it on the right queue.
+
+ err = aSess.WriteMessageToClient (aMsg);
+ // If the message was a command, and it was delivered with no error,
+ // then put it in the 'incoming delivered' log. Otherwise, delete it
+ // because it's finished with.
+ if ((aMsg.MsgType() == ERemConCommand) || (aMsg.MsgType() == ERemConNotifyCommand))
+ {
+ if (err == KErrNone )
+ {
+ // We'll need to remember it for the response coming back.
+ IncomingDelivered().Append(aMsg);
+ }
+ else
+ {
+ // 'Take ownership' of it by destroying it- it's finished with.
+ delete &aMsg;
+ }
+ }
+ else
+ {
+ // 'Take ownership' of it by destroying it- it's finished with.
+ delete &aMsg;
+ }
+ }
+ else
+ {
+ IncomingPendingDelivery().Append(aMsg);
+ }
+
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+ return err;
+ }
+
+void CRemConServer::MrctspoDoIncomingCommandAddressed(TInt aError)
+ {
+ LOG(KNullDesC8());
+ LOG_FUNC;
+ LOG1(_L("\taError = %d"), aError);
+ LOGINCOMINGCMDPENDINGADDRESS;
+ LOGINCOMINGDELIVERED;
+
+ // Send the command to the requested target client(s), and remove the
+ // addressed message from the iIncomingPendingAddress queue. Any error at
+ // any point should be ignored- just complete as much as we can.
+ // Then check iIncomingPendingAddress for more commands to give to the
+ // TSP.
+
+ ASSERT_DEBUG(iTspAddressingIncomingCommand);
+
+ iTspAddressingIncomingCommand = EFalse;
+
+ if (!iTspDropIncomingCommand)
+ {
+ // If we did not call CommandExpired on the first item in the queue,
+ // we know that the queue is not empty because we put something on the
+ // queue to call AddressIncomingCommand, which results in one call to this
+ // function, which is the only place where messages are removed from the
+ // queue.
+ CRemConMessage& msg = IncomingCmdPendingAddress().First();
+ TBool cmdDelivered = EFalse;
+
+ // If the TSP errored, can't complete to any clients.
+ if ( aError == KErrNone )
+ {
+ TSglQueIter<TClientInfo> iter(iTspIncomingCmdClients);
+
+ TClientInfo* procId;
+ CMessageRecipients* messageRecipients = NULL;
+ TBool canDeliver = ETrue;
+ TRAPD(err, messageRecipients = CMessageRecipients::NewL());
+ if (err != KErrNone)
+ {
+ // If we didn't manage to create the list of clients we're delivering to,
+ // we shouldn't deliver the message to the clients
+ canDeliver = EFalse;
+ }
+ else
+ {
+ messageRecipients->TransactionId() = msg.TransactionId();
+ }
+ if (canDeliver)
+ {
+ while ( ( procId = iter++ ) != NULL )
+ {
+ LOG1(_L("\t\tprocess ID %d"), static_cast<TUint>(procId->ProcessId()));
+ // Get the corresponding session.
+ CRemConSession* const sess = TargetSession(procId->ProcessId());
+ // NB The set of open sessions may have changed while the request
+ // was out on the TSP. If the TSP indicates a session that has
+ // gone away, then ignore that session.
+ if ( sess )
+ {
+ TInt err = KErrNone;
+ TClientInfo* clientInfo = NULL;
+ TRAP(err, clientInfo = new (ELeave) TClientInfo);
+ if (err == KErrNone)
+ {
+ // If we didn't manage to create the TClientInfo, we shouldn't deliver to the client
+ TRAP(err, DeliverCmdToClientL(msg, *sess));
+ }
+ if (err == KErrNone)
+ {
+ cmdDelivered = ETrue;
+ // Add to the delivered information queue
+ clientInfo->ProcessId() = procId->ProcessId();
+ clientInfo->SecureId() = procId->SecureId();
+ messageRecipients->Clients().AddLast(*clientInfo);
+ }
+ else
+ {
+ delete clientInfo;
+ }
+ // If we couldn't deliver an instance of the command to a
+ // target, there's not much we can do.
+ }
+ }
+ if ( messageRecipients->Clients().IsEmpty())
+ {
+ delete messageRecipients;
+ }
+ else
+ {
+ ASSERT_DEBUG(iMessageRecipientsList);
+ iMessageRecipientsList->Messages().AddLast (*messageRecipients);
+ }
+ }
+ }
+
+ if ( !cmdDelivered)
+ {
+ // The command wasn't delivered to any clients
+ // Tell bearer it won't be getting a response
+
+ SendReject(msg.Addr(), msg.InterfaceUid(), msg.OperationId(), msg.TransactionId());
+ }
+ // Destroy the message we've just dealt with.
+ IncomingCmdPendingAddress().RemoveAndDestroy(msg);
+
+ }
+
+ iTspDropIncomingCommand = EFalse;
+
+ if ( !IncomingCmdPendingAddress().IsEmpty() )
+ {
+ LOG(_L("\tmore incoming commands awaiting addressing..."));
+ AddressIncomingCommand();
+ }
+
+ LOGINCOMINGCMDPENDINGADDRESS;
+ LOGINCOMINGDELIVERED;
+ }
+
+TInt CRemConServer::MrctspoDoGetConnections(TSglQue<TRemConAddress>& aConnections)
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(aConnections.IsEmpty());
+
+ // Get an owned copy of the current set of connections in the system.
+ CConnections* conns = NULL;
+ TRAPD(err, conns = CConnections::CopyL(Connections()));
+ LOG1(_L("\terr = %d"), err);
+ if ( err == KErrNone )
+ {
+ // Pass these into aConnections, taking ownership of them.
+ TSglQueIter<TRemConAddress>& iter = conns->SetToFirst();
+ TRemConAddress* addr;
+ while ( ( addr = iter++ ) != NULL )
+ {
+ conns->Remove(*addr);
+ aConnections.AddLast(*addr);
+ };
+ delete conns;
+ }
+
+ return err;
+ }
+
+TInt CRemConServer::MrctspoSetLocalAddressedClient(const TUid& aBearerUid, const TClientInfo& aClientInfo)
+ {
+ LOG_FUNC;
+
+ TRemConClientId id = KNullClientId;
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for(TUint i=0; i<count; i++)
+ {
+ CRemConSession* const sess = iSessions[i];
+ ASSERT_DEBUG(sess);
+ if(sess->ClientInfo().ProcessId() == aClientInfo.ProcessId())
+ {
+ id = sess->Id();
+ break;
+ }
+ }
+ iSessionsLock.Signal();
+
+ if(id != KNullClientId)
+ {
+ ASSERT_DEBUG(iBearerManager);
+ return iBearerManager->SetLocalAddressedClient(aBearerUid, id);
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+void CRemConServer::LoadTspL()
+ {
+ LOG_FUNC;
+
+ // Instantiate one-and-only implementation of the target selector plugin
+ // interface.
+ const TUid KUidTargetSelectorInterface = TUid::Uid(KRemConTargetSelectorInterfaceUid);
+ RImplInfoPtrArray implementations;
+ const TEComResolverParams noResolverParams;
+ REComSession::ListImplementationsL(KUidTargetSelectorInterface,
+ noResolverParams,
+ KRomOnlyResolverUid,
+ implementations);
+ CleanupResetAndDestroyPushL(implementations);
+ LOG1(_L("\tnumber of implementations of target selector plugin interface: %d"), implementations.Count());
+ // We use ASSERT_ALWAYS here because this assumption is a crucial
+ // licensee-facing one- it's not a case of simply 'run the tests on a
+ // debug build and fix it if it's broken'.
+ ASSERT_ALWAYS( implementations.Count() == 1 );
+ CImplementationInformation* impl = implementations[0];
+ ASSERT_DEBUG(impl);
+ LOG(_L("\tloading TSP with:"));
+ LOG1(_L("\t\timplementation uid 0x%08x"), impl->ImplementationUid());
+ LOG1(_L("\t\tversion number %d"), impl->Version());
+ TBuf8<KMaxName> buf8;
+ buf8.Copy(impl->DisplayName());
+ LOG1(_L8("\t\tdisplay name \"%S\""), &buf8);
+ LOG1(_L("\t\tROM only %d"), impl->RomOnly());
+ LOG1(_L("\t\tROM based %d"), impl->RomBased());
+ iTsp = CRemConTargetSelectorPlugin::NewL(impl->ImplementationUid(), *this);
+ CleanupStack::PopAndDestroy(&implementations);
+
+ iTspIf = reinterpret_cast<MRemConTargetSelectorPluginInterface*>(
+ iTsp->GetInterface(TUid::Uid(KRemConTargetSelectorInterface1))
+ );
+
+ iTspIf2 = reinterpret_cast<MRemConTargetSelectorPluginInterfaceV2*>(
+ iTsp->GetInterface(TUid::Uid(KRemConTargetSelectorInterface2))
+ );
+
+ iTspIf3 = reinterpret_cast<MRemConTargetSelectorPluginInterfaceV3*>(
+ iTsp->GetInterface(TUid::Uid(KRemConTargetSelectorInterface3))
+ );
+
+ iTspIf4 = reinterpret_cast<MRemConTargetSelectorPluginInterfaceV4*>(
+ iTsp->GetInterface(TUid::Uid(KRemConTargetSelectorInterface4))
+ );
+
+ // If the TSP doesn't implement the required interface, panic server
+ // startup.
+ ASSERT_ALWAYS(iTspIf);
+
+ // We always need a V4 interface to allow simpler handling by the
+ // bearers of bearer addressing so if we don't have a V4 interface
+ // from the TSP itself use a stub object to implement default
+ // behaviour.
+ if(!iTspIf4)
+ {
+ iTspIf4 = &iTspIf4Stub;
+ }
+ }
+
+void CRemConServer::SendCommand(CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+
+ if (aMsg.MsgType() == ERemConCommand)
+ {
+ LOGOUTGOINGCMDPENDINGTSP;
+
+ OutgoingCmdPendingTsp().Append(aMsg);
+ if ( !iTspHandlingOutgoingCommand )
+ {
+ TspOutgoingCommand();
+ }
+
+ LOGOUTGOINGCMDPENDINGTSP;
+ }
+ else
+ {
+ // Check the command is a notify command
+ ASSERT_DEBUG(aMsg.MsgType() == ERemConNotifyCommand);
+
+ if(iTspIf3)
+ {
+ OutgoingNotifyCmdPendingTsp().Append(aMsg);
+ if ( !iTspHandlingOutgoingNotifyCommand )
+ {
+ TspOutgoingNotifyCommand();
+ }
+ }
+ else
+ {
+ CRemConSession* const sess = Session(aMsg.SessionId());
+ delete &aMsg;
+ ASSERT_DEBUG(sess);
+ sess->SendError() = KErrNotSupported;
+ sess->CompleteSend();
+ }
+ }
+
+ }
+
+void CRemConServer::SendResponse(CRemConMessage& aMsg, CRemConSession& aSess)
+ {
+ LOG_FUNC;
+ LOGINCOMINGDELIVERED;
+ LOGOUTGOINGRSPPENDINGTSP;
+ LOGOUTGOINGPENDINGSEND;
+
+ CRemConMessage* response = &aMsg;
+ CRemConMessage* newResponse = NULL;
+
+ // Find the first command ('John') in the iIncomingDelivered queue with
+ // the same session ID, interface UID and operation ID as the response
+ // we're sending, and send the response to the same address that John came
+ // from.
+ TSglQueIter<CRemConMessage>& iter = IncomingDelivered().SetToFirst();
+ CRemConMessage* msg;
+ TBool found = EFalse;
+ while ( ( msg = iter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSess.Id()
+ && msg->InterfaceUid() == response->InterfaceUid()
+ && msg->OperationId() == response->OperationId()
+ && (
+ (msg->MsgSubType() == ERemConMessageDefault && response->MsgSubType() == ERemConMessageDefault)
+ || (msg->MsgSubType() == ERemConNotifyCommandAwaitingInterim && response->MsgSubType() == ERemConNotifyResponseInterim)
+ || (msg->MsgSubType() == ERemConNotifyCommandAwaitingChanged && response->MsgSubType() == ERemConNotifyResponseChanged)
+ )
+ )
+ {
+ LOG1(_L("\tfound a matching item in the incoming delivered commands log: [0x%08x]"), msg);
+ found = ETrue;
+ ++aSess.NumRemotesToTry();
+
+ // Set the right address and transaction id in the outgoing message
+ response->Addr() = msg->Addr();
+ response->TransactionId() = msg->TransactionId();
+
+ if(msg->MsgType() == ERemConCommand)
+ {
+ // Check the normal command and response have the default subtype set
+ ASSERT_DEBUG(msg->MsgSubType() == ERemConMessageDefault && response->MsgSubType() == ERemConMessageDefault);
+
+ // Remove the item from the 'incoming delivered' queue now we've
+ // addressed a response using it.
+ IncomingDelivered().RemoveAndDestroy(*msg);
+
+ // At this point we need to ask the TSP if we can deliver the outgoing response,
+ // if there is a TSP supporting the V2 interface. If there isn't, we should just deliver
+ // the message to the bearer
+ OutgoingRspPendingTsp().Append(*response);
+ if (!iTspHandlingOutgoingResponse)
+ {
+ PermitOutgoingResponse();
+ }
+ }
+ else
+ {
+ // Check the command is a notify command
+ ASSERT_DEBUG(msg->MsgType() == ERemConNotifyCommand);
+
+ // Check the command has a valid subtype for a notify command
+ ASSERT_DEBUG(msg->MsgSubType() == ERemConNotifyCommandAwaitingInterim || msg->MsgSubType() == ERemConNotifyCommandAwaitingChanged);
+
+ // Check the response has a valid subtype for a notify response
+ ASSERT_DEBUG(response->MsgSubType() == ERemConNotifyResponseInterim || response->MsgSubType() == ERemConNotifyResponseChanged);
+
+ switch(msg->MsgSubType())
+ {
+ case ERemConNotifyCommandAwaitingChanged:
+ IncomingDelivered().RemoveAndDestroy(*msg);
+
+ // As this is a changed notification, there could be several notifications outstanding
+ // that should all be completed with this message.
+ // We therefore need to take a copy of the message, but the response should not be
+ // completed back to the client. We therefore set the Session ID of the new meessage to 0
+
+ TRAPD(err, newResponse = CRemConMessage::CopyL(*response));
+ if (err != KErrNone)
+ {
+ newResponse = NULL;
+ }
+ break;
+ case ERemConNotifyCommandAwaitingInterim:
+ msg->MsgSubType() = ERemConNotifyCommandAwaitingChanged;
+ break;
+ }
+ OutgoingRspPendingSend().Append(*response);
+ response = newResponse;
+ }
+ if (!newResponse)
+ {
+ break;
+ }
+ }
+ }
+
+ if (newResponse)
+ {
+ delete newResponse;
+ }
+
+
+ TSglQueIter<CRemConMessage>& rspIter = OutgoingRspPendingSend().SetToFirst();
+ while ((msg = rspIter++) != NULL)
+ {
+ OutgoingRspPendingSend().Remove(*msg);
+ CompleteSendResponse(*msg, aSess);
+ }
+
+
+ // If the command was not found, then the app has sent a response to a
+ // non-existant command. It may do this in good intention if the server
+ // has transparently died and been restarted between the app's reception
+ // of the command and it sending its response, so we can't panic it.
+ // Just drop the message.
+ if ( !found )
+ {
+ // Complete the message with KErrNone. We have done all we can with
+ // it. Any other error may encourage retries from the application,
+ // which would be useless in this situation.
+ aSess.NumRemotes() = 0;
+ aSess.SendError() = KErrNone;
+ delete &aMsg;
+ }
+
+ if (aSess.NumRemotesToTry() == 0)
+ {
+ aSess.CompleteSend();
+ }
+
+ LOGOUTGOINGRSPPENDINGTSP;
+ LOGINCOMINGDELIVERED;
+ LOGOUTGOINGPENDINGSEND;
+ }
+
+void CRemConServer::CompleteSendResponse(CRemConMessage& aMsg, CRemConSession& aSess)
+ {
+ LOG_FUNC;
+ LOGOUTGOINGPENDINGSEND;
+ // If the bearer-level connection exists, then send the message.
+ // Otherwise, queue the message and request the connection to come
+ // up. The message will be sent when ConnectConfirm or
+ // ConnectIndicate is called (assuming no error).
+ ASSERT_DEBUG(aMsg.MsgType() == ERemConResponse);
+ ASSERT_DEBUG(iBearerManager);
+ // If we're connected (and not mid-connect/disconnect) we can send immediately,
+ // otherwise we queue and try to bring up the connection.
+ switch ( ConnectionState(aMsg.Addr()) )
+ {
+ case EConnected:
+ {
+ // We're already connected
+ // If the bearer couldn't send, we need to error the client.
+ TInt err = iBearerManager->Send(aMsg);
+ // Complete client's message. Bearer-level error means the
+ // response got sent to zero remotes- bearer-level success
+ // means it got sent to precisely 1.
+ --aSess.NumRemotesToTry();
+ if (err == KErrNone)
+ {
+ ++aSess.NumRemotes();
+ }
+ aSess.SendError() = err;
+ if (aSess.NumRemotesToTry() == 0)
+ {
+ aSess.CompleteSend();
+ }
+ // We've now finished with the response.
+ delete &aMsg;
+ break;
+ }
+ case EDisconnected:
+ {
+ // We're not connected.
+ // Queue the response...
+ OutgoingPendingSend().Append(aMsg);
+ // ... and ask the bearer to establish a connection. If we
+ // couldn't then complete the client's message and clean up.
+ TInt err = iBearerManager->Connect(aMsg.Addr());
+ if ( err != KErrNone )
+ {
+ OutgoingPendingSend().RemoveAndDestroy(aMsg);
+ aSess.NumRemotes() = 0;
+ --aSess.NumRemotesToTry();
+ aSess.SendError() = err;
+ aSess.CompleteSend();
+ }
+ break;
+ }
+ case EConnecting:
+ case EDisconnecting:
+ {
+ // Just queue if connection is coming up or going down.
+ //
+ // If connection is coming up, the message will be
+ // sent when ConnectConfirm fires.
+ //
+ // If connection is going down: When CBearerManager gets
+ // the DisconnectConfirm it calls us back at RemoveConnection,
+ // whereat we will reconnect the bearer that was mid-disconnect;
+ // the message will be sent when that completes.
+ OutgoingPendingSend().Append(aMsg);
+ break;
+ }
+ default:
+ {
+ DEBUG_PANIC_LINENUM;
+ break;
+ }
+ }
+ LOGOUTGOINGPENDINGSEND;
+ }
+
+
+void CRemConServer::SendReject(TRemConAddress aAddr, TUid aInterfaceUid, TUint aOperationId, TUint aTransactionId)
+ {
+ LOG_FUNC;
+ LOGOUTGOINGPENDINGSEND;
+ // If the bearer-level connection exists, then send the message.
+ // Otherwise, queue the message and request the connection to come
+ // up. The message will be sent when ConnectConfirm or
+ // ConnectIndicate is called (assuming no error).
+
+ CRemConMessage* rejectMsg = NULL;
+ RBuf8 data;
+ data = KNullDesC8;
+ TRAPD(err, rejectMsg = CRemConMessage::NewL(aAddr, KNullClientId, ERemConReject, ERemConMessageDefault, aInterfaceUid, aOperationId, data, 0, aTransactionId));
+
+ if ( err == KErrNone)
+ {
+ // SendReject will always take ownership of rejectMsg
+
+ ASSERT_DEBUG(iBearerManager);
+ switch ( ConnectionState(rejectMsg->Addr()) )
+ {
+ case EConnected:
+ {
+ // We're already connected
+ err = iBearerManager->Send(*rejectMsg);
+ // We've now finished with the response.
+ delete rejectMsg;
+ break;
+ }
+ case EDisconnected:
+ {
+ // We're not connected.
+ // Queue the response...
+ OutgoingPendingSend().Append(*rejectMsg);
+ // ... and ask the bearer to establish a connection. If we
+ // couldn't then clean up.
+ err = iBearerManager->Connect (rejectMsg->Addr ());
+ if ( err != KErrNone)
+ {
+ OutgoingPendingSend().RemoveAndDestroy(*rejectMsg);
+ }
+ break;
+ }
+ case EConnecting:
+ case EDisconnecting:
+ {
+ // Just queue if connection is coming up or going down.
+ //
+ // If connection is coming up, the message will be
+ // sent when ConnectConfirm fires.
+ //
+ // If connection is going down: When CBearerManager gets
+ // the DisconnectConfirm it calls us back at RemoveConnection,
+ // whereat we will reconnect the bearer that was mid-disconnect;
+ // the message will be sent when that completes.
+ OutgoingPendingSend().Append(*rejectMsg);
+ break;
+ }
+ default:
+ {
+ DEBUG_PANIC_LINENUM;
+ break;
+ }
+ }
+ }
+ LOGOUTGOINGPENDINGSEND;
+ }
+
+void CRemConServer::SendCancel(CRemConSession& aSess)
+ {
+ LOG_FUNC;
+ LOGOUTGOINGCMDPENDINGTSP;
+
+ TSglQueIter<CRemConMessage>& iter = OutgoingCmdPendingTsp().SetToFirst();
+ CRemConMessage* msg;
+ TBool first = ETrue;
+ while ( ( msg = iter++ ) != NULL )
+ {
+ // A client can only have one send outstanding at once, so there can
+ // only be one message on the queue belonging to it.
+ if ( msg->SessionId() == aSess.Id() )
+ {
+ ASSERT_DEBUG(msg->MsgType() == ERemConCommand);
+ LOG1(_L("\tfound a command belonging to this client in the outgoing pending TSP queue: [0x%08x]"), msg);
+
+ // If the TSP is currently handling this command, we must stop
+ // them! The one the TSP is handling, if any, is always the first
+ // in the queue.
+ if ( iTspHandlingOutgoingCommand && first )
+ {
+ LOG(_L("\tTSP is processing this command- cancel it"));
+ ASSERT_DEBUG(iTspIf);
+ iTspIf->CancelOutgoingCommand();
+ iTspHandlingOutgoingCommand = EFalse;
+ iTspConnections.Reset();
+ }
+ // Can now destroy the message.
+ OutgoingCmdPendingTsp().RemoveAndDestroy(*msg);
+ }
+ first = EFalse;
+ }
+
+ LOGOUTGOINGCMDPENDINGTSP;
+ }
+
+void CRemConServer::NewResponse(CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+ LOGOUTGOINGSENT;
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+
+ // Look through the 'outgoing sent' queue for items with the same address,
+ // interface UID, operation ID and transaction ID. We assume there will
+ // only be one such item.
+ TBool sentCommandFound = EFalse;
+ TSglQueIter<CRemConMessage>& iter = OutgoingSent().SetToFirst();
+ CRemConMessage* cmd;
+ while ( ( cmd = iter++ ) != NULL )
+ {
+ if ( cmd->Addr() == aMsg.Addr()
+ && cmd->InterfaceUid() == aMsg.InterfaceUid()
+ && cmd->OperationId() == aMsg.OperationId()
+ && cmd->TransactionId() == aMsg.TransactionId()
+ )
+ {
+ LOG1(_L("\tfound a matching item in the sent commands log: [0x%08x]"), cmd);
+ sentCommandFound = ETrue;
+ CRemConSession* const session = Session(cmd->SessionId());
+ // When sessions close, their messages are removed from the logs,
+ // so the session here _should_ exist.
+ ASSERT_DEBUG(session);
+ aMsg.SessionId() = cmd->SessionId();
+ (void) DeliverMessageToClient(aMsg, *session);
+ // Remove the found item from the sent message log.
+ OutgoingSent().RemoveAndDestroy(*cmd);
+ break;
+ }
+ }
+ if ( !sentCommandFound )
+ {
+ // Either:
+ // (a) the remote is buggy (sent a response when there wasn't an
+ // originating command),
+ // (b) the client closed their controller session before the response
+ // came back (this cleans up the 'sent commands' log)
+ LOG(_L("\tno matching item found in sent commands log- response dropped"));
+ delete &aMsg;
+ }
+
+ LOGOUTGOINGSENT;
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+ }
+
+void CRemConServer::NewNotifyResponse(CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+ LOGOUTGOINGSENT;
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+
+ // Look through the 'outgoing sent' queue for items with the same address,
+ // interface UID, operation ID and transaction ID. We assume there will
+ // only be one such item.
+ TBool sentCommandFound = EFalse;
+ TSglQueIter<CRemConMessage>& iter = OutgoingSent().SetToFirst();
+ CRemConMessage* cmd;
+ TRemConMessageSubType submessagetype;
+ submessagetype = aMsg.MsgSubType();
+
+ while ( ( cmd = iter++ ) != NULL )
+ {
+ if ( cmd->Addr() == aMsg.Addr()
+ && cmd->InterfaceUid() == aMsg.InterfaceUid()
+ && cmd->OperationId() == aMsg.OperationId()
+ && cmd->TransactionId() == aMsg.TransactionId()
+ )
+ {
+ LOG1(_L("\tfound a matching item in the sent commands log: [0x%08x]"), cmd);
+ sentCommandFound = ETrue;
+ CRemConSession* const session = Session(cmd->SessionId());
+ // When sessions close, their messages are removed from the logs,
+ // so the session here _should_ exist.
+ ASSERT_DEBUG(session);
+ aMsg.SessionId() = cmd->SessionId();
+ (void) DeliverMessageToClient(aMsg, *session);
+
+ //Do not remove the command if it is an interim response because
+ //we need to wait for the changed response.
+ //If the changed response received or error occurs, then remove
+ //the command from the sent message log
+ if (submessagetype != ERemConNotifyResponseInterim)
+ {
+ OutgoingSent().RemoveAndDestroy(*cmd);
+ }
+
+ break;
+ }
+ }
+ if ( !sentCommandFound )
+ {
+ // Either:
+ // (a) the remote is buggy (sent a response when there wasn't an
+ // originating command),
+ // (b) the client closed their controller session before the response
+ // came back (this cleans up the 'sent commands' log)
+ LOG(_L("\tno matching item found in sent commands log- response dropped"));
+ delete &aMsg;
+ }
+
+ LOGOUTGOINGSENT;
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+ }
+
+void CRemConServer::NewCommand(CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+ LOGINCOMINGCMDPENDINGADDRESS;
+
+ IncomingCmdPendingAddress().Append(aMsg);
+ if ( !iTspAddressingIncomingCommand)
+ {
+ AddressIncomingCommand();
+ }
+
+ LOGINCOMINGCMDPENDINGADDRESS;
+ }
+
+void CRemConServer::NewNotifyCommand(CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+ LOGINCOMINGNOTIFYCMDPENDINGADDRESS;
+ if (!iTspIf2)
+ {
+ SendReject(aMsg.Addr(), aMsg.InterfaceUid(), aMsg.OperationId(), aMsg.TransactionId());
+ delete &aMsg;
+ }
+ else
+ {
+ IncomingNotifyCmdPendingAddress().Append(aMsg);
+ if ( !iTspAddressingIncomingNotifyCommand && !iTspReAddressingIncomingNotifyCommands)
+ {
+ AddressIncomingNotifyCommand();
+ }
+ }
+
+ LOGINCOMINGNOTIFYCMDPENDINGADDRESS;
+ }
+
+#ifdef __FLOG_ACTIVE
+void CRemConServer::LogOutgoingNotifyCmdPendingTsp() const
+ {
+ LOG(_L("Logging outgoing notify pending TSP commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->OutgoingNotifyCmdPendingTsp().LogQueue();)
+ }
+
+void CRemConServer::LogOutgoingCmdPendingTsp() const
+ {
+ LOG(_L("Logging outgoing pending TSP commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->OutgoingCmdPendingTsp().LogQueue();)
+ }
+
+void CRemConServer::LogOutgoingRspPendingTsp() const
+ {
+ LOG(_L("Logging outgoing pending TSP commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->OutgoingRspPendingTsp().LogQueue();)
+ }
+
+
+void CRemConServer::LogOutgoingPendingSend() const
+ {
+ LOG(_L("Logging outgoing pending send commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->OutgoingPendingSend().LogQueue();)
+ }
+
+void CRemConServer::LogOutgoingSent() const
+ {
+ LOG(_L("Logging outgoing sent commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->OutgoingSent().LogQueue();)
+ }
+
+void CRemConServer::LogIncomingCmdPendingAddress() const
+ {
+ LOG(_L("Logging incoming pending address commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->IncomingCmdPendingAddress().LogQueue();)
+ }
+
+void CRemConServer::LogIncomingNotifyCmdPendingAddress() const
+ {
+ LOG(_L("Logging incoming pending address commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->IncomingNotifyCmdPendingAddress().LogQueue();)
+ }
+
+void CRemConServer::LogIncomingNotifyCmdPendingReAddress() const
+ {
+ LOG(_L("Logging incoming pending address commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->IncomingNotifyCmdPendingReAddress().LogQueue();)
+ }
+
+void CRemConServer::LogIncomingPendingDelivery() const
+ {
+ LOG(_L("Logging incoming pending delivery messages"));
+ FTRACE(const_cast<CRemConServer*>(this)->IncomingPendingDelivery().LogQueue();)
+ }
+
+void CRemConServer::LogIncomingDelivered() const
+ {
+ LOG(_L("Logging incoming delivered commands"));
+ FTRACE(const_cast<CRemConServer*>(this)->IncomingDelivered().LogQueue();)
+ }
+#endif // __FLOG_ACTIVE
+
+CRemConSession* CRemConServer::Session(TUint aSessionId) const
+ {
+ CRemConSession* sess = NULL;
+
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const temp = iSessions[ii];
+ ASSERT_DEBUG(temp);
+ if ( temp->Id() == aSessionId )
+ {
+ sess = temp;
+ break;
+ }
+ }
+ iSessionsLock.Signal();
+
+ return sess;
+ }
+
+CRemConSession* CRemConServer::TargetSession(TProcessId aProcessId) const
+ {
+ CRemConSession* sess = NULL;
+
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const temp = iSessions[ii];
+ ASSERT_DEBUG(temp);
+ if ( temp->ClientInfo().ProcessId() == aProcessId
+ && temp->Type() == ERemConClientTypeTarget )
+ {
+ sess = temp;
+ break;
+ }
+ }
+ iSessionsLock.Signal();
+
+ return sess;
+ }
+
+MRemConConverterInterface* CRemConServer::Converter(TUid aInterfaceUid,
+ TUid aBearerUid) const
+ {
+ ASSERT_DEBUG(iConverterManager);
+ return iConverterManager->Converter(aInterfaceUid, aBearerUid);
+ }
+
+MRemConConverterInterface* CRemConServer::Converter(const TDesC8& aInterfaceData,
+ TUid aBearerUid) const
+ {
+ ASSERT_DEBUG(iConverterManager);
+ return iConverterManager->Converter(aInterfaceData, aBearerUid);
+ }
+
+void CRemConServer::ReceiveRequest(CRemConSession& aSession)
+ {
+ LOG_FUNC;
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+
+ // Find the first message in IncomingPendingDelivery for this session.
+ TSglQueIter<CRemConMessage>& iter = IncomingPendingDelivery().SetToFirst();
+ CRemConMessage* msg;
+ while ( ( msg = iter++ ) != NULL )
+ {
+ if ( msg->SessionId() == aSession.Id() )
+ {
+ TInt err = aSession.WriteMessageToClient(*msg);
+ IncomingPendingDelivery().Remove(*msg);
+ if ( msg->MsgType() == ERemConCommand || msg->MsgType() == ERemConNotifyCommand)
+ {
+ if (err == KErrNone )
+ {
+ // We'll need to remember it for the response coming back.
+ IncomingDelivered().Append(*msg);
+ }
+ else
+ {
+ // Tell bearer it won't be getting a response
+ CMessageRecipients* messageRecipients = iMessageRecipientsList->Message (msg->TransactionId ());
+
+ // If we aren't returned a client list, this means that the message has been delivered elsewhere
+ if (messageRecipients)
+ {
+ messageRecipients->RemoveAndDestroyClient (aSession.ClientInfo ());
+
+ if ( messageRecipients->Clients().IsEmpty ())
+ {
+ iMessageRecipientsList->Messages().Remove (*messageRecipients);
+ delete messageRecipients;
+
+ SendReject(msg->Addr(), msg->InterfaceUid(), msg->OperationId(), msg->TransactionId());
+ }
+ }
+
+ // 'Take ownership' of it by destroying it- it's finished with.
+ delete msg;
+ }
+ }
+ else
+ {
+ // 'Take ownership' of it by destroying it- it's finished with.
+ delete msg;
+ }
+
+ break;
+ }
+ }
+
+ LOGINCOMINGPENDINGDELIVERY;
+ LOGINCOMINGDELIVERED;
+ }
+
+TBool CRemConServer::FindDuplicateNotify(CRemConMessage& aMsg)
+ {
+ ASSERT_DEBUG(aMsg.MsgType() == ERemConNotifyCommand);
+ TSglQueIter<CRemConMessage>& deliveredIter = IncomingDelivered().SetToFirst();
+ CRemConMessage* msg;
+ while ((msg = deliveredIter++) != NULL)
+ {
+ if (msg->MsgType() == ERemConNotifyCommand
+ && msg->Addr() == aMsg.Addr()
+ && msg->InterfaceUid() == aMsg.InterfaceUid()
+ && msg->OperationId() == aMsg.OperationId()
+ && msg->Client() == aMsg.Client())
+ {
+ return ETrue;
+ }
+ }
+ TSglQueIter<CRemConMessage>& pendingDeliveryIter = IncomingPendingDelivery().SetToFirst();
+ while ((msg = pendingDeliveryIter++) != NULL)
+ {
+ if (msg->MsgType() == ERemConNotifyCommand
+ && msg->Addr() == aMsg.Addr()
+ && msg->InterfaceUid() == aMsg.InterfaceUid()
+ && msg->OperationId() == aMsg.OperationId()
+ && msg->Client() == aMsg.Client())
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+TInt UidCompare(const TUid& aFirst, const TUid& aSecond)
+ {
+ if(aFirst.iUid < aSecond.iUid)
+ {
+ return -1;
+ }
+ else if(aFirst.iUid == aSecond.iUid)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+/**
+Collect all supported interfaces of controller clients.
+
+@param aSupportedInterfaces An empty RArray which will be populated with the current
+ supported interfaces. Ownership is retained by the caller.
+@return KErrNone if any interfaces were able to be retrieved. This does not
+ imply that every session's interfaces were able to be retrieved.
+ KErrNoMemory if no interfaces could be retrived.
+*/
+TInt CRemConServer::ControllerSupportedInterfaces(RArray<TUid>& aSupportedInterfaces)
+ {
+ LOG_FUNC
+ ASSERT_DEBUG(aSupportedInterfaces.Count() == 0);
+
+ TLinearOrder<TUid> uidCompare(&UidCompare);
+ RArray<TUid> sessionFeatures;
+ TInt err = KErrNone;
+ for(TInt i=0; i<iSessions.Count(); i++)
+ {
+ ASSERT_DEBUG(iSessions[i]);
+ if(iSessions[i]->Type() == ERemConClientTypeController)
+ {
+ err = iSessions[i]->SupportedInterfaces(sessionFeatures);
+ ASSERT_DEBUG(err == KErrNone || err == KErrNoMemory);
+
+ if(!err)
+ {
+ for(TInt j=0; j<sessionFeatures.Count(); j++)
+ {
+ // Ignore failure here, we're trying this best effort
+ // InsertInOrder is used rather than just bunging the
+ // interface on the end as we want no duplicates
+ (void)aSupportedInterfaces.InsertInOrder(sessionFeatures[j], uidCompare);
+ }
+ }
+ sessionFeatures.Reset();
+ }
+ }
+
+ if(aSupportedInterfaces.Count() > 0)
+ {
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNoMemory;
+ }
+ }
+
+CMessageQueue& CRemConServer::OutgoingCmdPendingTsp()
+ {
+ ASSERT_DEBUG(iOutgoingCmdPendingTsp);
+ return *iOutgoingCmdPendingTsp;
+ }
+
+CMessageQueue& CRemConServer::OutgoingNotifyCmdPendingTsp()
+ {
+ ASSERT_DEBUG(iOutgoingNotifyCmdPendingTsp);
+ return *iOutgoingNotifyCmdPendingTsp;
+ }
+
+CMessageQueue& CRemConServer::OutgoingRspPendingTsp()
+ {
+ ASSERT_DEBUG(iOutgoingRspPendingTsp);
+ return *iOutgoingRspPendingTsp;
+ }
+
+CMessageQueue& CRemConServer::OutgoingRspPendingSend()
+ {
+ ASSERT_DEBUG(iOutgoingRspPendingSend);
+ return *iOutgoingRspPendingSend;
+ }
+
+CMessageQueue& CRemConServer::OutgoingPendingSend()
+ {
+ ASSERT_DEBUG(iOutgoingPendingSend);
+ return *iOutgoingPendingSend;
+ }
+
+CMessageQueue& CRemConServer::OutgoingSent()
+ {
+ ASSERT_DEBUG(iOutgoingSent);
+ return *iOutgoingSent;
+ }
+
+CMessageQueue& CRemConServer::IncomingCmdPendingAddress()
+ {
+ ASSERT_DEBUG(iIncomingCmdPendingAddress);
+ return *iIncomingCmdPendingAddress;
+ }
+
+CMessageQueue& CRemConServer::IncomingNotifyCmdPendingAddress()
+ {
+ ASSERT_DEBUG(iIncomingNotifyCmdPendingAddress);
+ return *iIncomingNotifyCmdPendingAddress;
+ }
+
+CMessageQueue& CRemConServer::IncomingPendingDelivery()
+ {
+ ASSERT_DEBUG(iIncomingPendingDelivery);
+ return *iIncomingPendingDelivery;
+ }
+
+CMessageQueue& CRemConServer::IncomingDelivered()
+ {
+ ASSERT_DEBUG(iIncomingDelivered);
+ return *iIncomingDelivered;
+ }
+
+
+CMessageQueue& CRemConServer::IncomingNotifyCmdPendingReAddress()
+ {
+ ASSERT_DEBUG(iIncomingNotifyCmdPendingReAddress);
+ return *iIncomingNotifyCmdPendingReAddress;
+ }
+
+TBool CRemConServer::ConnectionHistoryPointerAtLatest(TUint aSessionId) const
+ {
+ LOG_FUNC;
+ LOG1(_L("\taSessionId = %d"), aSessionId);
+
+#ifdef _DEBUG
+ TBool found = EFalse;
+#endif
+ TUint index = 0;
+ const TUint count = iSession2ConnHistory.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ if ( iSession2ConnHistory[ii].iSessionId == aSessionId )
+ {
+ index = iSession2ConnHistory[ii].iIndex;
+#ifdef _DEBUG
+ found = ETrue;
+#endif
+ break;
+ }
+ }
+ ASSERT_DEBUG(found);
+
+ TBool ret = EFalse;
+ ASSERT_DEBUG(iConnectionHistory);
+ if ( index == iConnectionHistory->Count() - 1 )
+ {
+ ret = ETrue;
+ }
+
+ LOG1(_L("\tret = %d"), ret);
+ return ret;
+ }
+
+CConnections& CRemConServer::Connections()
+ {
+ ASSERT_DEBUG(iConnectionHistory);
+ return iConnectionHistory->Last();
+ }
+
+TInt CRemConServer::HandleConnection(const TRemConAddress& aAddr, TInt aError)
+ {
+ LOG_FUNC;
+ LOG2(_L("\taError = %d, aAddr.BearerUid = 0x%08x"), aError, aAddr.BearerUid());
+ LOGREMOTES;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+
+ // Try to update the connection history. If this fails (it involves memory
+ // allocation) we need to return the error so the connection will be
+ // dropped.
+ if ( aError == KErrNone )
+ {
+ ASSERT_DEBUG(iConnectionHistory);
+ aError = iConnectionHistory->NewConnection(aAddr);
+ }
+
+ // If we have a real new connection and we could handle it, aError is
+ // now KErrNone. In this case, sessions' notifications need completing.
+ if ( aError == KErrNone )
+ {
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ ASSERT_DEBUG(iSessions[ii]);
+ iSessions[ii]->ConnectionsChanged();
+ }
+ iSessionsLock.Signal();
+ }
+
+ // Complete the specific client request(s) that caused a ConnectRequest on
+ // the bearer. Tell all sessions- they remember the address they wanted to
+ // connect to, and will filter on the address we give them. NB This
+ // function is called by ConnectIndicate as well as by ConnectConfirm, but
+ // the client doesn't care which end brought the connection up.
+ const TUint count = Sessions().Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ ASSERT_DEBUG(Sessions()[ii]);
+ Sessions()[ii]->CompleteConnect(aAddr, aError);
+ }
+
+ // Any messages waiting on OutgoingPendingSend for this connection need to
+ // be handled.
+ TSglQueIter<CRemConMessage>& iter = OutgoingPendingSend().SetToFirst();
+ CRemConMessage* msg;
+ TBool moveToSent = EFalse;
+ while ( ( msg = iter++ ) != NULL )
+ {
+ if ( msg->Addr() == aAddr )
+ {
+ CRemConSession* const sess = Session(msg->SessionId());
+ // The session should exist- if it doesn't then this message
+ // wasn't cleaned from OutgoingPendingSend correctly when the
+ // session closed. The exceptions are Reject, which can be put
+ // on the queue without a session, and notify changed responses when they are being
+ // delivered to multiple controllers
+ ASSERT_DEBUG(sess || msg->MsgType() == ERemConReject || msg->MsgSubType() == ERemConNotifyResponseChanged);
+
+ if ( aError == KErrNone)
+ {
+ // We have a connection!
+ ASSERT_DEBUG(iBearerManager);
+ TInt err = iBearerManager->Send(*msg);
+ if ( err == KErrNone
+ && ((msg->MsgType() == ERemConCommand)||(msg->MsgType() == ERemConNotifyCommand)))
+ {
+ // If the send succeeded and it was a command, we move the
+ // message to the 'sent' log. Otherwise, it's simply
+ // deleted because we've finished with it.
+ moveToSent = ETrue;
+ }
+ if ( sess)
+ {
+ if ( err == KErrNone)
+ {
+ ++sess->NumRemotes();
+ }
+ else
+ {
+ sess->SendError ()= err;
+ }
+ }
+ }
+ else
+ {
+ // No connection, remember the error.
+ if ( sess)
+ {
+ sess->SendError ()= aError;
+ }
+ }
+ if ( sess)
+ {
+ --sess->NumRemotesToTry();
+
+ // If we have now dealt with all the messages on the
+ // OutgoingPendingSend queue for this session, we can complete
+ // their send. In this case we should by now have collected the
+ // number of remotes and the send error. (NB A client can only
+ // have one send outstanding at any one time; a client may have
+ // more than one message on the 'pending send' queue if the TSP
+ // said to send to more than one remote.)
+ // If the message is a notify then it can only have been sent to
+ // one Remote so the NumRemotesToTry is not used
+ if(msg->MsgType() == ERemConNotifyCommand)
+ {
+ sess->CompleteSendNotify();
+ }
+ else if ( sess->NumRemotesToTry ()== 0)
+ {
+ sess->CompleteSend ();
+ }
+ }
+
+ if ( moveToSent)
+ {
+ OutgoingPendingSend().Remove (*msg);
+ OutgoingSent().Append (*msg);
+ }
+ else
+ {
+ OutgoingPendingSend().RemoveAndDestroy (*msg);
+ }
+ }
+ }
+
+ LOGREMOTES;
+ LOGOUTGOINGPENDINGSEND;
+ LOGOUTGOINGSENT;
+ LOG1(_L("\taError = %d"), aError);
+ return aError;
+ }
+
+void CRemConServer::RemoveConnection(const TRemConAddress& aAddr)
+ {
+ LOG_FUNC;
+ LOG1(_L("\taAddr.BearerUid = 0x%08x"), aAddr.BearerUid());
+ LOGREMOTES;
+
+ // We make a new item in the connection history and inform the sessions so
+ // they can complete outstanding connection status notifications.
+
+ ASSERT_DEBUG(iConnectionHistory);
+ iConnectionHistory->Disconnection(aAddr);
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ ASSERT_DEBUG(iSessions[ii]);
+ iSessions[ii]->ConnectionsChanged();
+ }
+ iSessionsLock.Signal();
+
+ // If there are any messages waiting on OutgoingPendingSend for this connection,
+ // we re-connect it - they'll be picked up in HandleConnection above.
+
+ TSglQueIter<CRemConMessage> iter = OutgoingPendingSend().SetToFirst();
+ CRemConMessage* msg;
+ TBool needToReconnect = false;
+ while ( ( msg = iter++ ) != NULL )
+ {
+ if (msg->Addr() == aAddr)
+ {
+ needToReconnect = true;
+ break;
+ }
+ }
+
+ if (needToReconnect)
+ {
+ ASSERT_DEBUG(iBearerManager);
+ TInt err = iBearerManager->Connect(aAddr);
+ if ( err != KErrNone )
+ {
+ // This fails if:
+ // 1. we're already connecting (in which case, we don't care)
+ // 2. we can't add aAddr to the connecting list
+ // The semantics of this observer don't let us return an error or leave, so
+ // we can't do much about it here. Log it, and the next command will
+ // invoke Connect from a better situation.
+ LOG1(_L("\tFailed to re-connect bearer after connection removed: %d"), err);
+ }
+ }
+
+ LOGREMOTES;
+ }
+
+void CRemConServer::SetConnectionHistoryPointer(TUint aSessionId)
+ {
+ LOG_FUNC;
+ LOG1(_L("\taSessionId = %d"), aSessionId);
+ LOGSESSIONS;
+ LOGCONNECTIONHISTORYANDINTEREST;
+
+ // Update the record for this session.
+ const TUint count = iSession2ConnHistory.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ if ( iSession2ConnHistory[ii].iSessionId == aSessionId )
+ {
+ ASSERT_DEBUG(iConnectionHistory);
+ iSession2ConnHistory[ii].iIndex = iConnectionHistory->Count() - 1;
+ break;
+ }
+ }
+
+ // If the calling session was the last session pointing to that item in
+ // the history, and if it was the earliest item in the history, then we'll
+ // be able to clean up the history a bit.
+ UpdateConnectionHistoryAndPointers();
+
+ LOGCONNECTIONHISTORYANDINTEREST;
+ }
+
+const CConnections& CRemConServer::Connections(TUint aSessionId) const
+ {
+ LOG_FUNC;
+ LOG1(_L("\taSessionId = %d"), aSessionId);
+
+ // Get the connection history record for this session.
+ const CConnections* conns = NULL;
+ const TUint count = iSession2ConnHistory.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ if ( iSession2ConnHistory[ii].iSessionId == aSessionId )
+ {
+ ASSERT_DEBUG(iConnectionHistory);
+ conns = &(*iConnectionHistory)[iSession2ConnHistory[ii].iIndex];
+ break;
+ }
+ }
+
+ ASSERT_DEBUG(conns);
+
+ return *conns;
+ }
+
+void CRemConServer::UpdateConnectionHistoryAndPointers()
+ {
+ LOG_FUNC;
+ LOGCONNECTIONHISTORYANDINTEREST;
+
+ // This function is called whenever a session finishes its interest in a
+ // connection history record, either by closing or by completing
+ // GetConnections. We remove uninteresting records in the history by
+ // removing the lowest-indexed item in the history until the
+ // lowest-indexed item has a session interested in it. As we do so, adjust
+ // the other sessions' pointers so they're still pointing at the right
+ // records.
+ TUint lowestInterestingRecord = KMaxTUint;
+ const TUint count = iSession2ConnHistory.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ if ( iSession2ConnHistory[ii].iIndex < lowestInterestingRecord )
+ {
+ lowestInterestingRecord = iSession2ConnHistory[ii].iIndex;
+ }
+ }
+
+ // In theory, lowestInterestingRecord is now the number of connection
+ // history records we have to delete, starting with the 0th. This will not
+ // be the case (lowestInterestingRecord will still be KMaxTUint) if there
+ // are no sessions left. So adjust lowestInterestingRecord down to
+ // iConnectionHistory->Count() - 1 so that we remove all but the 'current'
+ // connection history record. This cleans up as much as possible in case
+ // server termination is interrupted.
+ ASSERT_DEBUG(iConnectionHistory);
+ if ( lowestInterestingRecord >= iConnectionHistory->Count() )
+ {
+ lowestInterestingRecord = iConnectionHistory->Count() - 1;
+ }
+ ASSERT_DEBUG(iConnectionHistory);
+ for ( TUint ii = 0 ; ii < lowestInterestingRecord ; ++ii )
+ {
+ iConnectionHistory->DestroyFirst();
+ }
+
+ // We now have to go through iSession2ConnHistory and decrement each
+ // iIndex by lowestInterestingRecord, to keep _those_ records pointing
+ // at the right history records.
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ iSession2ConnHistory[ii].iIndex -= lowestInterestingRecord;
+ }
+
+ LOGCONNECTIONHISTORYANDINTEREST;
+ }
+
+TConnectionState CRemConServer::ConnectionState(const TRemConAddress& aAddr)
+ {
+ LOG_FUNC;
+ LOG1(_L("\taaAddr.BearerUid = 0x%08x"), aAddr.BearerUid());
+
+ TConnectionState ret;
+
+ // Because 'connection state' knowledge is spread across the system
+ // we have asserts in following if statement to ensure that our state
+ // is consistent
+
+ // Check if connecting
+ ASSERT_DEBUG(iBearerManager);
+ if ( iBearerManager->IsConnecting(aAddr) )
+ {
+ ASSERT_DEBUG(!iBearerManager->IsDisconnecting(aAddr));
+ ASSERT_DEBUG(!Connections().Find(aAddr));
+ ret = EConnecting;
+ }
+ // Check if disconnecting
+ else if ( iBearerManager->IsDisconnecting(aAddr) )
+ {
+ ASSERT_DEBUG(!iBearerManager->IsConnecting(aAddr));
+ // NB Connection remains in connections list until we get DisconnectConfirm
+ ASSERT_DEBUG(Connections().Find(aAddr));
+ ret = EDisconnecting;
+ }
+ // Check if connected
+ else if ( Connections().Find(aAddr) )
+ {
+ ASSERT_DEBUG(!iBearerManager->IsConnecting(aAddr));
+ ASSERT_DEBUG(!iBearerManager->IsDisconnecting(aAddr));
+ ret = EConnected;
+ }
+ // otherwise it's disconnected
+ else
+ {
+ ret = EDisconnected;
+ }
+
+ LOG1(_L("\tret(connection state) = %d"), ret);
+ return ret;
+ }
+
+void CRemConServer::CommandExpired(TUint aTransactionId)
+ {
+ LOG_FUNC;
+
+ CRemConMessage* msg;
+
+ TBool first = ETrue;
+
+ TSglQueIter<CRemConMessage> addressCommandIter = IncomingCmdPendingAddress().SetToFirst();
+
+ while ((msg = addressCommandIter++) != NULL)
+ {
+ if (msg->TransactionId() == aTransactionId)
+ {
+ IncomingCmdPendingAddress().RemoveAndDestroy(*msg);
+ if (first && iTspAddressingIncomingCommand)
+ {
+ iTspDropIncomingCommand = ETrue;
+ }
+ }
+ first = EFalse;
+ }
+
+ TSglQueIter<CRemConMessage> addressNotifyIter = IncomingNotifyCmdPendingAddress().SetToFirst();
+
+ first = ETrue;
+
+ while ((msg = addressNotifyIter++) != NULL)
+ {
+ if (msg->TransactionId() == aTransactionId)
+ {
+ IncomingNotifyCmdPendingAddress().RemoveAndDestroy(*msg);
+ if (first && iTspAddressingIncomingNotifyCommand)
+ {
+ iTspDropIncomingNotifyCommand = ETrue;
+ }
+ }
+ first = EFalse;
+ }
+
+ TSglQueIter<CRemConMessage> reAddressNotifyIter = IncomingNotifyCmdPendingReAddress().SetToFirst();
+
+
+ while ((msg = reAddressNotifyIter++) != NULL)
+ {
+ if (msg->TransactionId() == aTransactionId)
+ {
+ IncomingNotifyCmdPendingReAddress().RemoveAndDestroy(*msg);
+ if (first && iTspReAddressingIncomingNotifyCommands)
+ {
+ iTspDropIncomingNotifyCommand = ETrue;
+ }
+
+ }
+ first = EFalse;
+ }
+
+ TSglQueIter<CRemConMessage> pendingDeliveryIter = IncomingPendingDelivery().SetToFirst();
+
+ while ((msg = pendingDeliveryIter++) != NULL)
+ {
+ if (msg->TransactionId() == aTransactionId)
+ {
+ IncomingPendingDelivery().RemoveAndDestroy(*msg);
+ }
+ }
+
+ TSglQueIter<CRemConMessage> deliveredIter = IncomingDelivered().SetToFirst();
+
+ while ((msg = deliveredIter++) != NULL)
+ {
+ if (msg->TransactionId() == aTransactionId)
+ {
+ IncomingDelivered().RemoveAndDestroy(*msg);
+ }
+ }
+ ASSERT_DEBUG(iMessageRecipientsList);
+ iMessageRecipientsList->RemoveAndDestroyMessage(aTransactionId);
+ }
+
+TClientInfo* CRemConServer::ClientIdToClientInfo(TRemConClientId aId)
+ {
+ TClientInfo* clientInfo = NULL;
+
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const sess = iSessions[ii];
+ ASSERT_DEBUG(sess);
+ if (sess->Id() == aId)
+ {
+ clientInfo = &sess->ClientInfo();
+ break;
+ }
+ }
+ iSessionsLock.Signal();
+
+ return clientInfo;
+ }
+
+TInt CRemConServer::SupportedInterfaces(const TRemConClientId& aId, RArray<TUid>& aUids)
+ {
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const sess = iSessions[ii];
+ ASSERT_DEBUG(sess);
+ if (sess->Id() == aId)
+ {
+ iSessionsLock.Signal();
+ return sess->SupportedInterfaces(aUids);
+ }
+ }
+ iSessionsLock.Signal();
+
+ return KErrNotFound;
+ }
+
+TInt CRemConServer::SupportedOperations(const TRemConClientId& aId, TUid aInterfaceUid, RArray<TUint>& aOperations)
+ {
+ iSessionsLock.Wait();
+ const TUint count = iSessions.Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConSession* const sess = iSessions[ii];
+ ASSERT_DEBUG(sess);
+ if (sess->Id() == aId)
+ {
+ iSessionsLock.Signal();
+ return sess->SupportedOperations(aInterfaceUid, aOperations);
+ }
+ }
+ iSessionsLock.Signal();
+
+ return KErrNotFound;
+ }
+
+void CRemConServer::SetRemoteAddressedClient(const TUid& aBearerUid, const TRemConClientId& aId)
+ {
+ LOG_FUNC
+
+ TClientInfo* clientInfo = ClientIdToClientInfo(aId);
+ // Bearer must supply valid client id
+ ASSERT_DEBUG(clientInfo);
+
+ ASSERT_DEBUG(iTspIf4);
+ iTspIf4->SetRemoteAddressedClient(aBearerUid, *clientInfo);
+ }
+
+TRemConClientId CRemConServer::ClientIdByProcessId(TProcessId aProcessId)
+ {
+ LOG_FUNC
+ TRemConClientId ret = KNullClientId;
+ iSessionsLock.Wait();
+ CRemConSession* session = TargetSession(aProcessId);
+ if(session)
+ {
+ ret = session->Id();
+ }
+ iSessionsLock.Signal();
+ return ret;
+ }
+
+void CRemConServer::BulkInterfacesForClientL(TRemConClientId aId, RArray<TUid>& aUids)
+ {
+ LOG_FUNC
+ iSessionsLock.Wait();
+ CleanupSignalPushL(iSessionsLock);
+ CRemConSession* session = Session(aId);
+ if(!session)
+ {
+ LEAVEL(KErrNotFound);
+ }
+ LEAVEIFERRORL(session->SupportedBulkInterfaces(aUids));
+ CleanupStack::PopAndDestroy(&iSessionsLock);
+ }
+
+
+// Helper Active Objects
+
+CBulkThreadWatcher::CBulkThreadWatcher(CRemConServer& aServer)
+ : CActive(CActive::EPriorityStandard)
+ , iServer(aServer)
+ {
+ LOG_FUNC;
+ }
+
+CBulkThreadWatcher::~CBulkThreadWatcher()
+ {
+ LOG_FUNC;
+ Cancel();
+ }
+
+void CBulkThreadWatcher::StartL()
+ {
+ LOG_FUNC;
+ // Add to scheduler jit
+ CActiveScheduler::Add(this);
+ iServer.iBulkServerThread.Logon(iStatus);
+ if(iStatus.Int() == KErrNoMemory)
+ {
+ User::WaitForRequest(iStatus); // swallow the signal...
+ // if no memory then we have to fail now otherwise
+ // we are in an odd state where we don't know if the
+ // bulk thread is running or not.
+ LEAVEL(KErrNoMemory);
+ }
+ else
+ {
+ // Otherwise the request is handled by the active scheduler.
+ SetActive();
+ }
+ }
+
+void CBulkThreadWatcher::RunL()
+ {
+ LOG_FUNC;
+ LOG1(_L("\tiStatus.Int() = %d"), iStatus.Int());
+ // Thread is dead so kill handle.
+ iServer.iBulkServerThread.Close();
+ iServer.iBulkThreadOpen = EFalse;
+ iServer.StartShutdownTimerIfNoSessionsOrBulkThread();
+ iServer.iBulkThreadWatcher = NULL;
+ delete this; // end...
+ }
+
+void CBulkThreadWatcher::DoCancel()
+ {
+ LOG_FUNC;
+ iServer.iBulkServerThread.LogonCancel(iStatus);
+ }
+