sl@0: /* sl@0: * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * CScsSession implementation. See class and function definitions sl@0: * for more detail. sl@0: * sl@0: */ sl@0: sl@0: sl@0: /** sl@0: @file sl@0: */ sl@0: sl@0: sl@0: #include sl@0: #include "scsserverconstants.h" sl@0: sl@0: EXPORT_C void CScsSession::ConstructL() sl@0: /** sl@0: The subsession [handle] container could be constructed sl@0: here, but that is deferred until the subsession is allocated to sl@0: avoid the memory overhead for sessions which may not require sl@0: subsessions. sl@0: */ sl@0: { sl@0: iServer.IncrementSessionCount(); sl@0: } sl@0: sl@0: EXPORT_C CScsSession::CScsSession(CScsServer &aServer) sl@0: : iServer(aServer) sl@0: /** sl@0: Setup the iServer member variable so it can be used during construction sl@0: */ sl@0: { sl@0: } sl@0: sl@0: sl@0: EXPORT_C CScsSession::~CScsSession() sl@0: /** sl@0: Deletes any subsessions. sl@0: sl@0: Deletes any outstanding requests. sl@0: sl@0: Decrements the server's session count so the server can be shut down sl@0: if there are no open sessions. sl@0: */ sl@0: { sl@0: iServer.CancelOutstandingRequests(this, /* aCompleteClientRequests */ EFalse); sl@0: sl@0: DeleteSubsessionContainers(); // closes any remaining subsessions sl@0: sl@0: // decrement the session count, so the server can be shut down if sl@0: // there are no more open sessions. sl@0: iServer.DecrementSessionCount(); sl@0: } sl@0: sl@0: EXPORT_C void CScsSession::CloseAllSubsessionsL() sl@0: { sl@0: DeleteSubsessionContainers(); sl@0: } sl@0: sl@0: EXPORT_C void CScsSession::ServiceL(const RMessage2& aMessage) sl@0: /** sl@0: Implement CSession2 by handling any SCS-specific messages, and sl@0: otherwise delegating to the subclass' implementation. sl@0: sl@0: @param aMessage Standard server-side message object. sl@0: */ sl@0: { sl@0: ScsImpl::TScsFunction scsFunc; sl@0: TInt implFunc; sl@0: ScsImpl::ExtractScsAndImplFunctions(aMessage, &scsFunc, &implFunc); sl@0: TBool completeMessage = ETrue; sl@0: sl@0: switch (scsFunc) sl@0: { sl@0: // sessions sl@0: case ScsImpl::ECallSessionFunc: sl@0: completeMessage = DoServiceL(implFunc, aMessage); sl@0: break; sl@0: sl@0: case ScsImpl::EPreCloseSession: sl@0: PreCloseSession(); sl@0: break; sl@0: sl@0: case ScsImpl::ECancelSessionFunc: sl@0: CancelAsyncSessionRequestL(implFunc); sl@0: break; sl@0: sl@0: case ScsImpl::EGetServerPid: sl@0: { sl@0: TPckgBuf idBuf; sl@0: RProcess proc; sl@0: idBuf() = proc.Id(); sl@0: aMessage.WriteL(0, idBuf); sl@0: break; sl@0: } sl@0: sl@0: case ScsImpl::EShutdownAsap: sl@0: iServer.ShutdownWhenIdleL(); sl@0: break; sl@0: sl@0: // subsessions sl@0: case ScsImpl::ECreateSubsession: sl@0: // if there are no open subsessions before this attempt then clean up sl@0: // the containers if it fails. This is to ensure the server heap balances sl@0: // in the event of failure. sl@0: iPreCreateSubsessionCount = iSsHandles ? iSsHandles->ActiveCount() : 0; sl@0: CreateSubsessionL(implFunc, aMessage); sl@0: break; sl@0: sl@0: case ScsImpl::ECloseSubsession: sl@0: CloseSubsessionL(aMessage); sl@0: break; sl@0: sl@0: case ScsImpl::ECallSubsessionFunc: sl@0: completeMessage = CallSubsessionFunctionL(implFunc, aMessage); sl@0: break; sl@0: sl@0: case ScsImpl::ECancelSubsessionFunc: sl@0: CancelAsyncSubsessionRequestL(implFunc, aMessage); sl@0: break; sl@0: sl@0: // server heap testing sl@0: case ScsImpl::EUHeapSetFail: sl@0: #ifdef _DEBUG sl@0: iServer.DoPreHeapMarkOrCheckL(); sl@0: __UHEAP_MARK; sl@0: __UHEAP_SETFAIL(RAllocator::EDeterministic, aMessage.Int0()); sl@0: iServer.DoPostHeapMarkOrCheckL(); sl@0: #endif sl@0: break; sl@0: sl@0: case ScsImpl::EUHeapResetFail: sl@0: #ifdef _DEBUG sl@0: iServer.DoPreHeapMarkOrCheckL(); sl@0: __UHEAP_RESET; sl@0: __UHEAP_MARKEND; sl@0: iServer.DoPostHeapMarkOrCheckL(); sl@0: #endif sl@0: break; sl@0: sl@0: // unrecognized SCS code, so fail with KErrNotSupported sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: // None of the delegate functions have left so complete with KErrNone. sl@0: if(completeMessage) sl@0: { sl@0: aMessage.Complete(KErrNone); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CScsSession::ServiceError(const RMessage2& aMessage, TInt aError) sl@0: /** sl@0: Override CSession2 by handling any leave which occurred during the ServiceL. sl@0: sl@0: Panick the client if the leave is because of a bad descriptor or subsession sl@0: handle. Otherwise, complete the request with the error code. sl@0: sl@0: @param aMessage Message which caused leave to occur. sl@0: @param aError Leave code. This is a Symbian OS error code. sl@0: @see CSession2::ServiceError sl@0: */ sl@0: { sl@0: // if failed to create first subsession then free containers so heap sl@0: // balances after message has been completed. sl@0: sl@0: ScsImpl::TScsFunction scsFunc; sl@0: ScsImpl::ExtractScsAndImplFunctions(aMessage, &scsFunc, NULL); sl@0: sl@0: if (scsFunc == ScsImpl::ECreateSubsession && iPreCreateSubsessionCount == 0) sl@0: DeleteSubsessionContainers(); sl@0: sl@0: switch (aError) sl@0: { sl@0: case KErrBadDescriptor: sl@0: PanicClient(aMessage, ScsImpl::EScsClBadDesc); sl@0: break; sl@0: sl@0: case KErrBadHandle: sl@0: PanicClient(aMessage, ScsImpl::EScsClBadHandle); sl@0: break; sl@0: sl@0: case KErrScsAsyncAlreadyQueued: sl@0: PanicClient(aMessage, ScsImpl::EScsClAsyncAlreadyQueued); sl@0: break; sl@0: sl@0: default: sl@0: aMessage.Complete(aError); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // -------- session close -------- sl@0: sl@0: void CScsSession::PreCloseSession() sl@0: /** sl@0: This function is invoked from RScsClientBase::Close sl@0: just before the session is closed, to cancel any sl@0: outstanding requests. sl@0: */ sl@0: { sl@0: iServer.CancelOutstandingRequests(this, /* aCompleteClientRequests */ ETrue); sl@0: } sl@0: sl@0: // -------- asynchronous requests -------- sl@0: sl@0: void CScsSession::CancelAsyncSessionRequestL(TInt aFunction) sl@0: /** sl@0: This function is called when handling an ECancelSessionFunction message. sl@0: If the outstanding function cannot be found, this function does nothing. sl@0: sl@0: @param aFunction Implementation function without SCS code. sl@0: */ sl@0: { sl@0: iServer.CancelAsyncRequest(this, /* aSubsession */ 0, aFunction); sl@0: } sl@0: sl@0: // -------- subsessions -------- sl@0: sl@0: CScsSubsession* CScsSession::GetSubsessionL(const RMessage2& aMessage) sl@0: /** sl@0: Extract subsession handle from the supplied message and return sl@0: a pointer to the corresponding subsession object. sl@0: sl@0: @param aMessage Standard server-side message object. The fourth sl@0: argument is the subsession handle. sl@0: @return Pointer to corresponding subsession object. sl@0: @leave KErrBadHandle if the handle does not identify a sl@0: current subsession. sl@0: */ sl@0: { sl@0: TInt handle = aMessage.Int3(); sl@0: CObject* obj = iSsHandles->AtL(handle); // leaves with KErrBadHandle if not found sl@0: return static_cast(obj); sl@0: } sl@0: sl@0: void CScsSession::DeleteSubsessionContainers() sl@0: /** sl@0: Free the handle and object containers which this session uses sl@0: to manage subsessions. It is safe to call this function if the sl@0: containers were not set up successfully. sl@0: */ sl@0: { sl@0: delete iSsHandles; sl@0: iSsHandles = 0; sl@0: sl@0: if (iSsObjects != 0) sl@0: { sl@0: iServer.iContainerIndex->Remove(iSsObjects); sl@0: iSsObjects = 0; sl@0: } sl@0: } sl@0: sl@0: void CScsSession::CreateSubsessionL(TInt aFunction, const RMessage2& aMessage) sl@0: /** sl@0: Attempt to allocate a subsession object for this session. The actual sl@0: subsession allocation is delegated to the subclass's implementation sl@0: of DoCreateSubsessionL. If the subclass has not reimplemented this sl@0: function, then default implementation leaves with KErrNotSupported. sl@0: sl@0: @param aFunction Function identifier without SCS code. sl@0: @param aMessage Standard server-side message object. sl@0: */ sl@0: { sl@0: // if this is the first subsession then create the object container and index sl@0: if (iSsObjects == 0) sl@0: { sl@0: iSsObjects = iServer.iContainerIndex->CreateL(); sl@0: iSsHandles = CObjectIx::NewL(); sl@0: } sl@0: sl@0: CScsSubsession* ss = DoCreateSubsessionL(aFunction, aMessage); sl@0: CleanupClosePushL(*ss); sl@0: sl@0: iSsObjects->AddL(ss); sl@0: TInt handle = iSsHandles->AddL(ss); sl@0: CleanupStack::Pop(ss); sl@0: sl@0: TPckg handlePckg(handle); sl@0: TInt r = aMessage.Write(3, handlePckg); sl@0: User::LeaveIfError(r); sl@0: } sl@0: sl@0: #ifdef _BullseyeCoverage sl@0: static const char * const bull1="BullseyeCoverage save off"; sl@0: #endif sl@0: EXPORT_C CScsSubsession* CScsSession::DoCreateSubsessionL(TInt aFunction, const RMessage2& aMessage) sl@0: /** sl@0: This default implementation leaves with KErrNotSupported. The subclass sl@0: does not have to supply its own implementation unless it actually wants sl@0: to support subsessions. sl@0: sl@0: @param aFunction Function identifier without SCS code. The subclass sl@0: implementation of this function would use this to decide sl@0: what kind of subsession object to create. sl@0: @param aMessage Client message. Not used. sl@0: @leave KErrNotSupported. sl@0: */ sl@0: { sl@0: (void) aFunction; sl@0: (void) aMessage; sl@0: sl@0: User::Leave(KErrNotSupported); sl@0: /*lint -unreachable*/ // Avoid compiler warning and keep lint happy sl@0: return 0; sl@0: } sl@0: #ifdef _BullseyeCoverage sl@0: static const char * const bull2="BullseyeCoverage restore"; sl@0: #endif sl@0: sl@0: void CScsSession::CloseSubsessionL(const RMessage2& aMessage) sl@0: /** sl@0: Delete the subsession identified in the supplied message. sl@0: sl@0: If the subsession cannot be found this function leaves with KErrBadHandle, sl@0: and the client is panicked in ServiceError. sl@0: sl@0: @param aMessage Standard server-side message handle. The fourth sl@0: integer contains the subsession handle. sl@0: */ sl@0: { sl@0: TInt handle = aMessage.Int3(); sl@0: CObject* obj = iSsHandles->AtL(handle); // leaves with KErrBadHandle if not found sl@0: CScsSubsession* ss = static_cast(obj); sl@0: sl@0: iServer.CancelOutstandingRequests(this, ss, /* aCancelClientRequests */ ETrue); sl@0: sl@0: iSsHandles->Remove(handle); sl@0: sl@0: // close the container objects to ensure the heap balances when the last subsession is closed sl@0: if (iSsHandles->ActiveCount() == 0) sl@0: DeleteSubsessionContainers(); sl@0: } sl@0: sl@0: TBool CScsSession::CallSubsessionFunctionL(TInt aFunction, const RMessage2& aMessage) sl@0: /** sl@0: Pass the supplied function identifier and message to the subsession sl@0: which is identified in the message. sl@0: sl@0: If the subsession cannot be found this function leaves with KErrBadHandle, sl@0: and the client is panicked in ServiceError. sl@0: sl@0: @param aFunction Function identifier without SCS code. sl@0: @param aMessage Client message. sl@0: @return ETrue means complete client request now. sl@0: sl@0: */ sl@0: { sl@0: CScsSubsession* ss = GetSubsessionL(aMessage); sl@0: return ss->DoServiceL(aFunction, aMessage); sl@0: } sl@0: sl@0: void CScsSession::CancelAsyncSubsessionRequestL(TInt aFunction, const RMessage2& aMessage) sl@0: /** sl@0: Cancel an outstanding asynchronous request for the subsession sl@0: identified in the supplied message. sl@0: sl@0: @param aFunction Function identifier without SCS code. sl@0: @param aMessage Standard server-side message handle. The fourth sl@0: integer contains the subsession handle. sl@0: */ sl@0: { sl@0: CScsSubsession* ss = GetSubsessionL(aMessage); sl@0: iServer.CancelAsyncRequest(this, ss, aFunction); sl@0: } sl@0: