kernel/eka/euser/cbase/ub_svr.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1995-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 the License "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 // e32\euser\cbase\ub_svr.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "ub_std.h"
       
    19 //#define __DEBUG_IMAGE__ 1
       
    20 #if defined(__DEBUG_IMAGE__) && defined (__EPOC32__)
       
    21 #include "e32svr.h" 
       
    22 #define __IF_DEBUG(t) {RDebug debug;debug.t;}
       
    23 #else
       
    24 #define __IF_DEBUG(t)
       
    25 #endif
       
    26 
       
    27 
       
    28 
       
    29 _LIT(KSessionPanicCategory,"CSession");
       
    30 _LIT(KServerPanicCategory,"CServer");
       
    31 
       
    32 
       
    33 
       
    34 /**
       
    35 Default constructor.
       
    36 
       
    37 This constructor is empty.
       
    38 */
       
    39 EXPORT_C CSession2::CSession2()
       
    40 	{}
       
    41 
       
    42 
       
    43 
       
    44 /**
       
    45 Destructor.
       
    46 
       
    47 It frees resources prior to destruction of the object.
       
    48 Specifically, it removes this session object from the server
       
    49 active object’s list of sessions.
       
    50 */
       
    51 EXPORT_C CSession2::~CSession2()
       
    52 	{
       
    53 	if (iLink.iNext)
       
    54 		iLink.Deque();
       
    55 	}
       
    56 
       
    57 
       
    58 
       
    59 /**
       
    60 Completes construction of this server-side client session object.
       
    61 
       
    62 The function is called by the server active object, the CServer2 derived
       
    63 class instance, when a client makes a connection request.
       
    64 
       
    65 The connection request results in the creation of this session object,
       
    66 followed by a call to this function.
       
    67 
       
    68 The default implementation is empty.
       
    69 
       
    70 @see CServer2::NewSessionL()
       
    71 */
       
    72 EXPORT_C void CSession2::CreateL()
       
    73 	{
       
    74 	}
       
    75 
       
    76 /**
       
    77 Designates the (master or slave) server that is to service this session.
       
    78 
       
    79 This may be called from the NewSessionL() method of the CServer2-derived
       
    80 class or from the CreateL() method of the CSession2-derived class.
       
    81 
       
    82 It must not be called after CreateL() has finished, as this is the point
       
    83 at which the session binding become irrevocable.
       
    84 
       
    85 @see CServer::DoConnect()
       
    86 */
       
    87 EXPORT_C void CSession2::SetServer(const CServer2* aServer)
       
    88 	{
       
    89 	ASSERT(iLink.iNext == NULL);
       
    90 	ASSERT(aServer);
       
    91 	iServer = aServer;
       
    92 	}
       
    93 
       
    94 /**
       
    95 Handles the situation when a call to CSession2::ServiceL(), which services
       
    96 a client request, leaves.
       
    97 
       
    98 Servers are active objects, and the call to CSession2::ServiceL() to handle
       
    99 a client request is executed as part of the server's active object RunL()
       
   100 function. If the RunL() leaves, the active object framework calls the active
       
   101 object's RunError() function. The server framework implements this as a call
       
   102 to ServiceError()
       
   103 
       
   104 The default behaviour of this function is to complete the message, using
       
   105 the leave value, if it has not already been completed.
       
   106 
       
   107 Servers can re-implement this as appropriate.
       
   108 
       
   109 @param aMessage The message containing the details of the client request that
       
   110                 caused the leave.
       
   111 @param aError   The leave code.
       
   112 
       
   113 @see CActive::RunL()
       
   114 @see CActive::RunError()
       
   115 */
       
   116 EXPORT_C void CSession2::ServiceError(const RMessage2& aMessage,TInt aError)
       
   117 	{
       
   118 	if(!aMessage.IsNull())
       
   119 		aMessage.Complete(aError);
       
   120 	}
       
   121 
       
   122 
       
   123 
       
   124 /**
       
   125 Called by a server when it receives a disconnect message for the session.
       
   126 	
       
   127 This message is sent by the kernel when all client handles to the session have
       
   128 been closed.
       
   129 This method deletes the session object and completes the disconnect message.
       
   130 
       
   131 A derived session implementation may overide this virtual method if it needs to
       
   132 perform any asynchronous cleanup actions, these actions must end with a call to the
       
   133 base class implementation of this method, which will delete the session object
       
   134 and complete the disconnect message
       
   135 
       
   136 @param aMessage The disconnect message.
       
   137 
       
   138 @post 'this' session object has been deleted.
       
   139 */
       
   140 EXPORT_C void CSession2::Disconnect(const RMessage2& aMessage)
       
   141 	{
       
   142 	delete this;
       
   143 	aMessage.Complete(0);
       
   144 	}
       
   145 
       
   146 
       
   147 
       
   148 /**
       
   149 Marks the start of resource count checking.
       
   150 
       
   151 It sets up a starting value for resource count checking.
       
   152 
       
   153 The function sets up a starting value for resource count checking by using
       
   154 the value returned by a call to CSession2::CountResources(), and is the value
       
   155 that will be used for comparison if CSession2::ResourceCountMarkEnd() is called
       
   156 at some later time.
       
   157 
       
   158 The client/server framework does not call this function (nor
       
   159 does it call CSession2::ResourceCountMarkEnd()), but is available for servers
       
   160 to use, if appropriate.
       
   161 
       
   162 @see CSession2::CountResources()
       
   163 @see CSession2::ResourceCountMarkEnd()
       
   164 */
       
   165 EXPORT_C void CSession2::ResourceCountMarkStart()
       
   166 	{
       
   167 	iResourceCountMark=CountResources();
       
   168 	}
       
   169 
       
   170 
       
   171 
       
   172 /**
       
   173 Marks the end of resource count checking.
       
   174 
       
   175 The function takes the current resource count by
       
   176 calling CSession2::CountResources(), and compares it with the resource count
       
   177 value saved when CSession2::ResourceCountMarkStart() was called.
       
   178 If the resource counts differ, then the client thread is panicked (CSession 2)".
       
   179 
       
   180 The client/server framework does not call this function (nor does it call 
       
   181 CSession2::ResourceCountMarkStart()), but the function is available for
       
   182 servers to use, if appropriate.
       
   183 
       
   184 @param aMessage Represents the details of the client request that is requesting
       
   185                 this resource check.
       
   186 
       
   187 @see CSession2::CountResources()
       
   188 @see CSession2::ResourceCountMarkStart()
       
   189 */
       
   190 EXPORT_C void CSession2::ResourceCountMarkEnd(const RMessage2& aMessage)
       
   191 	{
       
   192 	if (iResourceCountMark!=CountResources())
       
   193 		aMessage.Panic(KSessionPanicCategory,ESesFoundResCountHeaven);
       
   194 	}
       
   195 
       
   196 
       
   197 
       
   198 /**
       
   199 Gets the number of resources currently in use.
       
   200 
       
   201 Derived classes must provide a suitable implementation.
       
   202 The meaning of a resource depends on the design intent of the server.
       
   203 
       
   204 The default implementation panics the calling thread (CSession 1)
       
   205 before returning KErrGeneral.
       
   206 
       
   207 @return The current number of resources in use.
       
   208 
       
   209 @see CSession2::ResourceCountmarkStart()
       
   210 @see CSession2::ResourceCountmarkEnd()
       
   211 */
       
   212 EXPORT_C TInt CSession2::CountResources()
       
   213 	{
       
   214 	User::Panic(KSessionPanicCategory,ESesCountResourcesNotImplemented);
       
   215 	return KErrGeneral;
       
   216 	}
       
   217 
       
   218 
       
   219 
       
   220 /**
       
   221 Extension function
       
   222 
       
   223 
       
   224 */
       
   225 EXPORT_C TInt CSession2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
       
   226 	{
       
   227 	return CBase::Extension_(aExtensionId, a0, a1);
       
   228 	}
       
   229 
       
   230 
       
   231 
       
   232 
       
   233 /**
       
   234 Constructs the server object, specifying the server type and the active
       
   235 object priority.
       
   236 
       
   237 Derived classes must define and implement a constructor through which
       
   238 the priority can be specified. A typical implementation calls this server
       
   239 base class constructor through a constructor initialization list.
       
   240 
       
   241 @param aPriority The priority of this active object.
       
   242 @param aType     Indicates the type of session that the server creates.
       
   243                  If not explicitly stated, then the server creates
       
   244                  a session that is not sharable with other threads.
       
   245 */
       
   246 EXPORT_C CServer2::CServer2(TInt aPriority, TServerType aType)
       
   247 	:	CActive(aPriority),
       
   248 		iSessionType((TUint8)aType),
       
   249 		iSessionQ(_FOFF(CSession2,iLink)),
       
   250 		iSessionIter(iSessionQ)
       
   251 	{
       
   252 	ASSERT(iSessionType == aType);
       
   253 	__ASSERT_COMPILE(EServerRole_Default == 0);
       
   254 	__ASSERT_COMPILE(EServerOpt_PinClientDescriptorsDefault == 0);
       
   255 	}
       
   256 
       
   257 
       
   258 
       
   259 /**
       
   260 Frees resources prior to destruction.
       
   261 
       
   262 Specifically, it cancels any outstanding request for messages, and 
       
   263 deletes all server-side client session objects.
       
   264 */
       
   265 EXPORT_C CServer2::~CServer2()
       
   266 	{
       
   267 	Cancel();
       
   268 	while (!iSessionQ.IsEmpty())
       
   269 		{
       
   270 		CSession2 *pS=iSessionQ.First();
       
   271 		pS->iLink.Deque();
       
   272 		pS->iLink.iNext=0;
       
   273 		delete pS;
       
   274 		}
       
   275 	iServer.Close();
       
   276 	}
       
   277 
       
   278 
       
   279 /**
       
   280 Sets whether the kernel will pin descriptors passed to this server in the context of the client
       
   281 thread.
       
   282 
       
   283 Setting this is one way of ensuring that the server will not take page faults when accessing client
       
   284 descriptors, which would otherwise happen if the data was paged out.
       
   285 
       
   286 This method overrides the default pinning policy of the server which is for the server 
       
   287 to pin its client's descriptors if the process creating the server is not data paged.
       
   288 I.e. if CServer2::SetPinClientDescriptors() is not invoked on the server and 
       
   289 RProcess::DefaultDataPaged() of the process creating the server returns EFalse, 
       
   290 the server will pin its client's descriptors, otherwise the server will not pin its
       
   291 client's descriptors.
       
   292 
       
   293 This method must be called prior to starting the server by calling the Start() method.
       
   294 
       
   295 @param aPin	Set to ETrue for the server to pin its client's descriptors, set to 
       
   296 			EFalse otherwise.
       
   297 @panic E32USER-CBase 106 When this method is invoked after the server has been started.
       
   298 @see CServer2::Start()
       
   299 
       
   300 @prototype
       
   301 */
       
   302 EXPORT_C void CServer2::SetPinClientDescriptors(TBool aPin)
       
   303 	{
       
   304 	if (iServer.Handle() != KNullHandle)
       
   305 		{// Server already started so too late to make it a pinning one.
       
   306 		Panic(ECServer2InvalidSetPin);
       
   307 		}
       
   308 	iServerOpts &= ~EServerOpt_PinClientDescriptorsMask;
       
   309 	if (aPin)
       
   310 		iServerOpts |= EServerOpt_PinClientDescriptorsEnable;
       
   311 	else
       
   312 		iServerOpts |= EServerOpt_PinClientDescriptorsDisable;
       
   313 	}
       
   314 
       
   315 /**
       
   316 Assigns a role (master or slave) for this server.
       
   317 
       
   318 The master server is typically named, and receives all Connect messages
       
   319 from clients. It can hand off some sessions to be processed by one or
       
   320 more anonymous slave servers, each running in a separate thread.
       
   321 
       
   322 Both master and slave servers must call this function before calling
       
   323 Start(), in order to define their roles.  Once the server is started,
       
   324 its role cannot be changed.
       
   325 
       
   326 @panic E32USER-CBase-? When this method is invoked after the server has been started.
       
   327 @see CServer2::Start()
       
   328 
       
   329 @prototype
       
   330 */
       
   331 EXPORT_C void CServer2::SetMaster(const CServer2* aServer)
       
   332 	{
       
   333 	// Roles can only be assigned before the call to Start()
       
   334 	ASSERT(Server().Handle() == KNullHandle);
       
   335 
       
   336 	if (aServer == NULL)
       
   337 		iServerRole = EServerRole_Standalone;
       
   338 	else if (aServer == this)
       
   339 		iServerRole = EServerRole_Master;
       
   340 	else
       
   341 		iServerRole = EServerRole_Slave;
       
   342 	}
       
   343 
       
   344 
       
   345 /**
       
   346 Adds the server with the specified name to the active scheduler,
       
   347 and issues the first request for messages.
       
   348 
       
   349 If KNullDesC is specified for the name, then an anonymous server will be created.
       
   350 To create a session to such a server, an overload of RSessionBase::CreateSession()
       
   351 which takes RServer2 object as a parameter can be used.
       
   352 
       
   353 @param aName The name of the server.
       
   354              KNullDesC, to create anonymous servers.
       
   355 @return KErrNone, if successful, otherwise one of the other system wide error codes.
       
   356 
       
   357 @capability ProtServ if aName starts with a '!' character
       
   358 */
       
   359 EXPORT_C TInt CServer2::Start(const TDesC& aName)
       
   360 	{
       
   361 	TInt r = iServer.CreateGlobal(aName, iSessionType, iServerRole, iServerOpts);
       
   362 	if (r == KErrNone)
       
   363 		{
       
   364 		CActiveScheduler::Add(this);
       
   365 		ReStart();
       
   366 		}
       
   367 	return r;
       
   368 	}
       
   369 
       
   370 
       
   371 	
       
   372 /**
       
   373 Adds the server with the specified name to the active scheduler,
       
   374 and issues the first request for messages, and leaves if the operation fails.
       
   375 
       
   376 If KNullDesC is specified for the name, then an anonymous server will be created.
       
   377 To create a session to such a server, the overload of RSessionBase::CreateSession() 
       
   378 which takes an RServer2 object as a parameter can be used.
       
   379 
       
   380 @param aName The name of the server.
       
   381              KNullDesC, to create anonymous servers.
       
   382 @capability  ProtServ if aName starts with a '!' character
       
   383 */
       
   384 EXPORT_C void CServer2::StartL(const TDesC& aName)
       
   385 	{
       
   386 	User::LeaveIfError(Start(aName));
       
   387 	}
       
   388 
       
   389 
       
   390 
       
   391 /**
       
   392 Implements the cancellation of any outstanding request for messages.
       
   393 */
       
   394 EXPORT_C void CServer2::DoCancel()
       
   395 	{
       
   396 
       
   397 	iServer.Cancel();
       
   398 	}
       
   399 
       
   400 
       
   401 
       
   402 void CServer2::Connect(const RMessage2& aMessage)
       
   403 //
       
   404 // Handle a connect request. Ptr0()==Version.
       
   405 // NOTE: We don't want this to leave as that may kill the server
       
   406 //
       
   407 	{
       
   408 
       
   409 	if (aMessage.Session())
       
   410 		{
       
   411 		aMessage.Panic(KServerPanicCategory,ESessionAlreadyConnected);
       
   412 		return;
       
   413 		}
       
   414 	DoConnect(aMessage);
       
   415 	}
       
   416 
       
   417 
       
   418 
       
   419 //
       
   420 //This is all of the Leaving code for connection creation.
       
   421 //This is in a seperate function in an effort to force compilers to store aSession
       
   422 //on the stack which enables cleanup to perform correctly when a Leave occurs
       
   423 //
       
   424 void CServer2::DoConnectL(const RMessage2& aMessage,CSession2* volatile& aSession)
       
   425 	{
       
   426 	TVersion v;
       
   427 	*(TInt*)&v = aMessage.Int0();
       
   428 	aSession = NewSessionL(v, aMessage);
       
   429 	if (!aSession->iServer)
       
   430 		aSession->iServer = this;
       
   431 	aSession->CreateL();
       
   432 	iSessionQ.AddLast(*aSession);
       
   433 	Exec::SetSessionPtr(aMessage.Handle(), aSession);
       
   434 	}
       
   435 
       
   436 
       
   437 
       
   438 /**
       
   439 Handles the connect request from the client.  We trap Leaves, to ensure
       
   440 that existing sessions aren't affected by failure to create a new one.
       
   441 
       
   442 @param aMessage The Connect message sent by the client requesting the
       
   443                 connection. aMessage.Ptr0() is the required Version.
       
   444 */
       
   445 EXPORT_C void CServer2::DoConnect(const RMessage2& aMessage)
       
   446 	{
       
   447 	ASSERT(aMessage.Function() == RMessage2::EConnect);
       
   448 	ASSERT(aMessage.Session() == NULL);
       
   449 	ASSERT(!aMessage.IsNull());
       
   450 
       
   451 	CSession2* newSession = NULL;
       
   452 	TRAPD(err, DoConnectL(aMessage, newSession));
       
   453 	if (err != KErrNone)
       
   454 		{
       
   455 		// Connect failed
       
   456 		delete newSession;
       
   457 		aMessage.Complete(err);
       
   458 		}
       
   459 	else
       
   460 		{
       
   461 		ASSERT(newSession != NULL);
       
   462 		CServer2* sessionServer = const_cast<CServer2*>(newSession->Server());
       
   463 		ASSERT(sessionServer != NULL);
       
   464 
       
   465 		// The return value of Server() will be 'this', unless it was
       
   466 		// changed by a call to SetServer().
       
   467 		if (sessionServer == this)
       
   468 			{
       
   469 			// no SetServer() call, so just complete the Connect message
       
   470 			aMessage.Complete(err);
       
   471 			}
       
   472 		else
       
   473 			{
       
   474 			// Transfer the new Csession to the specified slave Cserver
       
   475 			newSession->iLink.Deque();
       
   476 			sessionServer->iSessionQ.AddLast(*newSession);
       
   477 
       
   478 			// Ask the kernel to transfer the DSession to the slave DServer.
       
   479 			// Note: this Exec call also completes the Connect message.
       
   480 			TInt msgHandle = aMessage.iHandle;
       
   481 			const_cast<TInt&>(aMessage.iHandle) = 0;
       
   482 			ASSERT(msgHandle);
       
   483 			Exec::TransferSession(msgHandle, sessionServer->Server().Handle());
       
   484 			}
       
   485 		}
       
   486 
       
   487 	ASSERT(aMessage.IsNull());
       
   488 	}
       
   489 
       
   490 
       
   491 
       
   492 /**
       
   493 Handles the situation where a call to CServer2::RunL(), leaves.
       
   494 
       
   495 This is the server active object's implementation of the active object
       
   496 framework's RunError() function.
       
   497 
       
   498 In practice, the leave can only be caused by a session's ServiceL() function,
       
   499 which is called from this RunL(); this error is reflected back to that session
       
   500 by calling its ServiceError() function.
       
   501 
       
   502 @param aError The leave code.
       
   503 
       
   504 @return KErrNone.
       
   505 
       
   506 @see CActive::RunL()
       
   507 @see CActive::RunError()
       
   508 @see CSession2::ServiceError()
       
   509 */
       
   510 EXPORT_C TInt CServer2::RunError(TInt aError)
       
   511 	{
       
   512 	Message().Session()->ServiceError(Message(),aError);
       
   513 	if (!IsActive())
       
   514 		ReStart();
       
   515 	return KErrNone;
       
   516 	}
       
   517 
       
   518 
       
   519 
       
   520 /**
       
   521 Restarts the server.
       
   522 
       
   523 The function issues a request for messages.
       
   524 */
       
   525 EXPORT_C void CServer2::ReStart()
       
   526 	{
       
   527 
       
   528 	iServer.Receive(iMessage,iStatus);
       
   529 	SetActive();
       
   530 	}
       
   531 
       
   532 
       
   533 
       
   534 #ifndef __CSERVER_MACHINE_CODED__
       
   535 /**
       
   536 Handles the receipt of a message.
       
   537 */
       
   538 EXPORT_C void CServer2::RunL()
       
   539 	{
       
   540 	TInt fn = Message().Function();
       
   541 
       
   542 	if(fn>=0)
       
   543 		{
       
   544 		// Service the message
       
   545 		CSession2* session=Message().Session();
       
   546 		if(session)
       
   547 			session->ServiceL(Message());
       
   548 		else
       
   549 			NotConnected(Message());
       
   550 		}
       
   551 	else if(fn==RMessage2::EConnect)
       
   552 		{
       
   553 		Connect(Message());
       
   554 		}
       
   555 	else if(fn==RMessage2::EDisConnect)
       
   556 		{
       
   557 		Disconnect(Message());
       
   558 		}
       
   559 	else
       
   560 		{
       
   561 		BadMessage(Message());
       
   562 		}
       
   563 	// Queue reception of next message if it hasn't already been done
       
   564 	if(!IsActive())
       
   565 		ReStart();
       
   566 	}
       
   567 
       
   568 #endif
       
   569 
       
   570 
       
   571 
       
   572 void CServer2::Disconnect(const RMessage2& aMessage)
       
   573 //
       
   574 // Process a disconnect message
       
   575 //
       
   576 	{
       
   577 	CSession2* session=Message().Session();
       
   578 	if(!session)
       
   579 		{
       
   580 		// Session not created yet, so just complete message.
       
   581 		aMessage.Complete(0);
       
   582 		return;
       
   583 		}
       
   584 	session->Disconnect(aMessage);
       
   585 	}
       
   586 
       
   587 
       
   588 
       
   589 void CServer2::BadMessage(const RMessage2& aMessage)
       
   590 	{
       
   591 	aMessage.Panic(KServerPanicCategory,EBadMessageNumber);
       
   592 	}
       
   593 
       
   594 
       
   595 
       
   596 void CServer2::NotConnected(const RMessage2& aMessage)
       
   597 	{
       
   598 	aMessage.Panic(KServerPanicCategory,ESessionNotConnected);
       
   599 	}
       
   600 
       
   601 	
       
   602 
       
   603 /**
       
   604 Extension function
       
   605 
       
   606 
       
   607 */
       
   608 EXPORT_C TInt CServer2::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
       
   609 	{
       
   610 	return CActive::Extension_(aExtensionId, a0, a1);
       
   611 	}