bluetoothmgmt/btmgr/BTManServer/BTManServer.cpp
changeset 0 29b1cd4cb562
child 11 20fda83a6398
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 1999-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 #include <s32mem.h>
       
    17 #include <e32svr.h>
       
    18 #include "BTManServer.h"
       
    19 
       
    20 
       
    21 #include "BTSec.h"
       
    22 #include "BtManServerSecurityPolicy.h"
       
    23 #include <bluetooth/logger.h>
       
    24 
       
    25 #ifdef __FLOG_ACTIVE
       
    26 _LIT8(KLogComponent, LOG_COMPONENT_BT_MANAGER_SERVER);
       
    27 #endif
       
    28 
       
    29 static const TInt KMessageArrayGranularity = 4; //< The granularity of the array used to hold TBTManMessage objects
       
    30 static const TInt KBTManClientServerProtocolSlot = 2; // the slot that points to the struct buf used between client and server
       
    31 
       
    32 inline CBTManServerShutdown::CBTManServerShutdown()
       
    33 	:CTimer(-1)
       
    34 	{
       
    35 	LOG_FUNC
       
    36 	CActiveScheduler::Add(this);
       
    37 	}
       
    38 
       
    39 inline void CBTManServerShutdown::ConstructL()
       
    40 	{
       
    41 	LOG_FUNC
       
    42 	CTimer::ConstructL();
       
    43 	}
       
    44 
       
    45 inline void CBTManServerShutdown::Start()
       
    46 	{
       
    47 	LOG_FUNC
       
    48 	After(KBTManServerShutdownDelay);
       
    49 	}
       
    50 
       
    51 //
       
    52 
       
    53 
       
    54 void CBTManServerShutdown::RunL()
       
    55 /**
       
    56 Initiate server exit when the timer expires
       
    57 **/
       
    58 	{
       
    59 	LOG_FUNC
       
    60 	CActiveScheduler::Stop();
       
    61 	}
       
    62 
       
    63 //=====================================================================
       
    64 // CBTManServer
       
    65 //=====================================================================
       
    66 
       
    67 inline CBTManServer::CBTManServer()
       
    68 	:	CPolicyServer(EPriorityStandard,KBtmanServerPolicy,ESharableSessions)
       
    69 	{
       
    70 	LOG_FUNC
       
    71 	}
       
    72 
       
    73 CServer2* CBTManServer::NewLC()
       
    74 	{
       
    75 	LOG_STATIC_FUNC
       
    76 	CBTManServer* self=new(ELeave) CBTManServer;
       
    77 	CleanupStack::PushL(self);
       
    78 	self->ConstructL();
       
    79 	return self;
       
    80 	}
       
    81 
       
    82 void CBTManServer::ConstructL()
       
    83 	{
       
    84 	LOG_FUNC
       
    85 	StartL(KBTManServerName);
       
    86 	//Ensure that the server will exit even if the 1st client fails to connect
       
    87 	iShutdown.ConstructL();
       
    88 	iShutdown.Start();
       
    89 
       
    90 	TInt err;
       
    91 	err = iProperty.Define(KPropertyUidBluetoothCategory,
       
    92 						   KPropertyKeyBluetoothGetRegistryTableChange,
       
    93 						   RProperty::EInt,
       
    94 						   KLOCAL_SERVICES,
       
    95 						   KBTMAN_SID_PROT_SERV);
       
    96 						   
       
    97 	FLOGIFERR(err,_L("CBTManServer::ConstructL() - iProperty.Define Failure"));
       
    98 		
       
    99 	err = iProperty.Define(KPropertyUidBluetoothCategory,
       
   100 						   KPropertyKeyBluetoothCorruptRegistryReset,
       
   101 						   RProperty::EInt,
       
   102 						   KLOCAL_SERVICES,
       
   103 						   KLOCAL_SERVICES_AND_NETWORK_CONTROL);
       
   104 						   
       
   105 	FLOGIFERR(err,_L("CBTManServer::ConstructL() - iProperty.Define Failure"));
       
   106 
       
   107 	//Create the service providers...
       
   108 	iRegistry = CBTRegistry::NewL();
       
   109 
       
   110 	iContainerIndex = CObjectConIx::NewL();
       
   111 	// don't stop the server if we can't provide this service...				   
       
   112 	}
       
   113 
       
   114 
       
   115 CObjectCon* CBTManServer::NewContainerL()
       
   116 /**
       
   117 Return a new object container
       
   118 **/
       
   119 	{
       
   120 	LOG_FUNC
       
   121 	return iContainerIndex->CreateL();
       
   122 	}
       
   123 
       
   124 void CBTManServer::DeleteContainer(CObjectCon* aCon)
       
   125 	{
       
   126 	LOG_FUNC
       
   127 	iContainerIndex->Remove(aCon);
       
   128 	}
       
   129 
       
   130 CBTManServer::~CBTManServer()
       
   131 	{
       
   132 	LOG_FUNC
       
   133 
       
   134 	// Delete defined properties
       
   135 	TInt err;
       
   136 	err = iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetRegistryTableChange);
       
   137 	FLOGIFERR(err,_L("CBTManServer::~CBTManServer() - iProperty.Delete Failure"));
       
   138 	err = iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothCorruptRegistryReset);
       
   139 	FLOGIFERR(err,_L("CBTManServer::~CBTManServer() - iProperty.Delete Failure"));
       
   140 	// Close the RProperty handle in case it is ever attached.
       
   141 	iProperty.Close();
       
   142 
       
   143 	delete iRegistry;
       
   144 	delete iContainerIndex;
       
   145 	}
       
   146 
       
   147 CSession2* CBTManServer::NewSessionL(const TVersion &aVersion, const RMessage2& aMessage) const
       
   148 	{
       
   149 	LOG_FUNC
       
   150 	TVersion v(KBTManServerMajorVersionNumber,KBTManServerMinorVersionNumber,KBTManServerBuildVersionNumber);
       
   151 	if (!User::QueryVersionSupported(v,aVersion))
       
   152 		{
       
   153 		User::Leave(KErrNotSupported);
       
   154 		}
       
   155 	// make new session
       
   156 	return new(ELeave) CBTManSession(*iRegistry, aMessage);
       
   157 	}
       
   158 
       
   159 void CBTManServer::AddSession()
       
   160 /**
       
   161 A new session is being created
       
   162 Cancel the shutdown timer if it was running
       
   163 **/
       
   164 	{
       
   165 	LOG_FUNC
       
   166 	++iSessionCount;
       
   167 	if (iSessionCount > iMaxSessionCount)
       
   168 		{
       
   169 		iMaxSessionCount = iSessionCount;
       
   170 		}
       
   171 	iShutdown.Cancel();
       
   172 	}
       
   173 
       
   174 void CBTManServer::DropSession()
       
   175 /**
       
   176 A session is being destroyed
       
   177 Start the shutdown timer if it is the last session.
       
   178 **/
       
   179 	{
       
   180 	LOG_FUNC
       
   181 	__ASSERT_DEBUG(iSessionCount > 0, PanicServer(EBTManBadState));
       
   182 	
       
   183 	if (--iSessionCount==0)
       
   184 		{
       
   185 		iShutdown.Start();
       
   186 		}
       
   187 	}
       
   188 
       
   189 void CBTManServer::Publish(TUint aKey, TInt aValue)
       
   190 	{
       
   191 	LOG_FUNC
       
   192 	TInt err;
       
   193 	err = iProperty.Set(KPropertyUidBluetoothCategory,
       
   194 					    aKey,
       
   195 						aValue);
       
   196 	FLOGIFERR(err,_L("CBTManServer::Publish() - iProperty.Set Failure"));
       
   197 	}
       
   198 
       
   199 void CBTManServer::NotifyViewChange(CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor)
       
   200 	{
       
   201 	LOG_FUNC
       
   202 	// For views owned by subsessions.
       
   203 	
       
   204 	// Go through all sessions - they'll dispatch so all the subessions apart from the one calling here
       
   205 	iSessionIter.SetToFirst();
       
   206 
       
   207 	while (iSessionIter != NULL)
       
   208 		{
       
   209 		CBTManSession* s = static_cast<CBTManSession*>(iSessionIter++);
       
   210 		s->SubSessionHasOverlappingView(aSubSessionViewOwner, aViewDescriptor);
       
   211 		}
       
   212 	}
       
   213 
       
   214 void PanicClient(const RMessage2& aMessage,TInt aPanic, CBTManSession* aSession)
       
   215 /**
       
   216 RMessage2::Panic() also completes the message. This is:
       
   217 (a) important for efficient cleanup within the kernel
       
   218 (b) a problem if the message is completed a second time
       
   219 **/
       
   220 	{
       
   221 	LOG_STATIC_FUNC
       
   222 	LOG1(_L("PanicClient: Reason = %d"), aPanic);
       
   223 	//remove the message from the message table so we don't complete it again
       
   224 	//The message may not yet be in the table, so check for NULL before deleting it
       
   225 	//This code could be more efficient, but hopefully it won't be called enough to make
       
   226 	//it worthwhile improving it ;-)
       
   227 	
       
   228 	__DEBUGGER();
       
   229 
       
   230 	/*** ORDER MATTERS! ***/
       
   231 	//First find the message in the session's stored messages
       
   232 	//This must be done BEFORE panicking the client because
       
   233 	//panicking the client resets the RMessage2 handle value to
       
   234 	//zero and so almost always renders the FindMessage method useless!
       
   235 	CBTManMessage* m = aSession->FindMessage(aMessage);
       
   236 	
       
   237 	//Now panic the client - this is safer done before deleting 
       
   238 	//the message from the message array, just in case the RMessage2
       
   239 	//object is obtained from that array and not directly from the client
       
   240 	aMessage.Panic(KBTManPanic,aPanic);
       
   241 	
       
   242 	//Now delete the message from the session's queue. This is vital
       
   243 	//if we are not to attempt to complete on a dead message
       
   244 	if (m)
       
   245 		{
       
   246 		//aMessage will not be usable after the next line if it is obtained from the message array
       
   247 		//instead of the one directly supplied by the client
       
   248 		aSession->DeleteMessage(m);
       
   249 		}
       
   250 	}
       
   251 
       
   252 void PanicServer(TInt aPanic)
       
   253 /**
       
   254 Panic our own thread
       
   255 **/
       
   256 	{
       
   257 	LOG_STATIC_FUNC
       
   258 	LOG1(_L("PanicServer: Reason = %d"), aPanic);
       
   259 	User::Panic(KBTManPanic, aPanic);
       
   260 	}
       
   261 
       
   262 
       
   263 static void RunServerL()
       
   264 /**
       
   265 Perform all server initialisation, in particular creation of the
       
   266 scheduler and server and then run the scheduler
       
   267 **/
       
   268 	{
       
   269 	LOG_STATIC_FUNC
       
   270 	// create and install the active scheduler we need
       
   271 	CActiveScheduler* scheduler=new(ELeave) CActiveScheduler;
       
   272 	CleanupStack::PushL(scheduler);
       
   273 	CActiveScheduler::Install(scheduler);
       
   274 	//
       
   275 	// create the server (leave it on the cleanup stack)
       
   276 	CServer2* server = CBTManServer::NewLC();
       
   277 	//
       
   278 	
       
   279 	#ifdef __BTMANSERVER_NO_PROCESSES__
       
   280 	RThread::Rendezvous(KErrNone);
       
   281 	#else
       
   282 	// naming the server thread after the server helps to debug panics
       
   283 	// ignore error - we tried the best we could
       
   284 	User::RenameThread(KBTManServerName); 
       
   285 	
       
   286 	RProcess::Rendezvous(KErrNone);
       
   287 	#endif
       
   288 	
       
   289 	//
       
   290 	// Ready to run
       
   291 	CActiveScheduler::Start();
       
   292 	//
       
   293 	// Cleanup the server and scheduler
       
   294 	CleanupStack::PopAndDestroy(server);
       
   295 	CleanupStack::PopAndDestroy(scheduler);
       
   296 	}
       
   297 
       
   298 TInt E32Main()
       
   299 /**
       
   300 Main entry-point for the server process
       
   301 **/
       
   302 	{
       
   303 	CONNECT_LOGGER
       
   304 	LOG_STATIC_FUNC
       
   305 	LOG(_L("BTManServer RunServer"));
       
   306 
       
   307 	__UHEAP_MARK;
       
   308 #ifdef TEST_OOM //define TEST_OOM in preprocessor definitions in project settings
       
   309 	__UHEAP_SETFAIL(RHeap::ERandom, 100);
       
   310 #endif
       
   311 	CTrapCleanup* cleanup=CTrapCleanup::New();
       
   312 	TInt r=KErrNoMemory;
       
   313 	if (cleanup)
       
   314 		{
       
   315 		TRAP(r,RunServerL());
       
   316 		delete cleanup;
       
   317 		}
       
   318 	//
       
   319 	__UHEAP_MARKEND;
       
   320 	CLOSE_LOGGER
       
   321 	return r;
       
   322 	}
       
   323 
       
   324 
       
   325 //=====================================================================
       
   326 //CBTManMessage
       
   327 //=====================================================================
       
   328 
       
   329 // This framework is retained as it allows instrinsically asynchronous actions to be
       
   330 // looked after easily.  At present such actions are limited to change notifications
       
   331 // pretty much everything else is handled synchronously once the Server has had
       
   332 // its ServiceL called.
       
   333 
       
   334 CBTManMessage* CBTManMessage::NewL(const RMessage2& aMessage)
       
   335 	{
       
   336 	LOG_STATIC_FUNC
       
   337 	CBTManMessage* m = new (ELeave) CBTManMessage(aMessage);
       
   338 	CleanupStack::PushL(m);
       
   339 	m->ConstructL();
       
   340 	CleanupStack::Pop(m);
       
   341 	return m;
       
   342 	}
       
   343 
       
   344 CBTManMessage::CBTManMessage(const RMessage2& aMessage)
       
   345 : iMessage(aMessage)
       
   346 	{
       
   347 	LOG_FUNC
       
   348 	}
       
   349 
       
   350 void CBTManMessage::ConstructL()
       
   351 	{
       
   352 	LOG_FUNC
       
   353 	if (iMessage.Ptr2())
       
   354 		{
       
   355 		TPckgBuf<TBTManClientServerMessage> msgBuf;
       
   356 		iMessage.ReadL(KBTManClientServerProtocolSlot, msgBuf);
       
   357 		
       
   358 		iCancelPtr = msgBuf().iClientStatusToCancel;
       
   359 		}
       
   360 	}
       
   361 
       
   362 
       
   363 CBTManMessage::~CBTManMessage()
       
   364 	{
       
   365 	LOG_FUNC
       
   366 	//ensure we delete the helper if there is one
       
   367 	if (iHelper)
       
   368 		{
       
   369 		iHelper->Delete();
       
   370 		}
       
   371 	}
       
   372 
       
   373 void CBTManMessage::SetHelper(MBTManHelper* aHelper)
       
   374 /**
       
   375 Assigns a helper to the message.
       
   376 The helper will then be told to delete itself when the message is completed.
       
   377 This is especially important when cancelling or under leave conditions.
       
   378 **/
       
   379 	{
       
   380 	LOG_FUNC
       
   381 	__ASSERT_DEBUG(iHelper==NULL, PanicServer(EBTManBadHelper));
       
   382 	__ASSERT_DEBUG((aHelper->Message()).Ptr2() == iCancelPtr, PanicServer(EBTManBadHelper));
       
   383 	iHelper = aHelper;
       
   384 	}
       
   385 
       
   386 void CBTManMessage::RemoveHelper()
       
   387 /**
       
   388 Disassociates a helper with a message.
       
   389 **/
       
   390 	{
       
   391 	LOG_FUNC
       
   392 	iHelper = NULL;
       
   393 	}
       
   394 
       
   395 void CBTManMessage::Complete(TInt aReason)
       
   396 /**
       
   397 Completes the RMessage2 and deletes any associated helper.
       
   398 **/
       
   399 	{
       
   400 	LOG_FUNC
       
   401 	//complete the message
       
   402 	iMessage.Complete(aReason);
       
   403 	//delete the helper if there is one
       
   404 	if (iHelper)
       
   405 		iHelper->Delete();
       
   406 	}
       
   407 
       
   408 const RMessage2& CBTManMessage::Message()
       
   409 	{
       
   410 	LOG_FUNC
       
   411 	return iMessage;
       
   412 	}
       
   413 
       
   414 const TAny* CBTManMessage::CancelPtr()
       
   415 /**
       
   416 The CancelPtr is the address of the TRequestStatus of the client-side active object
       
   417 dealing with the request.  When a request is cancelled, it is located server-side using
       
   418 this address.
       
   419 **/
       
   420 	{
       
   421 	LOG_FUNC
       
   422 	return iCancelPtr;
       
   423 	}
       
   424 
       
   425 
       
   426 MBTManHelper* CBTManMessage::Helper()
       
   427 	{
       
   428 	LOG_FUNC
       
   429 	return iHelper;
       
   430 	}
       
   431 
       
   432 TBool CBTManMessage::operator==(CBTManMessage& aMessage) const
       
   433 	{
       
   434 	LOG_FUNC
       
   435 	if (iMessage == aMessage.Message())
       
   436 		return ETrue;
       
   437 	return EFalse;
       
   438 	}
       
   439 
       
   440 //=====================================================================
       
   441 //CBTManSession
       
   442 //=====================================================================
       
   443 
       
   444 CBTManServer& CBTManSession::Server()
       
   445 	{
       
   446 	LOG_FUNC
       
   447 	return *static_cast<CBTManServer*>(const_cast<CServer2*>(CSession2::Server()));
       
   448 	}
       
   449 
       
   450 CBTManSession::CBTManSession(CBTRegistry& aRegistry, const RMessage2& aMessage)
       
   451 : iRegistry(aRegistry), iCurrentMessage(aMessage)
       
   452 	{
       
   453 	LOG_FUNC
       
   454 	}
       
   455 
       
   456 void CBTManSession::CreateL()
       
   457 /**
       
   458 2nd phase construct for sessions - called by the CServer2 framework
       
   459 **/
       
   460 	{
       
   461 	LOG_FUNC
       
   462 	//CSession2::CreateL();	// private and does nowt so removed
       
   463 	//Add session to server first. If anything leaves, it will be removed by the destructor
       
   464 	Server().AddSession();
       
   465 	ConstructL();
       
   466 	}
       
   467 
       
   468 void CBTManSession::ConstructL()
       
   469 	{
       
   470 	LOG_FUNC
       
   471 	//Create new object index
       
   472 	iSubSessions = CObjectIx::NewL();
       
   473 	iContainer = Server().NewContainerL();
       
   474 
       
   475 	iMessageArray = new(ELeave) CArrayPtrFlat<CBTManMessage>(KMessageArrayGranularity);
       
   476 	}
       
   477 
       
   478 CBTManSession::~CBTManSession()
       
   479 	{
       
   480 	LOG_FUNC
       
   481 	if (iMessageArray)
       
   482 		{
       
   483 		CompleteOutstandingMessages();
       
   484 		iMessageArray->ResetAndDestroy();
       
   485 		}
       
   486 	delete iMessageArray;
       
   487 	delete iSubSessions;
       
   488 	Server().DeleteContainer(iContainer);
       
   489 	Server().DropSession();
       
   490 	}
       
   491 
       
   492 void CBTManSession::CompleteOutstandingMessages()
       
   493 /**
       
   494 Completes any messages left in the CBTManMessage array.
       
   495 **/
       
   496 	{
       
   497 	LOG_FUNC
       
   498 	CBTManMessage* ptr;
       
   499 	TInt count = iMessageArray->Count();
       
   500 	LOG1(_L("CBTManSession::CompleteOutstandingMessages(): %d"), count);
       
   501 	for (TInt i=(count-1); i>=0; i--)
       
   502 		{
       
   503 		ptr = iMessageArray->At(i);
       
   504 		ptr->Complete(KErrDied);
       
   505 		iMessageArray->Delete(i);
       
   506 		delete ptr;
       
   507 		ptr = NULL;
       
   508 		}
       
   509 	}
       
   510 
       
   511 
       
   512 CBTManSubSession* CBTManSession::SubSessionFromHandle(TInt aHandle)
       
   513 /**
       
   514 Returns a subsession given a handle
       
   515 
       
   516 	@param aHandle the handle given by the client
       
   517 	@param aMessage	only used if we need to panic client's having used a dodgy handle
       
   518 **/
       
   519 	{
       
   520 	LOG_FUNC
       
   521 	CBTManSubSession* p = static_cast<CBTManSubSession*>(iSubSessions->At(aHandle));
       
   522 	return p;
       
   523 	}
       
   524 
       
   525 TInt CBTManSession::HandleError(TInt aError, const RMessage2 &aMessage)
       
   526 /**
       
   527 Handle an error from ServiceL()
       
   528 A bad descriptor error implies a badly programmed client, so panic it;
       
   529 otherwise report the error to the client
       
   530 **/
       
   531 	{
       
   532 	LOG_FUNC
       
   533 	LOG1(_L("CBTManSession::HandleError(): %d"), aError);
       
   534 	if (aError==KErrBadDescriptor || aError==KErrBadHandle)
       
   535 		{
       
   536 #ifdef _DEBUG
       
   537 		__DEBUGGER(); //******** SERVER STOP ******************
       
   538 #endif
       
   539 		TInt convErr = aError==KErrBadDescriptor?EBTManBadDescriptor:EBTManBadSubSessionHandle;
       
   540 		PanicClient(aMessage, convErr, this);
       
   541 		}
       
   542 	else
       
   543 		{
       
   544 		CompleteMessage(aMessage, aError);
       
   545 		}
       
   546 	Server().ReStart();
       
   547 	return KErrNone;	// handled the error fully
       
   548 	}
       
   549 
       
   550 
       
   551 void CBTManSession::ServiceL(const RMessage2 &aMessage)
       
   552 /**
       
   553 Handle a client request.
       
   554 Leaving is handled by HandleError() which reports the error code
       
   555 to the client
       
   556 **/
       
   557 	{
       
   558 	LOG_FUNC		
       
   559 	//We don't need to create a message object if message is handled by session
       
   560 	//Simply dispatch and complete the message
       
   561 	TBool handled = ETrue;
       
   562 
       
   563 	TRAPD(err, handled = DispatchSessMessageL(aMessage));
       
   564 	if (handled || (err!=KErrNone))
       
   565 		{
       
   566 		if (!iClientPanic)
       
   567 			{
       
   568 			// Don't complete messages already completed by ClientPanic
       
   569 			aMessage.Complete(err);
       
   570 			}
       
   571 		else 
       
   572 			{
       
   573 			//Client Panic Handled - Reset Flag.
       
   574 			iClientPanic = EFalse;
       
   575 			}
       
   576 		return;
       
   577 		}
       
   578 
       
   579 	//not handled by session so must be for subsession
       
   580 	//Create a message object to handle this
       
   581 	//We need to trap this so a leave doesn't propogate to active scheduler
       
   582 	err = KErrNone;
       
   583 	TRAP(err, CreateBTManMessageL(aMessage));
       
   584 	if (err)
       
   585 		{
       
   586 		aMessage.Complete(err);
       
   587 		return;
       
   588 		}
       
   589 
       
   590 	//Trap dispatchSubSessMessage so we can handle error here
       
   591 	err=KErrNone;
       
   592 	TRAP(err, DispatchSubSessMessageL(aMessage));
       
   593 	//if we have an error, try to handle it with handleerror. If this fails, leave
       
   594 	//and let the active scheduler sort it out.
       
   595 	if (err != KErrNone)
       
   596 		{
       
   597 		// tell subsessions to try to reduce footprint and rollback
       
   598 		for (TInt i = 0; i<iSubSessions->Count(); i++)
       
   599 			{
       
   600 			//check this element is an actual object rather than an empty memory 
       
   601 			//cell on the free list
       
   602 			if((*iSubSessions)[i])
       
   603 				{
       
   604 				static_cast<CBTManSubSession*>((*iSubSessions)[i])->Cleanup(err);
       
   605 				}
       
   606 			}
       
   607 		// Tidy up of logic and construct
       
   608 		if (err != KErrNone)
       
   609 			{
       
   610 			User::LeaveIfError(HandleError(err, aMessage));
       
   611 			return;
       
   612 			}
       
   613 		}
       
   614 	}
       
   615 
       
   616 void CBTManSession::CreateBTManMessageL(const RMessage2& aMessage)
       
   617 /**
       
   618 Creates a CBTManMessage and appends it to iMessageArray.
       
   619 These are used for the BTMan server to conduct asynchronous activities itself
       
   620 
       
   621 Many activities that the BTMan Server does at present are synchronously handled; but
       
   622 for conformity all the subsessions use this framework so that any asynchronous
       
   623 tasks can be added later
       
   624 
       
   625 	@param	aMessage	The original client message
       
   626 **/
       
   627 	{
       
   628 	LOG_FUNC
       
   629 	CBTManMessage* m = CBTManMessage::NewL(aMessage);
       
   630 	CleanupStack::PushL(m);
       
   631 	iMessageArray->AppendL(m);
       
   632 	CleanupStack::Pop();
       
   633 	}
       
   634 
       
   635 
       
   636 TBool CBTManSession::DispatchSessMessageL(const RMessage2 &aMessage)
       
   637 /**
       
   638 Handles the request - it may not actually be for the session
       
   639 
       
   640 @param aMessage    The current message being handled.
       
   641 @return			   ETrue: The message was meant for the session.
       
   642 @return            EFalse: The message was meant for a subsession.
       
   643 **/
       
   644 	{
       
   645 	LOG_FUNC
       
   646 	switch (aMessage.Function())
       
   647 		{
       
   648 	case EBTManCreateRegistrySubSession:
       
   649 		NewSubSessionL(ERegistry, aMessage);
       
   650 		return ETrue;
       
   651 	case EBTManCreateLocalDeviceSubSession:
       
   652 		NewSubSessionL(ELocalDevice, aMessage);
       
   653 		return ETrue;
       
   654 	case EBTManCreateCommPortSettingsSubSession:
       
   655 		NewSubSessionL(ECommPortSettings, aMessage);
       
   656 		return ETrue;
       
   657 	case EBTManCreateHostResolverSubSession:
       
   658 		NewSubSessionL(EHostResolver, aMessage);
       
   659 		return ETrue;
       
   660 	case EBTManCancelRequest:
       
   661 		CancelRequest(aMessage);
       
   662 		return ETrue;
       
   663 	case EBTManCloseSubSession:
       
   664 		CloseSubSession(aMessage);
       
   665 		return ETrue;
       
   666 	case EBTManSetHeapFailure:
       
   667 #ifdef _DEBUG
       
   668 		User::__DbgSetAllocFail(RHeap::EUser,RHeap::TAllocFail(aMessage.Int0()),aMessage.Int1());
       
   669 #endif
       
   670 		return ETrue;
       
   671 	case EBTManSubSessionCount:
       
   672 		{
       
   673 #ifdef _DEBUG
       
   674 		TPckgBuf<TInt> pckg(iSubSessions->Count());
       
   675 		aMessage.WriteL(0, pckg);
       
   676 #endif
       
   677 		return ETrue;
       
   678 		}
       
   679 	default:
       
   680 		//not handled here so must be for subsession
       
   681 		return EFalse;
       
   682 		}
       
   683 	}
       
   684 
       
   685 void CBTManSession::DispatchSubSessMessageL(const RMessage2& aMessage)
       
   686 /**
       
   687 Handles subsession requests.
       
   688 
       
   689 	@param aMessage    The current message being handled.
       
   690 **/
       
   691 	{
       
   692 	LOG_FUNC
       
   693 	CBTManSubSession& ss = *SubSessionFromHandle(aMessage.Int3());
       
   694 	if (&ss == NULL)
       
   695 		{
       
   696 		User::Leave(KErrBadHandle);
       
   697 		}
       
   698 
       
   699 	// Get the status of the client request (sent on all msgs in slot2)
       
   700 	switch (aMessage.Function())
       
   701 		{
       
   702 	case EBTManRegistrySearch:
       
   703 		{
       
   704 		TBTRegistrySearchPckgBuf pckg;
       
   705 		aMessage.ReadL(0, pckg);
       
   706 		static_cast<CBTRegistrySubSession*>(&ss)->OpenViewL(pckg(), aMessage);
       
   707 		break;
       
   708 		}
       
   709 	case EBTRegistryAddDevice:
       
   710 		{
       
   711 		// create a new device subsession and add the device - may change API to require
       
   712 		// previously opened subsession??
       
   713 		// need to internalise a contiguated buffer
       
   714 	
       
   715 		TInt len = aMessage.GetDesLengthL(0);
       
   716 		HBufC8* buffer = HBufC8::NewLC(len);
       
   717 		TPtr8 ptr(buffer->Des());
       
   718 
       
   719 		aMessage.ReadL(0, ptr);
       
   720 		RDesReadStream stream;
       
   721 		stream.Open(ptr);
       
   722 		CleanupClosePushL(stream);
       
   723 
       
   724 		CBTDevice* addDetails = CBTDevice::NewLC();
       
   725 		addDetails->InternalizeL(stream);
       
   726 
       
   727 		static_cast<CBTRegistrySubSession*>(&ss)->AddDeviceL(*addDetails, aMessage);
       
   728 
       
   729 		CleanupStack::PopAndDestroy(3); //addDetails, stream, buffer
       
   730 		break;
       
   731 		}
       
   732 	case EBTRegistryModifyNamelessDevice:
       
   733 		{
       
   734 		LOG(_L("CBTManSession -> ModifyNamelessDevice"));
       
   735 		TBTNamelessDevicePckgBuf pckg;
       
   736 		aMessage.ReadL(0, pckg);
       
   737 		static_cast<CBTRegistrySubSession*>(&ss)->ModifyL(pckg(), aMessage);
       
   738 		break;
       
   739 		}
       
   740 	case EBTRegistryGetNamelessDevice:
       
   741 		{
       
   742 		TBTNamelessDevicePckgBuf pckg;
       
   743 		aMessage.ReadL(0, pckg);
       
   744 		static_cast<CBTRegistrySubSession*>(&ss)->GetDeviceL(pckg(), aMessage);
       
   745 		break;
       
   746 		}
       
   747 	case EBTManExtractRegistryDataIntoServer:
       
   748 		{
       
   749 		static_cast<CBTRegistrySubSession*>(&ss)->PreLoadL(aMessage);
       
   750 		break;
       
   751 		}
       
   752 
       
   753 	case EBTManRetrieveRegistryData:
       
   754 		{
       
   755 		static_cast<CBTRegistrySubSession*>(&ss)->RetrieveL(aMessage);
       
   756 		break;
       
   757 		}
       
   758 
       
   759 	case EBTRegistryDeleteLinkKey:
       
   760 		{
       
   761 		TBTDevAddrPckgBuf pckg;
       
   762 		aMessage.ReadL(0, pckg);
       
   763 		static_cast<CBTRegistrySubSession*>(&ss)->UnpairL(pckg(), aMessage);
       
   764 		break;
       
   765 		}
       
   766 
       
   767 	case EBTRegistryDeleteDevices:
       
   768 		{
       
   769 		//nothing to read
       
   770 		static_cast<CBTRegistrySubSession*>(&ss)->DeleteViewL(aMessage);
       
   771 		break;
       
   772 		}
       
   773 
       
   774 	case EBTRegistryModifyBluetoothName:
       
   775 	case EBTRegistryModifyFriendlyName:
       
   776 		{
       
   777 		// read the address - this could move into the handler
       
   778 		TBTDevAddrPckgBuf addr;
       
   779 		aMessage.ReadL(0, addr);
       
   780 		static_cast<CBTRegistrySubSession*>(&ss)->ModifyNameL(addr(), aMessage);
       
   781 		break;
       
   782 		}
       
   783 
       
   784 	case EBTRegistryGetLocalDevice:
       
   785 		{
       
   786 		//nothing to read
       
   787 		static_cast<CBTLocalDeviceSubSession*>(&ss)->GetL(aMessage);
       
   788 		break;
       
   789 		}
       
   790 
       
   791 	case EBTRegistryUpdateLocalDevice:
       
   792 		{
       
   793 		TPckgBuf<TBTLocalDevice> pckg;
       
   794 		aMessage.ReadL(0, pckg);
       
   795 		static_cast<CBTLocalDeviceSubSession*>(&ss)->UpdateL(pckg(), aMessage);
       
   796 		break;
       
   797 		}
       
   798 
       
   799 	case EBTRegistryGetCommPortSettings:
       
   800 		{
       
   801 		TPckgBuf<TBTCommPortSettings> pckg;
       
   802 		aMessage.ReadL(0, pckg);
       
   803 		static_cast<CBTCommPortSettingsSubSession*>(&ss)->GetL(pckg(), aMessage);
       
   804 		break;
       
   805 		}
       
   806 
       
   807 	case EBTRegistryUpdateCommPortSettings:
       
   808 		{
       
   809 		TPckgBuf<TBTCommPortSettings> pckg;
       
   810 		aMessage.ReadL(0, pckg);
       
   811 		static_cast<CBTCommPortSettingsSubSession*>(&ss)->UpdateL(pckg(), aMessage);
       
   812 		break;
       
   813 		}
       
   814 
       
   815 	case EBTRegistryDeleteCommPortSettings:
       
   816 		{
       
   817 		TPckgBuf<TBTCommPortSettings> pckg;
       
   818 		aMessage.ReadL(0, pckg);
       
   819 		static_cast<CBTCommPortSettingsSubSession*>(&ss)->DeleteL(pckg(), aMessage);
       
   820 		break;
       
   821 		}
       
   822 
       
   823 	case EBTRegistryUnpairView:
       
   824 		{
       
   825 		static_cast<CBTRegistrySubSession*>(&ss)->UnpairViewL(aMessage);
       
   826 		break;
       
   827 		}
       
   828 		
       
   829 	case EBTRegistryCloseView:
       
   830 		{
       
   831 		static_cast<CBTRegistrySubSession*>(&ss)->CloseView(aMessage);
       
   832 		break;
       
   833 		}	
       
   834 	
       
   835 	case EBTRegistryNotifyViewChange:
       
   836 		{
       
   837 		ss.SetViewChangeNotificationMessage(aMessage);
       
   838 		break;
       
   839 		}
       
   840 		
       
   841 	case EBTHostResolverDeviceRequest:
       
   842 	case EBTHostResolverDeviceModifyDevice:
       
   843 	default:
       
   844 		PanicClient(aMessage, EBTManBadRequest, this);
       
   845 		return;
       
   846 		}
       
   847 	}
       
   848 
       
   849 void CBTManSession::NewSubSessionL(TSubSessionType aType, const RMessage2 &aMessage)
       
   850 /**
       
   851 Create a subsession of type aType and add it to the object index.
       
   852 **/
       
   853 	{
       
   854 	LOG_FUNC
       
   855 	//Make new counter object
       
   856 	CBTManSubSession* ss = NULL;
       
   857 	switch (aType)
       
   858 		{
       
   859 	case ERegistry:
       
   860 		ss = CBTRegistrySubSession::NewL(*this, iRegistry);
       
   861 		break;
       
   862 	case ELocalDevice:
       
   863 		ss = CBTLocalDeviceSubSession::NewL(*this, iRegistry);
       
   864 		break;
       
   865 	case ECommPortSettings:
       
   866 		ss = CBTCommPortSettingsSubSession::NewL(*this, iRegistry);
       
   867 		break;
       
   868 	case EHostResolver:
       
   869 	default:
       
   870 		PanicServer(EBTManBadSubSessionType);
       
   871 		}
       
   872 
       
   873 	//add to container to generate unique id
       
   874 	//If anything goes wrong, make sure we close the subsession.
       
   875 	CleanupClosePushL(*ss);
       
   876 
       
   877 	iContainer->AddL(ss);
       
   878 
       
   879 	//add to object index - this returns a unique handle
       
   880 	// From inspection of CObjectIx::AddL(), it will can only leave BEFORE ss is added to the index.
       
   881 	// Therefore, we must close the subsession and leave if anything goes wrong, 
       
   882 	// and NOT call CObjectIx::Remove().
       
   883 	TInt handle = 0;
       
   884 	handle = iSubSessions->AddL(ss);
       
   885 
       
   886 	//ss now has an owner so we can pop it off the cleanupstack
       
   887 	CleanupStack::Pop();	//ss
       
   888 
       
   889 	//Write handle to client
       
   890 	//If anything goes wrong, call CObjectIx::Remove(). This will close the subsession for us.
       
   891 	TPckg<TInt> pckg(handle);
       
   892 	TRAPD(err, aMessage.WriteL(3, pckg));
       
   893 	if (err!=KErrNone)
       
   894 		{
       
   895 		iSubSessions->Remove(handle);
       
   896 		User::Leave(err);
       
   897 		}
       
   898 	//increase resource count
       
   899 	iResourceCount++;
       
   900 	}
       
   901 
       
   902 void CBTManSession::DeleteSubsession(TInt aHandle, const RMessage2 &aMessage)
       
   903 	{
       
   904 	LOG_FUNC
       
   905 	//panic client if bad handle
       
   906 	CBTManSubSession* ss = (CBTManSubSession*)iSubSessions->At(aHandle);
       
   907 	if (ss == NULL)
       
   908 		{
       
   909 		PanicClient(aMessage, EBTManBadSubSessionRemove, this);
       
   910 		//Flag that Client has been panic'd 
       
   911 		//so that the message is not completed twice
       
   912 		iClientPanic = ETrue;
       
   913 		}
       
   914 	else
       
   915 		{
       
   916 		iSubSessions->Remove(aHandle);
       
   917 		//decrement resource count
       
   918 		iResourceCount--;
       
   919 		}
       
   920 	}
       
   921 
       
   922 void CBTManSession::CloseSubSession(const RMessage2 &aMessage)
       
   923 	{
       
   924 	LOG_FUNC
       
   925 	// handle for subsession is in slot3
       
   926 	DeleteSubsession(aMessage.Int3(), aMessage);
       
   927 	}
       
   928 
       
   929 void CBTManSession::CompleteMessage(const RMessage2& aMessage, TInt aReason)
       
   930 /**
       
   931 Finds a message based on aMessage and completes it.
       
   932 **/
       
   933 	{
       
   934 	LOG_FUNC
       
   935 	CBTManMessage* m = FindMessage(aMessage);
       
   936 	__ASSERT_DEBUG(m!=NULL, PanicServer(EBTManBadBTManMessage));
       
   937 	DoCompleteMessage(*m, aReason);
       
   938 	}
       
   939 
       
   940 void CBTManSession::CompleteMessage(MBTManHelper* aHelper, TInt aReason)
       
   941 /**
       
   942 Finds a message based on aHelper and completes it.
       
   943 **/
       
   944 	{
       
   945 	LOG_FUNC
       
   946 	CBTManMessage* m = FindMessage(aHelper);
       
   947 	__ASSERT_DEBUG(m!=NULL, PanicServer(EBTManBadBTManMessage));
       
   948 	DoCompleteMessage(*m, aReason);
       
   949 	}
       
   950 
       
   951 void CBTManSession::DoCompleteMessage(CBTManMessage& aMessage, TInt aReason)
       
   952 /**
       
   953 	Actually does the completion
       
   954 **/
       
   955 	{
       
   956 	LOG_FUNC
       
   957 	if (aMessage.Message().Ptr2())
       
   958 		{
       
   959 		// notify clientAPI that we've serviced it - not needed if the client has
       
   960 		// not asked us to (typically for synchronous calls)
       
   961 		TBTManClientServerMessage clientMsg;
       
   962 		TPckg<TBTManClientServerMessage> clientMsgBuf(clientMsg);
       
   963 		TRAPD(err_read, aMessage.Message().ReadL(KBTManClientServerProtocolSlot, clientMsgBuf));
       
   964 		clientMsg.iClientBusy=EFalse;
       
   965 		TRAPD(err_write, aMessage.Message().WriteL(KBTManClientServerProtocolSlot, clientMsgBuf));
       
   966 		
       
   967 		if(err_read != KErrNone || err_write != KErrNone)
       
   968 			{
       
   969 			PanicClient(aMessage.Message(),EBTManBadBTManMessage, this);
       
   970 			return;
       
   971 			}
       
   972 		}
       
   973 	// now tell the kernel
       
   974 	aMessage.Complete(aReason);
       
   975 	DeleteMessage(&aMessage);
       
   976 	}
       
   977 
       
   978 CBTManMessage* CBTManSession::FindMessage(const RMessage2& aMessage)
       
   979 /**
       
   980 Searches the array of CBTManMessages for the one dealing with aMessage.
       
   981 **/
       
   982 	{
       
   983 	LOG_FUNC
       
   984 	CBTManMessage* ptr;
       
   985 	for (TInt i=0; i<iMessageArray->Count(); i++)
       
   986 		{
       
   987 		ptr = iMessageArray->At(i);
       
   988 		if(ptr->Message() == aMessage)
       
   989 			{
       
   990 			return ptr;
       
   991 			}
       
   992 		}
       
   993 	return NULL;
       
   994 	}
       
   995 
       
   996 CBTManMessage* CBTManSession::FindMessage(MBTManHelper* aHelper)
       
   997 /**
       
   998 Searches the array of CBTManMessages for the one containing a pointer to aHelper.
       
   999 **/
       
  1000 	{
       
  1001 	LOG_FUNC
       
  1002 	CBTManMessage* ptr;
       
  1003 	for (TInt i=0; i<iMessageArray->Count(); i++)
       
  1004 		{
       
  1005 		ptr = iMessageArray->At(i);
       
  1006 		if(ptr->Helper() == aHelper)
       
  1007 			{
       
  1008 			return ptr;
       
  1009 			}
       
  1010 		}
       
  1011 	return NULL;
       
  1012 	}
       
  1013 
       
  1014 void CBTManSession::DeleteMessage(CBTManMessage* aMessage)
       
  1015 /**
       
  1016 Find the CBTManMessage in the message array and delete it.
       
  1017 **/
       
  1018 	{
       
  1019 	LOG_FUNC
       
  1020 	CBTManMessage* ptr;
       
  1021 	TInt count = iMessageArray->Count();
       
  1022 	for (TInt i=(count-1); i>=0; i--)
       
  1023 		{
       
  1024 		ptr = iMessageArray->At(i);
       
  1025 		if(ptr == aMessage)
       
  1026 			{
       
  1027 			//Delete the message first before removing from the array since a helper associated
       
  1028 			//with the message will try to find the message by parsing the array as part of the
       
  1029 			//destruction the message.
       
  1030 			delete ptr;
       
  1031 			iMessageArray->Delete(i);
       
  1032 			ptr = NULL;
       
  1033 			break;
       
  1034 			}
       
  1035 		}
       
  1036 	//compress the array if the count is less than the length - granularity AND if the count != 0
       
  1037 	if (iMessageArray->Count())
       
  1038 		{
       
  1039 		if (iMessageArray->Length() - iMessageArray->Count() >= KMessageArrayGranularity)
       
  1040 			{
       
  1041 			iMessageArray->Compress();
       
  1042 			}
       
  1043 		}
       
  1044 	}
       
  1045 
       
  1046 void CBTManSession::CancelRequest(const RMessage2& aMessage)
       
  1047 /**
       
  1048 Cancels an asyncronous request.
       
  1049  We need to find the asynchronous message we are cancelling
       
  1050  - we can do this by comparing the TRequestStatus held
       
  1051  in Ptr2() of the message.  This is ok since ALL asynchronous
       
  1052  requests to this server have the TRequestStatus passed over
       
  1053  in Ptr2() and only these may be cancelled. The TRequestStatus
       
  1054  is sent over in ptr0() of the cancel request so we don't confuse
       
  1055  the cancel message with the one we are trying to cancel.
       
  1056 **/
       
  1057 	{
       
  1058 	LOG_FUNC
       
  1059 	CBTManMessage* m;
       
  1060 	TInt count = iMessageArray->Count();
       
  1061 	for (TInt i=(count-1); i>=0; i--)
       
  1062 		{
       
  1063 		m = iMessageArray->At(i);
       
  1064 		if (m->CancelPtr() == aMessage.Ptr0())
       
  1065 			{
       
  1066 			//Complete the message
       
  1067 			m->Complete(KErrCancel);
       
  1068 			//delete the message from the array
       
  1069 			iMessageArray->Delete(i);
       
  1070 			delete m;
       
  1071 			m = NULL;
       
  1072 			break;
       
  1073 			}
       
  1074 		}
       
  1075 	//aMessage will be completed by CBTManSession::ServiceL()
       
  1076 	}
       
  1077 
       
  1078 TBool CBTManSession::SubSessionHasOverlappingView(CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor)
       
  1079 	{
       
  1080 	LOG_FUNC
       
  1081 	// Iterate over all subsessions apart from the view owner
       
  1082 	TBool overlapFound = EFalse;
       
  1083 	for (TInt i = 0; i < iContainer->Count(); i++)
       
  1084 		{
       
  1085 		CBTManSubSession* ss = static_cast<CBTManSubSession*>((*iContainer)[i]);
       
  1086 		if (&aSubSessionViewOwner != ss)
       
  1087 			{
       
  1088 			if (ss->IsOverlappingView(aViewDescriptor))
       
  1089 				{
       
  1090 				// Overlaps - subsession will have completed the Notify message
       
  1091 				// With bool return, we can test if indeed it did.
       
  1092 				overlapFound = ETrue;
       
  1093 				}
       
  1094 			}
       
  1095 		}
       
  1096 
       
  1097 	return overlapFound;
       
  1098 	}
       
  1099 
       
  1100 
       
  1101 //=====================================================================
       
  1102 //	CBTManSubSession
       
  1103 //=====================================================================
       
  1104 
       
  1105 CBTManSubSession::CBTManSubSession(CBTManSession& aSession, CBTRegistry& aRegistry) :
       
  1106 	iSession(aSession), iRegistry(aRegistry)
       
  1107 	{
       
  1108 	LOG_FUNC
       
  1109 	}
       
  1110 
       
  1111 void CBTManSubSession::NotifyChange(TUint aTableChanged)
       
  1112 	{
       
  1113 	LOG_FUNC
       
  1114 	iSession.Server().Publish(KPropertyKeyBluetoothGetRegistryTableChange,
       
  1115 							  aTableChanged);
       
  1116 	}
       
  1117 
       
  1118 void CBTManSubSession::NotifyChange(TUint aTableChanged, CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor)
       
  1119 	{
       
  1120 	LOG_FUNC
       
  1121 	NotifyChange(aTableChanged);
       
  1122 	iSession.Server().NotifyViewChange(aSubSessionViewOwner, aViewDescriptor);
       
  1123 	}	
       
  1124 
       
  1125 /*virtual*/ TBool CBTManSubSession::IsOverlappingView(const TDesC& /*aViewDescriptor*/)
       
  1126 	{
       
  1127 	LOG_FUNC
       
  1128 	// By default, not supported - so no overlapping view.
       
  1129 	return EFalse;
       
  1130 	}
       
  1131 
       
  1132 /*virtual*/ void CBTManSubSession::SetViewChangeNotificationMessage(const RMessage2& aMessage)
       
  1133 	{
       
  1134 	LOG_FUNC
       
  1135 	// By default, not supported
       
  1136 	iSession.CompleteMessage(aMessage, KErrNotSupported);
       
  1137 	}
       
  1138 
       
  1139 #ifdef __BTMANSERVER_NO_PROCESSES__
       
  1140 
       
  1141 // The server binary is an "EPOCEXE" target type
       
  1142 // Thus the server parameter passing and startup code for WINS and EPOC are
       
  1143 // significantly different.
       
  1144 //
       
  1145 // In EKA1 WINS, the EPOCEXE target is a DLL with an entry point called WinsMain,
       
  1146 // taking no parameters and returning TInt. This is not really valid as a thread
       
  1147 // function which takes a TAny* parameter which we need.
       
  1148 //
       
  1149 // So the DLL entry-point WinsMain() is used to return a TInt representing the
       
  1150 // real thread function within the DLL. This is good as long as
       
  1151 // sizeof(TInt)>=sizeof(TThreadFunction).
       
  1152 //
       
  1153 
       
  1154 static TInt ThreadFunction(TAny*)
       
  1155 //
       
  1156 // WINS thread entry-point function.
       
  1157 //
       
  1158 	{
       
  1159 	LOG_FUNC
       
  1160 	return E32Main();
       
  1161 	}
       
  1162 
       
  1163 IMPORT_C TInt WinsMain();
       
  1164 EXPORT_C TInt WinsMain()
       
  1165 //
       
  1166 // WINS DLL entry-point. Just return the real thread function 
       
  1167 // cast to TInt
       
  1168 //
       
  1169 	{
       
  1170 	LOG_FUNC
       
  1171 	return reinterpret_cast<TInt>(&ThreadFunction);
       
  1172 	}
       
  1173 
       
  1174 TInt E32Dll(TDllReason)
       
  1175 	{
       
  1176 	LOG_FUNC
       
  1177 	return KErrNone;
       
  1178 	}
       
  1179 
       
  1180 #endif