serialserver/c32serialserver/SCOMM/CS_SES.CPP
changeset 0 dfb7c4ff071f
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 
       
    17 /** @file
       
    18  *
       
    19  * Implements CCommSession, CCommSubSession
       
    20  */
       
    21 
       
    22 #include "CS_STD.H"
       
    23 #include "C32LOG.H"
       
    24 #include "cs_thread.h"
       
    25 #include "cs_roles.h"
       
    26 #include "cs_msgs.h"
       
    27 #include "cs_glob.h"
       
    28 #include <comms-infras/c32startcli.h>
       
    29 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    30 #include <c32comm_internal.h>
       
    31 #endif
       
    32 
       
    33 
       
    34 class CCommSubSession;
       
    35 
       
    36 void PanicClient(TInt aPanic, const RMessagePtr2& aMessage)
       
    37 	{
       
    38 	if(aMessage.Handle() != 0)
       
    39 		{
       
    40 		aMessage.Panic(KCommServerName(), aPanic);
       
    41 		}
       
    42 	}
       
    43 
       
    44 
       
    45 
       
    46 
       
    47 
       
    48 
       
    49 TWorkerId CCommSession::WorkerId() const
       
    50 	{
       
    51 	return Dealer().WorkerId();
       
    52 	}
       
    53 
       
    54 
       
    55 /**
       
    56 @param aMessage IPC message received from client.
       
    57 @param aSubSess Subsession that needs to deal with this message.
       
    58 */
       
    59 void CCommSession::ForwardMessageL(const RMessage2 &aMessage, CCommSubSession& aSubSess)
       
    60 	{
       
    61 	ForwardMessageL(aMessage, &aSubSess, aSubSess.Player().WorkerId());
       
    62 	}
       
    63 
       
    64 /** Determine whether to deal with message directly or to send it on a channel.
       
    65 @param aMessage IPC message received from client.
       
    66 @param aWorkerId Id of worker that can handle this message.
       
    67 */
       
    68 void CCommSession::ForwardMessageL(const RMessage2& aMessage, CCommSubSession* aSS, TWorkerId aWorker)
       
    69 	{
       
    70 	ASSERT(aWorker <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId);
       
    71 
       
    72 	CC32WorkerThread& owner = C32WorkerThread();
       
    73 
       
    74 	/**
       
    75 	While forwarding the message to player, Add player to disconnect list. While closing the session
       
    76 	the disconnect list is used and session close message is forwarded to player. Only when session
       
    77 	close response is received, the session is destroyed.
       
    78 	*/
       
    79 	// If the Player is co-resident in this worker thread
       
    80 	if(owner.WorkerId()==aWorker)
       
    81 		{
       
    82 		AddPlayerToDisconnectList(aWorker);
       
    83 		owner.Player()->ProcessMessageL(aMessage, aSS);
       
    84 		DontCompleteCurrentRequest();
       
    85 		}
       
    86 	else if(owner.PeerReachable(aWorker))	// Forward to Player thread
       
    87 		{
       
    88 		AddPlayerToDisconnectList(aWorker);
       
    89 		TC32PlayerForwardRequestMsg msg(aMessage, aSS);
       
    90 		owner.PostMessage(aWorker, msg);
       
    91 		DontCompleteCurrentRequest();
       
    92 		const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage);
       
    93 		forwardedMsg.NullHandle();
       
    94 		}
       
    95 	else
       
    96 		{
       
    97 		C32LOG1(KC32Warning, _L8("CCommSession::ForwardMessageL() Peer Thread Unreachable"));
       
    98 		DontCompleteCurrentRequest();
       
    99 		__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker));
       
   100 		}
       
   101 	}
       
   102 
       
   103 void CCommSession::ServiceError(const RMessage2& aMessage, TInt aError)
       
   104 	{
       
   105 	if (aError==KErrBadDescriptor)
       
   106 		{
       
   107 		// this completes message as well so we have to handle it in ServiceL
       
   108 		PanicClient(EBadDescriptor,aMessage);
       
   109 		return;
       
   110 		}
       
   111 	C32LOG1(KC32Detail, _L8("CCommSession::ServiceError() ServiceL leave occured"));
       
   112 	inherited::ServiceError(aMessage,aError);
       
   113 	}
       
   114 
       
   115 void CCommSession::ServiceL(const RMessage2& aMessage)
       
   116 /**
       
   117  * Handle messages for this session.
       
   118  *
       
   119  * @param aMessage handle to the IPC message from the client
       
   120  */
       
   121 	{
       
   122 	C32LOG5(KC32Detail,_L8("CCommSession::ServiceL(), Session : 0x%x, IPC: %d (%S). Message: %08x"), this, aMessage.Function(), &TC32Log::C32RequestStr(aMessage.Function()),aMessage.Handle());
       
   123 	iComplete = ETrue;
       
   124 	const CC32WorkerThread& owner=C32WorkerThread();
       
   125 	CC32Dealer& c32Dealer = owner.DealerByRef();
       
   126 
       
   127 	if (c32Dealer.StartupFailed())
       
   128 		{
       
   129 		SafeComplete(aMessage, KErrNotReady);
       
   130 		return;
       
   131 		}
       
   132 
       
   133 	// TestImmediateShutdownPresent is only set when EImmediate shutdown is present, which is
       
   134 	// used only in testing phase.
       
   135 	if(c32Dealer.TestImmediateShutdownPresent())
       
   136 		{
       
   137 		User::Leave(KErrServerTerminated);
       
   138 		}
       
   139 
       
   140 	if((aMessage.Function()==ECommOpen)
       
   141 	   ||
       
   142 	   (aMessage.Function()==ECommOpenWhenAvailable))
       
   143 		{
       
   144 		NewPortL(aMessage);
       
   145 		return;
       
   146 		}
       
   147 
       
   148 #if defined (_DEBUG)
       
   149 	switch (aMessage.Function())
       
   150 		{
       
   151 		case ECommDbgMarkHeap:
       
   152 			__UHEAP_MARK;
       
   153 			SafeComplete(aMessage, KErrNone);
       
   154 			return;
       
   155 		case ECommDbgCheckHeap:
       
   156 			__UHEAP_CHECK(aMessage.Int0());
       
   157 			SafeComplete(aMessage, KErrNone);
       
   158 			return;
       
   159 		case ECommDbgMarkEnd:
       
   160 			__UHEAP_MARKENDC(aMessage.Int0());
       
   161 			SafeComplete(aMessage, KErrNone);
       
   162 			return;
       
   163 		case ECommDbgFailNext:
       
   164   			// We set the fail point for all heaps, rather than just the current Dealer. This could lead to a failure not related
       
   165   			// directly to whatever the client test code is trying to exercise but it all helps find bugs
       
   166   			c32Dealer.SetFailNextForAllHeaps(aMessage.Int0());
       
   167 			SafeComplete(aMessage, KErrNone);
       
   168 			return;
       
   169 		}
       
   170 #endif
       
   171 
       
   172 
       
   173 	switch ((aMessage.Function()))
       
   174 		{
       
   175 		case ECommLoadCommModule:
       
   176 			{
       
   177 			TFileName fullCSYFilename;
       
   178 			TInt ret = Read(0,aMessage,fullCSYFilename);
       
   179 			if (ret != KErrNone)
       
   180 				{
       
   181 				C32LOG2(KC32Warning, _L8("ServiceL: LoadCommModule  Read returned %d instead of KErrNone, cannot proceed"), ret);
       
   182 				PanicClient(EBadDescriptor,aMessage);
       
   183 				return;
       
   184 				}
       
   185 
       
   186 			ret = AddCSYExtension(fullCSYFilename,aMessage);
       
   187 			if(ret != KErrNone)
       
   188 				{
       
   189 				C32LOG2(KC32Warning, _L8("ServiceL: LoadCommModule AddCSYExtension returned %d instead of KErrNone, cannot proceed"), ret);
       
   190 				return;
       
   191 				}
       
   192 
       
   193  		 	CommsFW::TWorkerId worker;
       
   194 	 		TBuf8<KMaxFileName> fileName8;
       
   195 			fileName8.Copy(fullCSYFilename);
       
   196 
       
   197  		    TBool found = iThreadManager->FindThreadByFileName(fileName8, worker);
       
   198 	 		if(!found)
       
   199 		 		{
       
   200 		 		worker = iThreadManager->iDefaultThreadIndex;
       
   201 		 		}
       
   202 
       
   203  		 	if(c32Dealer.WorkerExists(worker))
       
   204  		 		{
       
   205  		 		LoadCommModuleL(aMessage,worker,!found,fullCSYFilename);
       
   206  		 		}
       
   207  		 	else
       
   208  		 		{
       
   209 				C32LOG2(KC32Dealer,_L8("ServiceL: LoadCommModule requires worker %d. This worker does not exist so starting"),worker);
       
   210  		 		ret = c32Dealer.LoadCPMOnLoadCommModule(worker);
       
   211  		 		if ((ret!=KErrNone) && (ret!=KErrInUse))
       
   212  		 			{
       
   213  		 			// only likely return codes here are KErrNoMemory or KErrNotFound if
       
   214  		 			// the RS server could not be found - which means system is probably in pretty bad state (ie, no memory)
       
   215  		 			// luckily at this point there isn't anything to clean up!
       
   216  		 			SafeComplete(aMessage,ret);
       
   217  		 			}
       
   218  		 		else
       
   219  		 			{
       
   220 	 		 		ret = c32Dealer.ParkRequest(this, aMessage);
       
   221 	 		 		if(ret != KErrNone)
       
   222 	 		 			{
       
   223 	 		 			SafeComplete(aMessage, ret);
       
   224 	 		 			}
       
   225  		 			}
       
   226  		 		}
       
   227  		 	return;
       
   228  		 	}
       
   229 		case ECommCloseCommModule:
       
   230 			CloseCommModuleL(aMessage);
       
   231 			return;
       
   232 		case ECommPortInfoByName:
       
   233 			{
       
   234 			TPortName name;
       
   235 			TInt ret = Read(1,aMessage,name);
       
   236 			if (ret != KErrNone)
       
   237 				{
       
   238 				C32LOG2(KC32Warning, _L8("ServiceL: LoadCommModule  Read returned %d instead of KErrNone, cannot proceed"), ret);
       
   239 				PanicClient(EBadDescriptor,aMessage);
       
   240 				return;
       
   241 				}
       
   242 			PortInfoL(aMessage,name);
       
   243 			return;
       
   244 			}
       
   245 		case ECommPortInfoByNumber:		// original msg is not forwarded as global as aMessage.Int2() is not valid in player, instead CSerial* is wrapped in TC32PlayerGetPortInfoMsg
       
   246 			PortInfo(aMessage,aMessage.Int2());
       
   247 			return;
       
   248 		case ECommNumPorts:				// get information from ThreadManager in dealer
       
   249 			NumPorts(aMessage);
       
   250 			return;
       
   251 		case ECommStartServerThread:	// KErrNotSupported
       
   252 			C32LOG2(KC32Dealer, _L8("WARNING: deprecated function ECommStartServerThread called, CCommSession(%08x)"), this);
       
   253 			SafeComplete(aMessage, KErrNotSupported);
       
   254 			return;
       
   255 		}
       
   256 
       
   257 	// obtain subsession* from aMessage.Int3()
       
   258 	CCommSubSession *p = SubSessionFromHandle(aMessage.Int3(), CCommSubSession::ECPort);
       
   259 
       
   260 	if (aMessage.Function()==ECommClose)
       
   261 		{
       
   262 		if (p==NULL)	// not a valid aMessage.Int3()
       
   263 			{
       
   264 			SafeComplete(aMessage, KErrBadHandle);
       
   265 			return;
       
   266 			}
       
   267 		else
       
   268 			{
       
   269 			CloseSubSessionL(aMessage, CCommSubSession::ECPort);
       
   270 			return;
       
   271 			}
       
   272 		}
       
   273 
       
   274 	if (p==NULL)	// not a valid aMessage.Int3()
       
   275 		{
       
   276 		PanicClient(EBadCommHandle, aMessage);
       
   277 		return;
       
   278 		}
       
   279 
       
   280 	// Its OK to proceed with the dispatch of other requests
       
   281 	switch (aMessage.Function())
       
   282         {
       
   283 	    case ECommRead:
       
   284 		case ECommReadCancel:
       
   285 		case ECommQueryReceiveBuffer:
       
   286 		case ECommResetBuffers:
       
   287 		case ECommWrite:
       
   288 		case ECommWriteCancel:
       
   289 		case ECommBreak:
       
   290 		case ECommBreakCancel:
       
   291 		case ECommCancel:
       
   292 		case ECommConfig:
       
   293 		case ECommSetConfig:
       
   294 		case ECommCaps:
       
   295 		case ECommSetMode:
       
   296 		case ECommGetMode:
       
   297 		case ECommSignals:
       
   298 		case ECommSetSignalsToMark:
       
   299 		case ECommSetSignalsToSpace:
       
   300 		case ECommReceiveBufferLength:
       
   301 		case ECommSetReceiveBufferLength:
       
   302 		case ECommSetAccess:
       
   303 		case ECommOpenWhenAvailableCancel:
       
   304 	#ifdef _DEBUG
       
   305 		case ECommDebugState:
       
   306 	#endif
       
   307 
       
   308 		// Extensions to the CCommSession starts from here
       
   309 
       
   310 		case ECommNotifySignals:
       
   311 		case ECommNotifyFlowControl:
       
   312 		case ECommNotifySignalsCancel:
       
   313 		case ECommNotifyFlowControlCancel:
       
   314 		case ECommGetFlowControl:
       
   315 		case ECommNotifyConfigChange:
       
   316 		case ECommNotifyConfigChangeCancel:
       
   317 		case ECommNotifyBreak:
       
   318 		case ECommNotifyBreakCancel:
       
   319 		case ECommGetRole:
       
   320 		case ECommNotifyDataAvailable:
       
   321 		case ECommNotifyDataAvailableCancel:
       
   322 		case ECommNotifyOutputEmpty:
       
   323 		case ECommNotifyOutputEmptyCancel:
       
   324 			ForwardMessageL(aMessage, *p);
       
   325 			break;
       
   326 
       
   327 		// Extensions to the CCommSession ends to here
       
   328 
       
   329 		default:
       
   330 			SafeComplete(aMessage, KErrNotSupported);
       
   331 			break;
       
   332 
       
   333 		}
       
   334 	C32LOG(KC32Detail,_L8("CCommSession::ServiceL() end"));
       
   335 	}
       
   336 
       
   337 TInt CCommSession::DisconnectPlayers()
       
   338 	{
       
   339 	return iDisconnectPlayers;
       
   340 	}
       
   341 
       
   342 CCommSubSession* CCommSession::SubSessionFromHandle(TUint aHandle, CCommSubSession::TSubSessionType aType) const
       
   343     {
       
   344 	iSubSessions.Lock();
       
   345 	CCommSubSession* subSess = iSubSessions.At(aHandle, aType);
       
   346 	iSubSessions.Unlock();
       
   347 	return subSess;
       
   348 	}
       
   349 
       
   350 CCommSession::CC32SessionCloseTimer::CC32SessionCloseTimer(CCommSession* aSession)
       
   351 : CTimer(EPriorityLow),
       
   352   iSession(aSession)
       
   353 	{
       
   354 	}
       
   355 
       
   356 CCommSession::CC32SessionCloseTimer* CCommSession::CC32SessionCloseTimer::NewL(CCommSession* aSession)
       
   357 	{
       
   358 	CC32SessionCloseTimer* self = new (ELeave) CCommSession::CC32SessionCloseTimer(aSession);
       
   359 	CleanupStack::PushL(self);
       
   360 	self->ConstructL();
       
   361 	CleanupStack::Pop(self);
       
   362 	return self;
       
   363 	}
       
   364 
       
   365 void CCommSession::CC32SessionCloseTimer::Start()
       
   366 	{
       
   367 	CActiveScheduler::Add(this);
       
   368 	After(KC32SessionCloseDelay);
       
   369 	}
       
   370 
       
   371 void CCommSession::CC32SessionCloseTimer::RunL()
       
   372 	{
       
   373 	Deque();
       
   374 	if(iStatus == KErrNone)
       
   375 		{
       
   376 		C32LOG3(KC32Detail, _L8("CCommSession::CC32SessionCloseTimer::RunL session = %08x, DisconnectList = %08x. Will panic in debug."), iSession,	iSession->DisconnectPlayers());
       
   377 
       
   378 		// After sending a sessionclose message to the player the timeout is set and it is in the order
       
   379 		// of seconds. IF the player doesn't respond (may be unloaded during shutdown, see below comment
       
   380 		// about stackable csy) and we get to this place, it is a defect and we'd like to catch that in
       
   381 		// debug mode.
       
   382 
       
   383 		// NOTE FOR STACKABLE CSY WRITERS
       
   384 		// The session from csy loading another csy was not closed properly and hence when shutdown was
       
   385 		// commanded, player CPMs unload, while the session remains. When EDisconnect message is received
       
   386 		// by the comms server from kernel, session close message is sent to player CPM which has already
       
   387 		// been unloaded and thus this timer expires. Ensure that all sessions from within csy is closed
       
   388 		// before shutdown is called
       
   389 
       
   390 		ASSERT(0);
       
   391 
       
   392 		CC32Dealer* dealer = const_cast<CC32Dealer*>(&iSession->Dealer());
       
   393 		dealer->DeleteSession(iSession);
       
   394 		}
       
   395 	}
       
   396 
       
   397 void CCommSession::AddPlayerToDisconnectList(TWorkerId aPlayerId)
       
   398 	{
       
   399 	__ASSERT_COMPILE(TC32WorkerThreadPublicInfo::EMaxWorkerThreadId < 32);	// Using a TUint32 as a flag container
       
   400 	ASSERT(aPlayerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId);
       
   401 	__FLOG_STMT(
       
   402 		if(!IsPlayerInDisconnectList(aPlayerId))
       
   403 			{
       
   404 			C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tAddPlayerToDisconnectList(%d)"), this, aPlayerId );
       
   405 			}
       
   406 		)
       
   407 	iDisconnectPlayers |= (1 << aPlayerId);
       
   408 	}
       
   409 
       
   410 void CCommSession::RemovePlayerFromDisconnectList(TWorkerId aPlayerId)
       
   411 	{
       
   412 	ASSERT(aPlayerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId);
       
   413 	__FLOG_STMT(
       
   414 		if(IsPlayerInDisconnectList(aPlayerId))
       
   415 			{
       
   416 			C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tRemovePlayerFromDisconnectList(%d)"), this, aPlayerId );
       
   417 			}
       
   418 		)
       
   419 	iDisconnectPlayers &= ~(1 << aPlayerId);
       
   420 	}
       
   421 
       
   422 TBool CCommSession::IsDisconnectListEmpty() const
       
   423 	{
       
   424 	C32LOG2(KC32Detail, _L8("CCommSession::IsDisconnectListEmpty %d "), iDisconnectPlayers );
       
   425 	return iDisconnectPlayers == 0;
       
   426 	}
       
   427 
       
   428 TBool CCommSession::IsPlayerInDisconnectList(TWorkerId aPlayerId) const
       
   429 	{
       
   430 	// A potential optimisation for the future would be to actively check whether the player still has subsessions here, rather
       
   431 	// than blinding sending the session close message
       
   432 	ASSERT(aPlayerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId);
       
   433 	return iDisconnectPlayers & (1 << aPlayerId);
       
   434 	}
       
   435 
       
   436 void CCommSession::ForgetSubSession(CCommSession* aSelf, CCommSubSession* aSubSession, TInt aSubSessionHandle, TAny*)
       
   437 	{
       
   438 	(void) aSubSession;	// suppress UREL warnings
       
   439 	VERIFY_RESULT(aSelf->iSubSessions.Remove(aSubSessionHandle), aSubSession);
       
   440 	}
       
   441 
       
   442 void CCommSession::CountSubSessions(CCommSession*, CCommSubSession*, TInt, TAny* aArg)
       
   443 	{
       
   444 	TInt* counter = reinterpret_cast<TInt*>(aArg);
       
   445 	++*counter;
       
   446 	}
       
   447 
       
   448 CCommSession::CCommSession(CC32ThreadManager* aThreadManager)
       
   449 /**
       
   450  * C'Tor - must pass client to CSession
       
   451  *
       
   452  * @param aClient handle to the Clients thread
       
   453  * @param aPortManager pointer to th port manager
       
   454  */
       
   455 	:CSession2(),
       
   456 	iThreadManager(aThreadManager)
       
   457 	{
       
   458 	C32GlobalUtil::NewSession();		// increment iNumSessions
       
   459 	C32LOG1(KC32Detail, _L8("CCommSession::CCommSession()"));
       
   460 	}
       
   461 
       
   462 CCommSession* CCommSession::NewL(CC32ThreadManager* aThreadManager)
       
   463 	{
       
   464 	CCommSession* self = new (ELeave) CCommSession(aThreadManager);
       
   465 	CleanupStack::PushL(self);
       
   466 	self->ConstructL();
       
   467 	CleanupStack::Pop(self);
       
   468 	return self;
       
   469 	}
       
   470 
       
   471 void CCommSession::ConstructL()
       
   472 	{
       
   473 	iSessionCloseTimer = CCommSession::CC32SessionCloseTimer::NewL(this);
       
   474 	iSubSessions.InitialiseL();			// initialise CC32SubSessionIx
       
   475 	}
       
   476 
       
   477 void CCommSession::CloseSubSessionL(const RMessage2& aMessage, CCommSubSession::TSubSessionType aType)
       
   478 	{
       
   479 	iSubSessions.Lock();
       
   480 	CCommSubSession* subSess = iSubSessions.At(aMessage.Int3(), aType);
       
   481 	C32LOG5(KC32Detail, _L8("CCommSession(%08x):\tCloseSubSession(%08x, %d) - subSess %08x"), this, aMessage.Int3(), aType, subSess);
       
   482 	ASSERT(subSess);
       
   483 	iSubSessions.Unlock();
       
   484 	ForwardMessageL(aMessage, *subSess);
       
   485 	}
       
   486 
       
   487 TInt CCommSession::AddCSYToSessionL(const TDesC& aCSYFileName, TBool& aIsDuplicate)
       
   488 	{
       
   489 	aIsDuplicate=EFalse;
       
   490 
       
   491 	TInt k = 0;
       
   492 	while (k < iCsyCon.Count() && !aIsDuplicate)
       
   493 		{
       
   494 		if (aCSYFileName.CompareF(*iCsyCon[k])==0)
       
   495 			{
       
   496 			aIsDuplicate=ETrue;
       
   497 			}
       
   498 		k++;
       
   499 		}
       
   500 
       
   501 	HBufC* name = aCSYFileName.AllocL();
       
   502 	return iCsyCon.Append(name);
       
   503 	}
       
   504 
       
   505 TInt CCommSession::RemoveCSYFromSession(const TDesC& aCSYFileName, TBool& aIsLast)
       
   506 	{
       
   507 	TBool aFound=EFalse;
       
   508 	TInt k = 0;
       
   509 	while (k < iCsyCon.Count())
       
   510 		{
       
   511 		if (iCsyCon[k]->CompareF(aCSYFileName)==0)
       
   512 			{
       
   513             // coverity [dead_error_condition] aFound can be true on later iterations of the while loop
       
   514             if (aFound)
       
   515 				{
       
   516 				aIsLast=EFalse;
       
   517 				}
       
   518 			else
       
   519 				{
       
   520 				delete iCsyCon[k];
       
   521 				iCsyCon.Remove(k);
       
   522 				aIsLast=ETrue;
       
   523 				aFound=ETrue;
       
   524 				return KErrNone;
       
   525 				}
       
   526 			}
       
   527 		k++;
       
   528 		}
       
   529 	return KErrNotFound;
       
   530 	}
       
   531 
       
   532 CC32WorkerThread& CCommSession::C32WorkerThread() const
       
   533 	{
       
   534 	return Dealer().WorkerThread();
       
   535 	}
       
   536 
       
   537 void CCommSession::LoadCommModuleL(const RMessage2& aMessage, CommsFW::TWorkerId aWorker, TBool aDefaulted, const TDesC& aFilename)
       
   538 /**
       
   539  Load a comm module
       
   540  We assume that the worker we need is loaded if we've come this far.
       
   541  aFilename - full filename of CSY
       
   542  aDefaulted - True if the supplied filename is for a CSY that is not known via CSYList values in CMI file.
       
   543  In this case aWorker will be the default thread
       
   544  */
       
   545 	{
       
   546 	TBool isDuplicate;		// used both for AddCSYToSessionL and RemoveCSYFromSession (where it is used as isLast)
       
   547 	TInt ret;
       
   548 	// Add csy to session, if present we still add csyfilename to session CSY container to keep accesscount but do not
       
   549 	// forward message, (preserve legacy behaviour where c32 allowed multiple load attempts with KErrNone)
       
   550 	ret = AddCSYToSessionL(aFilename,isDuplicate);
       
   551 	if(ret != KErrNone)
       
   552 		{
       
   553 		C32LOG2(KC32Warning,_L8("CCommSession::LoadCommModuleL() failed to append CSY to csy container returned %d "), ret);
       
   554 		SafeComplete(aMessage, ret);
       
   555 		return;
       
   556 		}
       
   557 	// if no memory, or other error, return as such to client
       
   558 	if (isDuplicate)
       
   559 		{
       
   560 		ret = iThreadManager->IncrementCountOnLoad(aFilename);	// increment count for multiple load attempt
       
   561 		__ASSERT_DEBUG(ret == KErrNone, Fault(EBadState,_L("CCommSession::LoadCommModuleL(): duplicate entry of CSY but not found in Thread Manager !")));
       
   562 		SafeComplete(aMessage,KErrNone);
       
   563 		}
       
   564 	else
       
   565 		{
       
   566 		if (aDefaulted)
       
   567 			{
       
   568 			C32LOG2(KC32Dealer,_L("CCommSession::LoadCommModuleL(): CSY (%S) not found in Threadmanager so adding"),&aFilename);
       
   569 			// add csy record since it is unknown, probably after-marked csy
       
   570 			TBuf8<KMaxFileName> fileName8;   // huge stack usage, but no other way
       
   571 			fileName8.Copy(aFilename);
       
   572 
       
   573 			CCSYInfo* csyPtr = NULL;
       
   574 			TRAP(ret,csyPtr = CCSYInfo::NewL(fileName8, aWorker));
       
   575 			if (ret==KErrNone)
       
   576 				{
       
   577 				ret = iThreadManager->iCSYList.Append(csyPtr);
       
   578 				if (ret!=KErrNone)
       
   579 					{
       
   580 					// failed to add so undo and abort
       
   581 					delete csyPtr;
       
   582 					(void)RemoveCSYFromSession(aFilename,isDuplicate);
       
   583 					SafeComplete(aMessage,ret);
       
   584 					return;
       
   585 					}
       
   586 				}
       
   587             else
       
   588 				{
       
   589 				// probably OOM
       
   590 				(void)RemoveCSYFromSession(aFilename,isDuplicate);
       
   591 				SafeComplete(aMessage,ret);
       
   592 				return;
       
   593 				}
       
   594 			}
       
   595 
       
   596 		// if this module hasn't been loaded before, it won't have had its portname set. As
       
   597 		// the portname could be quite long we need to allocate it now to its max size
       
   598 		// since we can't afford to run out of memory after player responds with the portname after load.
       
   599 
       
   600 		ret = iThreadManager->GrowCSYPortNameToMaximumIfNotLoaded(aFilename);
       
   601 
       
   602 		if (ret == KErrNoMemory)
       
   603 			{
       
   604 			C32LOG2(KC32Dealer,_L("CCommSession::LoadCommModuleL(): CSY (%S).Ran out of memory growing portname - cleaning up"),&aFilename);
       
   605 			(void)RemoveCSYFromSession(aFilename,isDuplicate);
       
   606 			if (aDefaulted)
       
   607 				{
       
   608 				C32LOG3(KC32Dealer,_L("CCommSession::LoadCommModuleL(): CSY (%S), cleanup for abort: This was a newly-added default record (at index %d), so deleting"),&aFilename,iThreadManager->iCSYList.Count()-1);
       
   609 				// we just appended csy record, so remove it
       
   610 				delete iThreadManager->iCSYList[iThreadManager->iCSYList.Count()-1];
       
   611 				iThreadManager->iCSYList.Remove(iThreadManager->iCSYList.Count()-1);
       
   612 				}
       
   613 			SafeComplete(aMessage,ret);
       
   614 			return;
       
   615 			}
       
   616 		else
       
   617 			{
       
   618 			__ASSERT_DEBUG(ret==KErrNone,Fault(EBadState,_L("CCommSession::LoadCommModuleL(): Panicking due to failure to grow CSY portname for unexpected reason: %d" ),ret));
       
   619 			}
       
   620 
       
   621 
       
   622 		// entry for unlisted CSY created now, increment count for this CSY, count as in number of times its loaded
       
   623 		ret = iThreadManager->IncrementCountOnLoad(aFilename);
       
   624 		__ASSERT_DEBUG(ret==KErrNone,Fault(EBadState,_L("CCommSession::LoadCommModuleL(): Panicking due to failure to increment count for CSY: %d" ),ret));
       
   625 
       
   626 		// send Message to player
       
   627 		CC32WorkerThread& owner = C32WorkerThread();
       
   628 		if(aWorker==TC32WorkerThreadPublicInfo::EMainThread)
       
   629 			{
       
   630 			// co-resident player, make direct function call, avoid ProcessMessageL(), as aMessage.Int2() points to global index
       
   631 			AddPlayerToDisconnectList(aWorker);
       
   632 			owner.Player()->LoadCommModule(aMessage);
       
   633 			DontCompleteCurrentRequest();
       
   634 			}
       
   635 		else if (owner.PeerReachable(aWorker))
       
   636 			{
       
   637 			// send the message via transports wrapped in TC32PlayerLoadCommModuleMsg
       
   638 			AddPlayerToDisconnectList(aWorker);
       
   639 			TC32PlayerLoadCommModuleMsg respMsg(aMessage);
       
   640 			owner.PostMessage(aWorker, respMsg);
       
   641 			DontCompleteCurrentRequest();
       
   642 			const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage);
       
   643 			forwardedMsg.NullHandle();
       
   644 			}
       
   645 		else
       
   646 			{
       
   647 			C32LOG2(KC32Warning,_L8("CCommSession::LoadCommModuleL() Peer Thread Unreachable.  RMessage2& = %08x. Will panic in debug"), aMessage.Handle());
       
   648 			DontCompleteCurrentRequest();
       
   649 			__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker));
       
   650 			}
       
   651 
       
   652 		}
       
   653 	}
       
   654 
       
   655 void CCommSession::SafeComplete(const RMessagePtr2& aMessage, TInt aCompletionCode)
       
   656 	{
       
   657 	if(iComplete)
       
   658 		{
       
   659 		::SafeComplete(aMessage, aCompletionCode);
       
   660 		}
       
   661 	}
       
   662 
       
   663 void CCommSession::DontCompleteCurrentRequest()
       
   664 	{
       
   665 	iComplete = EFalse;
       
   666 	}
       
   667 
       
   668 void CCommSession::CloseCommModuleL(const RMessage2& aMessage)
       
   669 /**
       
   670  * Close a comm module
       
   671  */
       
   672 	{
       
   673 	TFullName name;      // not a TPortName for backwards compat reasons
       
   674 	Read(0,aMessage,name);
       
   675 
       
   676 	TFileName csyfilename;
       
   677 	TInt ret = iThreadManager->MapPortprefixToCSYFileName(name, csyfilename);	// fill csyfilename
       
   678 	if (ret!=KErrNone)
       
   679 		{
       
   680 		SafeComplete(aMessage, KErrNotFound);
       
   681 		return;
       
   682 		}
       
   683 
       
   684 	TBool isLast;
       
   685 	TInt res = RemoveCSYFromSession(csyfilename,isLast);	// can return either KErrNone or KErrNotFound in case when csy is not found listed
       
   686 
       
   687 	if (res==KErrNone)
       
   688 		{
       
   689 		// decrement the LoadCount for CSY
       
   690 		iThreadManager->DecrementCountOnCSYUnLoad(csyfilename);
       
   691 		if (isLast)
       
   692 			{
       
   693 			// if CSY is the last one for the session, then remove from session and forward mesage to player
       
   694 			// unload message is forwarded "per session basis", so every session sends unload message to player,
       
   695 			// if this csy was previously loaded by this session, unload message is sent to player either when
       
   696 			// unloadcommmodule is explicitly called or when session is closed
       
   697 			CommsFW::TWorkerId worker;
       
   698 	 		TBuf8<KMaxFileName> fileName8;
       
   699 			fileName8.Copy(csyfilename);
       
   700 
       
   701 			__ASSERT_ALWAYS(iThreadManager->FindThreadByFileName(fileName8,worker),Fault(EBadState)); //  find worker
       
   702 			ForwardMessageL(aMessage, NULL, worker);
       
   703 			}
       
   704 		else
       
   705 			{
       
   706 			SafeComplete(aMessage, KErrNone);
       
   707 			}
       
   708 		}
       
   709 	else
       
   710 		{
       
   711 		// old api used to just return and not panic during an attempt to unload a module not loaded
       
   712 		// so we do too, altho we log to record this unsavoury behavior
       
   713 		C32LOG(KC32Warning, _L8("CCommSession::CloseCommModuleL(), Attempt to Close an unloaded module. Continuing due to old API allowing this unadvised behavior."));
       
   714 		SafeComplete(aMessage, res);	// res = KErrNotFound
       
   715 		}
       
   716 
       
   717 	}
       
   718 
       
   719 void CCommSession::PortInfoL(const RMessage2& aMessage,const TPortName& aName)
       
   720 /**
       
   721  * Write back the port info to the client for a specified port
       
   722  *
       
   723  * @param aName name of the port/filename to get information about
       
   724  */
       
   725 	{
       
   726 	TWorkerId worker;
       
   727 	if(iThreadManager->FindThreadOfActiveCSYByName(aName, worker))
       
   728 		{
       
   729 		ForwardMessageL(aMessage, NULL, worker);
       
   730 		}
       
   731 	else
       
   732 		{
       
   733 		SafeComplete(aMessage, KErrNotFound);
       
   734 		}
       
   735 	}
       
   736 
       
   737 // PortInfo overload requires the CSerial* to be forwarded to player, as the
       
   738 // aMessage.Int2() has the global index which is not valid in player.
       
   739 void CCommSession::PortInfo(const RMessage2& aMessage,TInt aNumber)
       
   740 /**
       
   741  * Write back the port info to the client for a specified port
       
   742  * aNumber is the client supplied index of the CSY
       
   743  * @param aNumber number of the port to get information about
       
   744  */
       
   745 	{
       
   746 	// check if the aNumber is sane i.e. within the # of CSYs loaded in C32
       
   747 	if (aNumber < 0)
       
   748 		{
       
   749 		SafeComplete(aMessage,KErrArgument);
       
   750 		return;
       
   751 		}
       
   752 
       
   753 	TInt workerId = iThreadManager->FindThreadByGlobalIndex(aNumber);
       
   754 	if (workerId == KErrNotFound)
       
   755 		{
       
   756 		SafeComplete(aMessage, KErrTooBig); // preserve old API behaviour
       
   757 		}
       
   758 	else
       
   759 		{
       
   760 		CC32WorkerThread& owner = C32WorkerThread();
       
   761 		CommsFW::TWorkerId thisworker = owner.WorkerId();
       
   762 		CSerial* s = iThreadManager->FindSerialObjectByGlobalIndex(aNumber);
       
   763 		// Find Thread
       
   764 		if(workerId==thisworker)
       
   765 			{
       
   766 			// co-resident player, make direct function call, avoid ProcessMessageL(), as aMessage.Int2() points to global index
       
   767 			AddPlayerToDisconnectList(workerId);
       
   768 			owner.Player()->PortInfo(aMessage, s);
       
   769 			DontCompleteCurrentRequest();
       
   770 			}
       
   771 		else if (owner.PeerReachable(workerId))
       
   772 			{
       
   773 			// send the message via transports wrapped in TC32PlayerGetPortInfoMsg
       
   774 			C32LOG4(KC32Dealer, _L8("CCommSession::PortInfo(aNumber) Sending Peer Thread %d request for info on CSerial %x which is for CSY at active idx %d"),workerId,s,aNumber);
       
   775 			AddPlayerToDisconnectList(workerId);
       
   776 			TC32PlayerGetPortInfoMsg respMsg(aMessage, s);
       
   777 			owner.PostMessage(workerId, respMsg);
       
   778 			DontCompleteCurrentRequest();
       
   779 			const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage);
       
   780 			forwardedMsg.NullHandle();
       
   781 			}
       
   782 		else
       
   783 			{
       
   784 			C32LOG2(KC32Warning, _L8("CCommSession::PortInfo(aNumber) Peer Thread %d Unreachable. Will panic in debug."),workerId);
       
   785 			DontCompleteCurrentRequest();
       
   786 			__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker));
       
   787 			}
       
   788 		}
       
   789 	}
       
   790 
       
   791 void CCommSession::NumPorts(const RMessage2& aMessage)
       
   792 /**
       
   793  * Write back the number of CSYs loaded to the client
       
   794  */
       
   795 	{
       
   796 	// returns the number of CSYs loaded in all sessions
       
   797 	TPckgBuf<TInt> num;
       
   798 
       
   799 	TInt idx = 0;
       
   800 	TInt count = 0;
       
   801 	while (idx < iThreadManager->iCSYList.Count())
       
   802 		{
       
   803 		if (iThreadManager->iCSYList[idx]->IsLoaded())
       
   804 			{
       
   805 			count++;
       
   806 			}
       
   807 		idx++;
       
   808 		}
       
   809 
       
   810 	C32LOG2(KC32Detail, _L8("CCommSession::NumPorts = %d "), count);
       
   811 	num() = count;
       
   812 	Write(0,aMessage,num);
       
   813 	SafeComplete(aMessage, KErrNone);
       
   814 	}
       
   815 
       
   816 CCommSession::~CCommSession()
       
   817 /**
       
   818  *	D'tor - clean up and go home.
       
   819  */
       
   820 	{
       
   821 	C32LOG1(KC32Detail, _L8("CCommSession::~CCommSession()"));
       
   822 
       
   823 	delete iSessionCloseTimer;
       
   824 
       
   825 	iCsyCon.ResetAndDestroy();		// delete session CSY container
       
   826 
       
   827 	C32GlobalUtil::SessionClosing();	// decrement iNumSessions
       
   828 
       
   829 	}
       
   830 
       
   831 void CCommSession::ProcessSubSessions(TWorkerId aPeerId, TSubSessionProcessor aSubSessionProcessor, TAny* aPtr)
       
   832 	{
       
   833 	iSubSessions.Lock();
       
   834 	CC32SubSessionIx::TIter iter(iSubSessions);
       
   835 
       
   836 	CCommSubSession* ss;
       
   837 	TInt ssHandle;
       
   838 	while((ss = iter.Next(ssHandle)) != NULL)
       
   839 		{
       
   840 		if(aPeerId == TC32WorkerThreadPublicInfo::ENullWorkerId || aPeerId == ss->Player().WorkerId())
       
   841 			{
       
   842 			aSubSessionProcessor(this, ss, ssHandle, aPtr);
       
   843 			}
       
   844 		}
       
   845 	iSubSessions.Unlock();
       
   846 	}
       
   847 
       
   848 void CCommSession::NewPortL(const RMessage2& aMessage)
       
   849 /**
       
   850  * Ask the port manager to open a port in the CSY which is then added
       
   851  * to this session's port list. If another session has already opened
       
   852  * the same port, the port manager will still give us a reference if
       
   853  * the port is not being used exclusively.
       
   854  *
       
   855  * @param aMessage handle to the IPC message from the client
       
   856  */
       
   857 	{
       
   858 	C32LOG1(KC32Detail, _L8("CCommSession::NewPort()"));
       
   859 
       
   860 	TFullName name;      // not a TPortName for backwards compat reasons
       
   861 	TUint port;
       
   862 	TInt len;
       
   863 
       
   864 	TInt ret = ExtractPortNameAndNumber(aMessage, name, port, len);
       
   865 	if(ret != KErrNone)
       
   866 		{
       
   867 		C32LOG2(KC32Detail, _L8("CCommSession::NewPort() - returning KErrBadName to client. Offending portname was: %S"),&name);
       
   868         // Bad Handle, (session) dealer completes.
       
   869         // it would be nicer to complete with value of "ret", but as old C32 always completed with KErrBadName
       
   870         // it seems an easy way to reduce compatibility problems by continuing this
       
   871 		SafeComplete(aMessage, KErrBadName);
       
   872 		return;
       
   873 		}
       
   874 	else
       
   875 		{
       
   876 		// message details are valid, forward the message based on portname "COMM"
       
   877 		// lookup in ThreadManager, fails if no port-prefix found (if RComm::Open called directly without loading the CSY)
       
   878 		TWorkerId worker;
       
   879 		if(iThreadManager->FindThreadByPortPrefix(TPtrC(name.Left(len)), worker))
       
   880 			{
       
   881 			ForwardMessageL(aMessage, NULL, worker);
       
   882 			}
       
   883 		else
       
   884 			{
       
   885 			C32LOG2(KC32Dealer, _L("CCommSession::NewPort() - returning KErrNotFound to client due to no loaded CSY for supplied port: %S"),&name);
       
   886 			SafeComplete(aMessage, KErrNotFound);
       
   887 			}
       
   888 		}
       
   889 	}
       
   890 
       
   891 TInt CCommSession::ExtractPortNameAndNumber(const RMessagePtr2& aMessage, TDes& aPortName, TUint& aPortNumber, TInt& aLength)
       
   892 /**
       
   893 Extract the port name and number from RMessage
       
   894 aPortName on return is full name including double-colon and number. The length is not policed for compliance with
       
   895 TPortName type since this would break a backwards compatibility behaviour.
       
   896 aLength is length of the actual name part without the double-colon and port number.
       
   897 */
       
   898 	{
       
   899   	Read(0,aMessage, aPortName);
       
   900 
       
   901 	_LIT(KDoubleColon, "::");
       
   902 	aLength = aPortName.Find(KDoubleColon);
       
   903 	if (aLength == KErrNotFound)
       
   904 		{
       
   905 		return KErrNotFound;
       
   906 		}
       
   907 	// extract the numeric value after ::
       
   908 	TInt numPos = aLength + KDoubleColon.iTypeLength;
       
   909 	if (numPos == aPortName.Length())
       
   910 		{
       
   911 		C32LOG1(KC32Warning, _L("CCommSession::ExtractPortNameAndNumber() - no port number mentioned to open"));
       
   912 		return KErrBadName; // kerrbadname preserves old c32 return code for this function
       
   913 		}
       
   914 
       
   915 	TPtrC numPtr(&aPortName[numPos], aPortName.Length() - numPos);
       
   916 	TLex lexer(numPtr);
       
   917 	TInt ret = lexer.Val(aPortNumber);
       
   918 
       
   919 	return ret;
       
   920 	}
       
   921 
       
   922 /** Sends SessionClosed to all no-resident players. Add self to Dealers list of disconnecting sessions.
       
   923 */
       
   924 void CCommSession::Disconnect()
       
   925 	{
       
   926 	C32LOG2(KC32Detail, _L8("CCommSession(%08x):\tDisconnect()"), this );
       
   927 
       
   928 	// Remove all subsessions from the session, ie just as if the client had closed them all individually
       
   929 	ProcessSubSessions(TC32WorkerThreadPublicInfo::ENullWorkerId, ForgetSubSession, NULL);
       
   930 
       
   931 	CC32WorkerThread& owner = C32WorkerThread();
       
   932 	TWorkerId self = owner.WorkerId();
       
   933 
       
   934 	// remove any parked requests if any as this session is going down.
       
   935 	owner.Dealer()->RemoveParkedRequestsOnSessionClose(this);
       
   936 
       
   937 	// run thru our list of csys we've loaded for this session and remove each one
       
   938 	// and send thru to player to unload each one. As the list allows duplicates,
       
   939 	// we only send unload for each csy when its last ref for this session
       
   940 	for(TInt i = iCsyCon.Count() -1; i >= 0; i--)
       
   941 		{
       
   942 		// find worker
       
   943 		TWorkerId worker;
       
   944  		TBuf8<KMaxFileName> fileName8;
       
   945 		fileName8.Copy(*iCsyCon[i]);
       
   946 
       
   947 		TBool found = iThreadManager->FindThreadByFileName(fileName8, worker);	// TBool found is re-used for testing last csy in session CSY container
       
   948 		__ASSERT_DEBUG(found, Fault(EBadState,_L("CCommSession::Disconnect: Csy not found in ThreadManager !")));
       
   949 		// find CSerial object
       
   950 		CSerial* s = iThreadManager->GetSerialObjectFromCSYFileName(*iCsyCon[i]);
       
   951 #ifdef _DEBUG
       
   952 		if (s == NULL)
       
   953 			{
       
   954 #ifdef __FLOG_ACTIVE
       
   955 			iThreadManager->DumpThreadInfoAndCSYLists();
       
   956 #endif
       
   957 			TPtrC csyFilename = *iCsyCon[i];
       
   958 			Fault(EBadState,_L("CCommSession::Disconnect: CSerial not found for CSY (%S) in ThreadManager !"),&csyFilename);
       
   959 			}
       
   960 #endif
       
   961 
       
   962 		TInt res = iThreadManager->DecrementCountOnCSYUnLoad(*iCsyCon[i]);
       
   963 
       
   964 		TBool isLast;
       
   965 		res = RemoveCSYFromSession((*iCsyCon[i]), isLast);
       
   966 		// if its last entry for this csy in TCSYFileNameContainer, send the message to player
       
   967 		if(res == KErrNone)
       
   968 			{
       
   969 			if(isLast)	// last CSY in session CSY container - same TBool found re-used
       
   970 				{
       
   971 				if(worker==self)
       
   972 					{
       
   973 					// co-resident player, make direct function call, avoid ProcessMessageL(), as aMessage.Int2() points to global index
       
   974 					owner.Player()->ProcessUnLoadCommModuleMsg(s);
       
   975 					}
       
   976 				else if (owner.PeerReachable(worker))
       
   977 					{
       
   978 					// send the message via transports wrapped in TC32PlayerUnLoadCommModuleMsg
       
   979 					TC32PlayerUnLoadCommModuleMsg respMsg(s);
       
   980 					owner.PostMessage(worker, respMsg);
       
   981 					}
       
   982 				else
       
   983 					{
       
   984 					C32LOG2(KC32Warning, _L8("CCommSession::Disconnect() Peer Thread (%d) Unreachable. Will Panic in Debug"), worker);
       
   985 					__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker));
       
   986 					}
       
   987 				}
       
   988 			}
       
   989 		}
       
   990 
       
   991 	TTime time;
       
   992 	time.HomeTime();
       
   993 	time+=TTimeIntervalMicroSeconds32(KC32SessionClosePlayerDeadline);
       
   994 	for(TWorkerId player = TC32WorkerThreadPublicInfo::EMainThread; player <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId; ++player)
       
   995 		{
       
   996 		if(IsPlayerInDisconnectList(player))
       
   997 			{
       
   998 			if(player == self)
       
   999 				{
       
  1000 				RemovePlayerFromDisconnectList(player);
       
  1001 				owner.Player()->CloseSession(this);
       
  1002 				}
       
  1003 			else if(owner.PeerReachable(player))
       
  1004 				{
       
  1005 				/* Sending closed session message to involved player, dont care if it times out. After this we just wait
       
  1006 				anyway for a while and then obliterate it.*/
       
  1007 				C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tDisconnect() Sending SessionClose to W%d"), this, player);
       
  1008 				TC32PlayerSessionCloseMsg msg(this, time.Int64());
       
  1009 				owner.PostMessage(player, msg);
       
  1010 				}
       
  1011 			else
       
  1012 				{
       
  1013 				C32LOG(KC32Warning,_L8("CCommSession::Disconnect: Peer not reachable. Will panic in debug."));
       
  1014 				__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker));
       
  1015 				}
       
  1016 			}
       
  1017 		}
       
  1018 	if(!IsDisconnectListEmpty())
       
  1019 		{
       
  1020 		C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tDisconnect() Starting timer [discoList = 0x%x]"), this, iDisconnectPlayers );
       
  1021 		iSessionCloseTimer->Start();
       
  1022 		}
       
  1023 	}
       
  1024 
       
  1025 void CCommSession::Disconnect(const RMessage2& aMessage)
       
  1026 	{
       
  1027 	iDisconnectMessage = aMessage;
       
  1028 	C32LOG3(KC32Detail, _L("CCommSession(%08x):\tDisconnect(const RMessage2& = %08x)"), this, aMessage.Handle() );
       
  1029 
       
  1030 	Disconnect();
       
  1031 
       
  1032 	// If co-resident Player was only one then complete immediately
       
  1033 	if(IsDisconnectListEmpty())
       
  1034 		{
       
  1035 		C32LOG2(KC32Detail, _L8("CCommSession(%08x)::Disconnect(const RMessage2&) inherited disconnect"), this );
       
  1036 		inherited::Disconnect(aMessage);
       
  1037 		}
       
  1038 	}
       
  1039 
       
  1040 /** The player has handled the SessionClose message and has cleaned up */
       
  1041 void CCommSession::SessionCloseResp(TWorkerId aPlayerId)
       
  1042 	{
       
  1043 	RemovePlayerFromDisconnectList(aPlayerId);
       
  1044 	if(IsDisconnectListEmpty())
       
  1045 		{
       
  1046 		C32LOG2(KC32Detail, _L8("CCommSession::SessionCloseResp(%08x), Stopping the timer"),this);
       
  1047 		iSessionCloseTimer->Cancel();
       
  1048 		// Dealer()->DeleteSession(...) is called by the caller of this function after this
       
  1049 		}
       
  1050 	}
       
  1051 
       
  1052 
       
  1053 TInt CCommSession::Write(TInt aPos, const RMessagePtr2& aMessage , const TDesC8& aDes, TInt aOffset)
       
  1054 /**
       
  1055  * Write and kill the client if it leaves.
       
  1056  *
       
  1057  * Copies data from an 8 bit descriptor in the server address space to the client
       
  1058  * thread's address space. The target location must be a valid modifiable descriptor.
       
  1059  * Data is copied from the source descriptor to the specified offset position within
       
  1060  * the target descriptor data area. The length of data copied is the length of the
       
  1061  * source descriptor. The length of the target descriptor is set to the length of
       
  1062  * the source descriptor plus the value of the offset.
       
  1063  *
       
  1064  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  1065  *                The data type at this location must be a modifiable descriptor, i.e. aTDes8 type.
       
  1066  * @param aDes    An 8 bit descriptor in the server address space. This is the source of the copy operation.
       
  1067  * @param aOffset The offset from the start of the target descriptor data area where copying is to begin.
       
  1068  *                This value must be greater than or equal to zero.
       
  1069  *
       
  1070  * @panic This function will panic the client if the WriteL() leaves
       
  1071  */
       
  1072 	{
       
  1073 	//C32LOG4(KC32Detail, _L8("CCommSession::Write() Data = (%s), Pos (%d) Offset (%d)"), aDes.Ptr(), aPos, aOffset);
       
  1074 
       
  1075 	TInt ret = aMessage.Write(aPos, aDes, aOffset);
       
  1076 	if (ret!=KErrNone)
       
  1077 		{
       
  1078 		PanicClient(EBadDescriptor,aMessage);
       
  1079 		}
       
  1080 	return ret;
       
  1081 	}
       
  1082 
       
  1083 
       
  1084 TInt CCommSession::Read(TInt aPos, const RMessagePtr2& aMessage , TDes8& aDes, TInt aOffset)
       
  1085 /**
       
  1086  * Read and kill the client if it leaves.
       
  1087  *
       
  1088  * Copies data from the client thread's address space into an 8 bit descriptor
       
  1089  * in the server address space. The source data must be a valid descriptor.
       
  1090  * Data is copied from the specified offset position within the source descriptor
       
  1091  * data area. The length of data copied is the length of source descriptor data
       
  1092  * minus the offset value. If the offset value is greater than the length of the
       
  1093  * source descriptor, then no data is copied. The length of data copied is limited
       
  1094  * to the maximum length of the target descriptor.
       
  1095  *
       
  1096  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  1097  *                The data at this pointer must be a descriptor, i.e. a TDesC8 type.
       
  1098  * @param aDes    An 8 bit descriptor in the server address space. This is the target
       
  1099  *                of the copy operation.
       
  1100  * @param aOffset The offset from the start of the source descriptor data area from where
       
  1101  *                copying is to begin. This value must be greater than or equal to zero.
       
  1102  *
       
  1103  * @panic This function will panic the client if the ReadL() leaves
       
  1104  */
       
  1105 	{
       
  1106 	C32LOG3(KC32Detail, _L8("CCommSession::Read(), Pos (%d), Offset (%d)"), aPos, aOffset);
       
  1107 
       
  1108 	TInt ret = aMessage.Read(aPos, aDes, aOffset);
       
  1109 	if (ret!=KErrNone)
       
  1110 		{
       
  1111 		C32LOG1(KC32Detail, _L8("Error at the time of reading data from client"));
       
  1112 		PanicClient(EBadDescriptor,aMessage);
       
  1113 		}
       
  1114 	return ret;
       
  1115 	}
       
  1116 
       
  1117 
       
  1118 TInt CCommSession::Write(TInt aPos, const RMessagePtr2& aMessage , const TDesC16& aDes, TInt aOffset)
       
  1119 /**
       
  1120  * Write and kill the client if it leaves.
       
  1121  *
       
  1122  * (see CCommSession::Write() with 8-bit descriptor)
       
  1123  *
       
  1124  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  1125  *                The data type at this location must be a modifiable descriptor, i.e. aTDes16 type.
       
  1126  * @param aDes    A 16 bit descriptor in the server address space. This is the source of the copy operation.
       
  1127  * @param aOffset The offset from the start of the target descriptor data area where copying is to begin.
       
  1128  *                This value must be greater than or equal to zero.
       
  1129  *
       
  1130  * @panic This function will panic the client if the WriteL() leaves
       
  1131  */
       
  1132 	{
       
  1133 
       
  1134 	//C32LOG4(KC32Detail, _L8("CCommSession::Write(), Data = (%s), Pos (%d), Offset (%d)"), aDes.Ptr(), aPos, aOffset);
       
  1135 
       
  1136 	TInt ret = aMessage.Write(aPos, aDes, aOffset);
       
  1137 	if (ret!=KErrNone)
       
  1138 		{
       
  1139 		PanicClient(EBadDescriptor,aMessage);
       
  1140 		}
       
  1141 	return ret;
       
  1142 	}
       
  1143 
       
  1144 
       
  1145 TInt CCommSession::Read(TInt aPos, const RMessagePtr2& aMessage , TDes16& aDes, TInt aOffset)
       
  1146 /**
       
  1147  * Read and kill the client if it leaves.
       
  1148  *
       
  1149  * (see CCommSession::Write() with 8-bit descriptor)
       
  1150  *
       
  1151  * @param aPtr    A pointer to a valid address within the client thread's address space.
       
  1152  *                The data at this pointer must be a descriptor, i.e. a TDesC16 type.
       
  1153  * @param aDes    A 16 bit descriptor in the server address space. This is the target
       
  1154  *                of the copy operation.
       
  1155  * @param aOffset The offset from the start of the source descriptor data area from where
       
  1156  *                copying is to begin. This value must be greater than or equal to zero.
       
  1157  *
       
  1158  * @panic This function will panic the client if the ReadL() leaves
       
  1159  */
       
  1160 	{
       
  1161 	C32LOG3(KC32Detail, _L8("CCommSession::Read(), Pos (%d), Offset (%d)"), aPos, aOffset);
       
  1162 
       
  1163 	TInt ret = aMessage.Read(aPos, aDes, aOffset);
       
  1164 	if (ret!=KErrNone)
       
  1165 		{
       
  1166 		C32LOG1(KC32Detail, _L8("Error at the time of reading data from client"));
       
  1167 		PanicClient(EBadDescriptor,aMessage);
       
  1168 		}
       
  1169 	return ret;
       
  1170 	}
       
  1171 
       
  1172 /**
       
  1173 Checks for a null'd handle before attempting complete.
       
  1174 If handle is null'd then don't complete as this will panic server.
       
  1175 
       
  1176 @param aMessage Message to complete
       
  1177 @param aCompletionCode Completion code.
       
  1178 */
       
  1179 void SafeComplete(const RMessagePtr2& aMessage, TInt aCompletionCode)
       
  1180 	{
       
  1181 	if(!aMessage.IsNull())
       
  1182 		{
       
  1183 		C32LOG3(KC32Dealer,_L8("CCommSession::SafeComplete(%08x) Completion code: %d"),aMessage.Handle(),aCompletionCode);
       
  1184 		aMessage.Complete(aCompletionCode);
       
  1185 		}
       
  1186 	else
       
  1187 		{
       
  1188 		C32LOG3(KC32Detail,_L8("CCommSession::SafeComplete(%08x) - cannot complete message since Null! Completion code was meant to be: %d"),aMessage.Handle(),aCompletionCode);
       
  1189 		}
       
  1190 	}
       
  1191 
       
  1192 
       
  1193 
       
  1194 TInt AddCSYExtension(TFileName& aFilename, const RMessage2& aMessage)
       
  1195 // implements variation whereby filename is 16-bit, and we want to panic client if the extension won't fit
       
  1196 // KErrNone if no probs or extension already present, KErrBadDescriptor if too short
       
  1197 	{
       
  1198 	TInt r=aFilename.LocateReverse('.');
       
  1199  	if (r==KErrNotFound)
       
  1200 		{
       
  1201 		if (aFilename.Length()>KMaxFileName - (TInt)KCSYExtension.iTypeLength)	//< valid filename is checked here
       
  1202 			{
       
  1203 			PanicClient(EBadDescriptor,aMessage);
       
  1204 			return KErrBadDescriptor;
       
  1205 			}
       
  1206 		aFilename.Append(KCSYExtension);
       
  1207 		}
       
  1208 	return KErrNone;
       
  1209 	}
       
  1210 
       
  1211 
       
  1212 //
       
  1213 // CCommSubSession
       
  1214 //
       
  1215 
       
  1216 /**
       
  1217 Constructor
       
  1218 */
       
  1219 CCommSubSession::CCommSubSession(CCommSession* aSession, CPort* aPort, CC32Player* aPlayer)
       
  1220 : iPlayer(aPlayer),
       
  1221   iAccessCount(1),
       
  1222   iPort(aPort),
       
  1223   iSession(aSession)
       
  1224 	{
       
  1225 	C32LOG4(KC32Detail, _L8("CCommSubSession(%08x):\tCPort Port(%08x):\tCCommSubSession Session(%08x)"), this, iPort, iSession );
       
  1226 	}
       
  1227 
       
  1228 #ifdef _DEBUG
       
  1229 CCommSubSession::~CCommSubSession()
       
  1230 	{
       
  1231 	C32LOG3(KC32Detail, _L8("CCommSubSession(%08x):\t~CCommSubSession Session(%08x)"), this, iSession );
       
  1232 	}
       
  1233 #endif
       
  1234 
       
  1235 void CCommSubSession::RemoveAndDestroy()
       
  1236 	{
       
  1237 	// Remove from the Player's container and delete
       
  1238 	C32LOG3(KC32Detail, _L8("CCommSubSession(%08x):\tRemoveAndDestroy(), session=%08x"), this, iSession );
       
  1239 	CC32Player::TSubSessionContainer& subSessions = Player().SubSessions();
       
  1240 	TInt sessIdx = subSessions.Find(this);
       
  1241 	if(sessIdx >= 0)
       
  1242 		{
       
  1243 		subSessions.Remove(sessIdx);
       
  1244 		if(subSessions.Count() == 0)
       
  1245 			{
       
  1246 			CC32WorkerThread& workerThread = Player().WorkerThread();
       
  1247 			if(workerThread.ShuttingDown())
       
  1248 				{
       
  1249 				workerThread.MaybeTriggerThreadShutdownCallback();
       
  1250 				}
       
  1251 			}
       
  1252 		}
       
  1253 	delete this;
       
  1254 	}
       
  1255 
       
  1256 CCommSubSession* CCommSubSession::NewL(CCommSession *aSession, CPort* aPort, CC32Player* aPlayer)
       
  1257 	{
       
  1258 	CCommSubSession *s=new (ELeave) CCommSubSession(aSession, aPort, aPlayer);
       
  1259 	return s;
       
  1260 	}
       
  1261 
       
  1262 // EOF - CS_SES.CPP
       
  1263