--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothmgmt/btmgr/BTManServer/BTManServer.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1180 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <s32mem.h>
+#include <e32svr.h>
+#include "BTManServer.h"
+
+
+#include "BTSec.h"
+#include "BtManServerSecurityPolicy.h"
+#include <bluetooth/logger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_BT_MANAGER_SERVER);
+#endif
+
+static const TInt KMessageArrayGranularity = 4; //< The granularity of the array used to hold TBTManMessage objects
+static const TInt KBTManClientServerProtocolSlot = 2; // the slot that points to the struct buf used between client and server
+
+inline CBTManServerShutdown::CBTManServerShutdown()
+ :CTimer(-1)
+ {
+ LOG_FUNC
+ CActiveScheduler::Add(this);
+ }
+
+inline void CBTManServerShutdown::ConstructL()
+ {
+ LOG_FUNC
+ CTimer::ConstructL();
+ }
+
+inline void CBTManServerShutdown::Start()
+ {
+ LOG_FUNC
+ After(KBTManServerShutdownDelay);
+ }
+
+//
+
+
+void CBTManServerShutdown::RunL()
+/**
+Initiate server exit when the timer expires
+**/
+ {
+ LOG_FUNC
+ CActiveScheduler::Stop();
+ }
+
+//=====================================================================
+// CBTManServer
+//=====================================================================
+
+inline CBTManServer::CBTManServer()
+ : CPolicyServer(EPriorityStandard,KBtmanServerPolicy,ESharableSessions)
+ {
+ LOG_FUNC
+ }
+
+CServer2* CBTManServer::NewLC()
+ {
+ LOG_STATIC_FUNC
+ CBTManServer* self=new(ELeave) CBTManServer;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+void CBTManServer::ConstructL()
+ {
+ LOG_FUNC
+ StartL(KBTManServerName);
+ //Ensure that the server will exit even if the 1st client fails to connect
+ iShutdown.ConstructL();
+ iShutdown.Start();
+
+ TInt err;
+ err = iProperty.Define(KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothGetRegistryTableChange,
+ RProperty::EInt,
+ KLOCAL_SERVICES,
+ KBTMAN_SID_PROT_SERV);
+
+ FLOGIFERR(err,_L("CBTManServer::ConstructL() - iProperty.Define Failure"));
+
+ err = iProperty.Define(KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothCorruptRegistryReset,
+ RProperty::EInt,
+ KLOCAL_SERVICES,
+ KLOCAL_SERVICES_AND_NETWORK_CONTROL);
+
+ FLOGIFERR(err,_L("CBTManServer::ConstructL() - iProperty.Define Failure"));
+
+ //Create the service providers...
+ iRegistry = CBTRegistry::NewL();
+
+ iContainerIndex = CObjectConIx::NewL();
+ // don't stop the server if we can't provide this service...
+ }
+
+
+CObjectCon* CBTManServer::NewContainerL()
+/**
+Return a new object container
+**/
+ {
+ LOG_FUNC
+ return iContainerIndex->CreateL();
+ }
+
+void CBTManServer::DeleteContainer(CObjectCon* aCon)
+ {
+ LOG_FUNC
+ iContainerIndex->Remove(aCon);
+ }
+
+CBTManServer::~CBTManServer()
+ {
+ LOG_FUNC
+
+ // Delete defined properties
+ TInt err;
+ err = iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetRegistryTableChange);
+ FLOGIFERR(err,_L("CBTManServer::~CBTManServer() - iProperty.Delete Failure"));
+ err = iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothCorruptRegistryReset);
+ FLOGIFERR(err,_L("CBTManServer::~CBTManServer() - iProperty.Delete Failure"));
+ // Close the RProperty handle in case it is ever attached.
+ iProperty.Close();
+
+ delete iRegistry;
+ delete iContainerIndex;
+ }
+
+CSession2* CBTManServer::NewSessionL(const TVersion &aVersion, const RMessage2& aMessage) const
+ {
+ LOG_FUNC
+ TVersion v(KBTManServerMajorVersionNumber,KBTManServerMinorVersionNumber,KBTManServerBuildVersionNumber);
+ if (!User::QueryVersionSupported(v,aVersion))
+ {
+ User::Leave(KErrNotSupported);
+ }
+ // make new session
+ return new(ELeave) CBTManSession(*iRegistry, aMessage);
+ }
+
+void CBTManServer::AddSession()
+/**
+A new session is being created
+Cancel the shutdown timer if it was running
+**/
+ {
+ LOG_FUNC
+ ++iSessionCount;
+ if (iSessionCount > iMaxSessionCount)
+ {
+ iMaxSessionCount = iSessionCount;
+ }
+ iShutdown.Cancel();
+ }
+
+void CBTManServer::DropSession()
+/**
+A session is being destroyed
+Start the shutdown timer if it is the last session.
+**/
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(iSessionCount > 0, PanicServer(EBTManBadState));
+
+ if (--iSessionCount==0)
+ {
+ iShutdown.Start();
+ }
+ }
+
+void CBTManServer::Publish(TUint aKey, TInt aValue)
+ {
+ LOG_FUNC
+ TInt err;
+ err = iProperty.Set(KPropertyUidBluetoothCategory,
+ aKey,
+ aValue);
+ FLOGIFERR(err,_L("CBTManServer::Publish() - iProperty.Set Failure"));
+ }
+
+void CBTManServer::NotifyViewChange(CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor)
+ {
+ LOG_FUNC
+ // For views owned by subsessions.
+
+ // Go through all sessions - they'll dispatch so all the subessions apart from the one calling here
+ iSessionIter.SetToFirst();
+
+ while (iSessionIter != NULL)
+ {
+ CBTManSession* s = static_cast<CBTManSession*>(iSessionIter++);
+ s->SubSessionHasOverlappingView(aSubSessionViewOwner, aViewDescriptor);
+ }
+ }
+
+void PanicClient(const RMessage2& aMessage,TInt aPanic, CBTManSession* aSession)
+/**
+RMessage2::Panic() also completes the message. This is:
+(a) important for efficient cleanup within the kernel
+(b) a problem if the message is completed a second time
+**/
+ {
+ LOG_STATIC_FUNC
+ LOG1(_L("PanicClient: Reason = %d"), aPanic);
+ //remove the message from the message table so we don't complete it again
+ //The message may not yet be in the table, so check for NULL before deleting it
+ //This code could be more efficient, but hopefully it won't be called enough to make
+ //it worthwhile improving it ;-)
+
+ __DEBUGGER();
+
+ /*** ORDER MATTERS! ***/
+ //First find the message in the session's stored messages
+ //This must be done BEFORE panicking the client because
+ //panicking the client resets the RMessage2 handle value to
+ //zero and so almost always renders the FindMessage method useless!
+ CBTManMessage* m = aSession->FindMessage(aMessage);
+
+ //Now panic the client - this is safer done before deleting
+ //the message from the message array, just in case the RMessage2
+ //object is obtained from that array and not directly from the client
+ aMessage.Panic(KBTManPanic,aPanic);
+
+ //Now delete the message from the session's queue. This is vital
+ //if we are not to attempt to complete on a dead message
+ if (m)
+ {
+ //aMessage will not be usable after the next line if it is obtained from the message array
+ //instead of the one directly supplied by the client
+ aSession->DeleteMessage(m);
+ }
+ }
+
+void PanicServer(TInt aPanic)
+/**
+Panic our own thread
+**/
+ {
+ LOG_STATIC_FUNC
+ LOG1(_L("PanicServer: Reason = %d"), aPanic);
+ User::Panic(KBTManPanic, aPanic);
+ }
+
+
+static void RunServerL()
+/**
+Perform all server initialisation, in particular creation of the
+scheduler and server and then run the scheduler
+**/
+ {
+ LOG_STATIC_FUNC
+ // create and install the active scheduler we need
+ CActiveScheduler* scheduler=new(ELeave) CActiveScheduler;
+ CleanupStack::PushL(scheduler);
+ CActiveScheduler::Install(scheduler);
+ //
+ // create the server (leave it on the cleanup stack)
+ CServer2* server = CBTManServer::NewLC();
+ //
+
+ #ifdef __BTMANSERVER_NO_PROCESSES__
+ RThread::Rendezvous(KErrNone);
+ #else
+ // naming the server thread after the server helps to debug panics
+ // ignore error - we tried the best we could
+ User::RenameThread(KBTManServerName);
+
+ RProcess::Rendezvous(KErrNone);
+ #endif
+
+ //
+ // Ready to run
+ CActiveScheduler::Start();
+ //
+ // Cleanup the server and scheduler
+ CleanupStack::PopAndDestroy(server);
+ CleanupStack::PopAndDestroy(scheduler);
+ }
+
+TInt E32Main()
+/**
+Main entry-point for the server process
+**/
+ {
+ CONNECT_LOGGER
+ LOG_STATIC_FUNC
+ LOG(_L("BTManServer RunServer"));
+
+ __UHEAP_MARK;
+#ifdef TEST_OOM //define TEST_OOM in preprocessor definitions in project settings
+ __UHEAP_SETFAIL(RHeap::ERandom, 100);
+#endif
+ CTrapCleanup* cleanup=CTrapCleanup::New();
+ TInt r=KErrNoMemory;
+ if (cleanup)
+ {
+ TRAP(r,RunServerL());
+ delete cleanup;
+ }
+ //
+ __UHEAP_MARKEND;
+ CLOSE_LOGGER
+ return r;
+ }
+
+
+//=====================================================================
+//CBTManMessage
+//=====================================================================
+
+// This framework is retained as it allows instrinsically asynchronous actions to be
+// looked after easily. At present such actions are limited to change notifications
+// pretty much everything else is handled synchronously once the Server has had
+// its ServiceL called.
+
+CBTManMessage* CBTManMessage::NewL(const RMessage2& aMessage)
+ {
+ LOG_STATIC_FUNC
+ CBTManMessage* m = new (ELeave) CBTManMessage(aMessage);
+ CleanupStack::PushL(m);
+ m->ConstructL();
+ CleanupStack::Pop(m);
+ return m;
+ }
+
+CBTManMessage::CBTManMessage(const RMessage2& aMessage)
+: iMessage(aMessage)
+ {
+ LOG_FUNC
+ }
+
+void CBTManMessage::ConstructL()
+ {
+ LOG_FUNC
+ if (iMessage.Ptr2())
+ {
+ TPckgBuf<TBTManClientServerMessage> msgBuf;
+ iMessage.ReadL(KBTManClientServerProtocolSlot, msgBuf);
+
+ iCancelPtr = msgBuf().iClientStatusToCancel;
+ }
+ }
+
+
+CBTManMessage::~CBTManMessage()
+ {
+ LOG_FUNC
+ //ensure we delete the helper if there is one
+ if (iHelper)
+ {
+ iHelper->Delete();
+ }
+ }
+
+void CBTManMessage::SetHelper(MBTManHelper* aHelper)
+/**
+Assigns a helper to the message.
+The helper will then be told to delete itself when the message is completed.
+This is especially important when cancelling or under leave conditions.
+**/
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(iHelper==NULL, PanicServer(EBTManBadHelper));
+ __ASSERT_DEBUG((aHelper->Message()).Ptr2() == iCancelPtr, PanicServer(EBTManBadHelper));
+ iHelper = aHelper;
+ }
+
+void CBTManMessage::RemoveHelper()
+/**
+Disassociates a helper with a message.
+**/
+ {
+ LOG_FUNC
+ iHelper = NULL;
+ }
+
+void CBTManMessage::Complete(TInt aReason)
+/**
+Completes the RMessage2 and deletes any associated helper.
+**/
+ {
+ LOG_FUNC
+ //complete the message
+ iMessage.Complete(aReason);
+ //delete the helper if there is one
+ if (iHelper)
+ iHelper->Delete();
+ }
+
+const RMessage2& CBTManMessage::Message()
+ {
+ LOG_FUNC
+ return iMessage;
+ }
+
+const TAny* CBTManMessage::CancelPtr()
+/**
+The CancelPtr is the address of the TRequestStatus of the client-side active object
+dealing with the request. When a request is cancelled, it is located server-side using
+this address.
+**/
+ {
+ LOG_FUNC
+ return iCancelPtr;
+ }
+
+
+MBTManHelper* CBTManMessage::Helper()
+ {
+ LOG_FUNC
+ return iHelper;
+ }
+
+TBool CBTManMessage::operator==(CBTManMessage& aMessage) const
+ {
+ LOG_FUNC
+ if (iMessage == aMessage.Message())
+ return ETrue;
+ return EFalse;
+ }
+
+//=====================================================================
+//CBTManSession
+//=====================================================================
+
+CBTManServer& CBTManSession::Server()
+ {
+ LOG_FUNC
+ return *static_cast<CBTManServer*>(const_cast<CServer2*>(CSession2::Server()));
+ }
+
+CBTManSession::CBTManSession(CBTRegistry& aRegistry, const RMessage2& aMessage)
+: iRegistry(aRegistry), iCurrentMessage(aMessage)
+ {
+ LOG_FUNC
+ }
+
+void CBTManSession::CreateL()
+/**
+2nd phase construct for sessions - called by the CServer2 framework
+**/
+ {
+ LOG_FUNC
+ //CSession2::CreateL(); // private and does nowt so removed
+ //Add session to server first. If anything leaves, it will be removed by the destructor
+ Server().AddSession();
+ ConstructL();
+ }
+
+void CBTManSession::ConstructL()
+ {
+ LOG_FUNC
+ //Create new object index
+ iSubSessions = CObjectIx::NewL();
+ iContainer = Server().NewContainerL();
+
+ iMessageArray = new(ELeave) CArrayPtrFlat<CBTManMessage>(KMessageArrayGranularity);
+ }
+
+CBTManSession::~CBTManSession()
+ {
+ LOG_FUNC
+ if (iMessageArray)
+ {
+ CompleteOutstandingMessages();
+ iMessageArray->ResetAndDestroy();
+ }
+ delete iMessageArray;
+ delete iSubSessions;
+ Server().DeleteContainer(iContainer);
+ Server().DropSession();
+ }
+
+void CBTManSession::CompleteOutstandingMessages()
+/**
+Completes any messages left in the CBTManMessage array.
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* ptr;
+ TInt count = iMessageArray->Count();
+ LOG1(_L("CBTManSession::CompleteOutstandingMessages(): %d"), count);
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ ptr = iMessageArray->At(i);
+ ptr->Complete(KErrDied);
+ iMessageArray->Delete(i);
+ delete ptr;
+ ptr = NULL;
+ }
+ }
+
+
+CBTManSubSession* CBTManSession::SubSessionFromHandle(TInt aHandle)
+/**
+Returns a subsession given a handle
+
+ @param aHandle the handle given by the client
+ @param aMessage only used if we need to panic client's having used a dodgy handle
+**/
+ {
+ LOG_FUNC
+ CBTManSubSession* p = static_cast<CBTManSubSession*>(iSubSessions->At(aHandle));
+ return p;
+ }
+
+TInt CBTManSession::HandleError(TInt aError, const RMessage2 &aMessage)
+/**
+Handle an error from ServiceL()
+A bad descriptor error implies a badly programmed client, so panic it;
+otherwise report the error to the client
+**/
+ {
+ LOG_FUNC
+ LOG1(_L("CBTManSession::HandleError(): %d"), aError);
+ if (aError==KErrBadDescriptor || aError==KErrBadHandle)
+ {
+#ifdef _DEBUG
+ __DEBUGGER(); //******** SERVER STOP ******************
+#endif
+ TInt convErr = aError==KErrBadDescriptor?EBTManBadDescriptor:EBTManBadSubSessionHandle;
+ PanicClient(aMessage, convErr, this);
+ }
+ else
+ {
+ CompleteMessage(aMessage, aError);
+ }
+ Server().ReStart();
+ return KErrNone; // handled the error fully
+ }
+
+
+void CBTManSession::ServiceL(const RMessage2 &aMessage)
+/**
+Handle a client request.
+Leaving is handled by HandleError() which reports the error code
+to the client
+**/
+ {
+ LOG_FUNC
+ //We don't need to create a message object if message is handled by session
+ //Simply dispatch and complete the message
+ TBool handled = ETrue;
+
+ TRAPD(err, handled = DispatchSessMessageL(aMessage));
+ if (handled || (err!=KErrNone))
+ {
+ if (!iClientPanic)
+ {
+ // Don't complete messages already completed by ClientPanic
+ aMessage.Complete(err);
+ }
+ else
+ {
+ //Client Panic Handled - Reset Flag.
+ iClientPanic = EFalse;
+ }
+ return;
+ }
+
+ //not handled by session so must be for subsession
+ //Create a message object to handle this
+ //We need to trap this so a leave doesn't propogate to active scheduler
+ err = KErrNone;
+ TRAP(err, CreateBTManMessageL(aMessage));
+ if (err)
+ {
+ aMessage.Complete(err);
+ return;
+ }
+
+ //Trap dispatchSubSessMessage so we can handle error here
+ err=KErrNone;
+ TRAP(err, DispatchSubSessMessageL(aMessage));
+ //if we have an error, try to handle it with handleerror. If this fails, leave
+ //and let the active scheduler sort it out.
+ if (err != KErrNone)
+ {
+ // tell subsessions to try to reduce footprint and rollback
+ for (TInt i = 0; i<iSubSessions->Count(); i++)
+ {
+ //check this element is an actual object rather than an empty memory
+ //cell on the free list
+ if((*iSubSessions)[i])
+ {
+ static_cast<CBTManSubSession*>((*iSubSessions)[i])->Cleanup(err);
+ }
+ }
+ // Tidy up of logic and construct
+ if (err != KErrNone)
+ {
+ User::LeaveIfError(HandleError(err, aMessage));
+ return;
+ }
+ }
+ }
+
+void CBTManSession::CreateBTManMessageL(const RMessage2& aMessage)
+/**
+Creates a CBTManMessage and appends it to iMessageArray.
+These are used for the BTMan server to conduct asynchronous activities itself
+
+Many activities that the BTMan Server does at present are synchronously handled; but
+for conformity all the subsessions use this framework so that any asynchronous
+tasks can be added later
+
+ @param aMessage The original client message
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* m = CBTManMessage::NewL(aMessage);
+ CleanupStack::PushL(m);
+ iMessageArray->AppendL(m);
+ CleanupStack::Pop();
+ }
+
+
+TBool CBTManSession::DispatchSessMessageL(const RMessage2 &aMessage)
+/**
+Handles the request - it may not actually be for the session
+
+@param aMessage The current message being handled.
+@return ETrue: The message was meant for the session.
+@return EFalse: The message was meant for a subsession.
+**/
+ {
+ LOG_FUNC
+ switch (aMessage.Function())
+ {
+ case EBTManCreateRegistrySubSession:
+ NewSubSessionL(ERegistry, aMessage);
+ return ETrue;
+ case EBTManCreateLocalDeviceSubSession:
+ NewSubSessionL(ELocalDevice, aMessage);
+ return ETrue;
+ case EBTManCreateCommPortSettingsSubSession:
+ NewSubSessionL(ECommPortSettings, aMessage);
+ return ETrue;
+ case EBTManCreateHostResolverSubSession:
+ NewSubSessionL(EHostResolver, aMessage);
+ return ETrue;
+ case EBTManCancelRequest:
+ CancelRequest(aMessage);
+ return ETrue;
+ case EBTManCloseSubSession:
+ CloseSubSession(aMessage);
+ return ETrue;
+ case EBTManSetHeapFailure:
+#ifdef _DEBUG
+ User::__DbgSetAllocFail(RHeap::EUser,RHeap::TAllocFail(aMessage.Int0()),aMessage.Int1());
+#endif
+ return ETrue;
+ case EBTManSubSessionCount:
+ {
+#ifdef _DEBUG
+ TPckgBuf<TInt> pckg(iSubSessions->Count());
+ aMessage.WriteL(0, pckg);
+#endif
+ return ETrue;
+ }
+ default:
+ //not handled here so must be for subsession
+ return EFalse;
+ }
+ }
+
+void CBTManSession::DispatchSubSessMessageL(const RMessage2& aMessage)
+/**
+Handles subsession requests.
+
+ @param aMessage The current message being handled.
+**/
+ {
+ LOG_FUNC
+ CBTManSubSession& ss = *SubSessionFromHandle(aMessage.Int3());
+ if (&ss == NULL)
+ {
+ User::Leave(KErrBadHandle);
+ }
+
+ // Get the status of the client request (sent on all msgs in slot2)
+ switch (aMessage.Function())
+ {
+ case EBTManRegistrySearch:
+ {
+ TBTRegistrySearchPckgBuf pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTRegistrySubSession*>(&ss)->OpenViewL(pckg(), aMessage);
+ break;
+ }
+ case EBTRegistryAddDevice:
+ {
+ // create a new device subsession and add the device - may change API to require
+ // previously opened subsession??
+ // need to internalise a contiguated buffer
+
+ TInt len = aMessage.GetDesLengthL(0);
+ HBufC8* buffer = HBufC8::NewLC(len);
+ TPtr8 ptr(buffer->Des());
+
+ aMessage.ReadL(0, ptr);
+ RDesReadStream stream;
+ stream.Open(ptr);
+ CleanupClosePushL(stream);
+
+ CBTDevice* addDetails = CBTDevice::NewLC();
+ addDetails->InternalizeL(stream);
+
+ static_cast<CBTRegistrySubSession*>(&ss)->AddDeviceL(*addDetails, aMessage);
+
+ CleanupStack::PopAndDestroy(3); //addDetails, stream, buffer
+ break;
+ }
+ case EBTRegistryModifyNamelessDevice:
+ {
+ LOG(_L("CBTManSession -> ModifyNamelessDevice"));
+ TBTNamelessDevicePckgBuf pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTRegistrySubSession*>(&ss)->ModifyL(pckg(), aMessage);
+ break;
+ }
+ case EBTRegistryGetNamelessDevice:
+ {
+ TBTNamelessDevicePckgBuf pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTRegistrySubSession*>(&ss)->GetDeviceL(pckg(), aMessage);
+ break;
+ }
+ case EBTManExtractRegistryDataIntoServer:
+ {
+ static_cast<CBTRegistrySubSession*>(&ss)->PreLoadL(aMessage);
+ break;
+ }
+
+ case EBTManRetrieveRegistryData:
+ {
+ static_cast<CBTRegistrySubSession*>(&ss)->RetrieveL(aMessage);
+ break;
+ }
+
+ case EBTRegistryDeleteLinkKey:
+ {
+ TBTDevAddrPckgBuf pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTRegistrySubSession*>(&ss)->UnpairL(pckg(), aMessage);
+ break;
+ }
+
+ case EBTRegistryDeleteDevices:
+ {
+ //nothing to read
+ static_cast<CBTRegistrySubSession*>(&ss)->DeleteViewL(aMessage);
+ break;
+ }
+
+ case EBTRegistryModifyBluetoothName:
+ case EBTRegistryModifyFriendlyName:
+ {
+ // read the address - this could move into the handler
+ TBTDevAddrPckgBuf addr;
+ aMessage.ReadL(0, addr);
+ static_cast<CBTRegistrySubSession*>(&ss)->ModifyNameL(addr(), aMessage);
+ break;
+ }
+
+ case EBTRegistryGetLocalDevice:
+ {
+ //nothing to read
+ static_cast<CBTLocalDeviceSubSession*>(&ss)->GetL(aMessage);
+ break;
+ }
+
+ case EBTRegistryUpdateLocalDevice:
+ {
+ TPckgBuf<TBTLocalDevice> pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTLocalDeviceSubSession*>(&ss)->UpdateL(pckg(), aMessage);
+ break;
+ }
+
+ case EBTRegistryGetCommPortSettings:
+ {
+ TPckgBuf<TBTCommPortSettings> pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTCommPortSettingsSubSession*>(&ss)->GetL(pckg(), aMessage);
+ break;
+ }
+
+ case EBTRegistryUpdateCommPortSettings:
+ {
+ TPckgBuf<TBTCommPortSettings> pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTCommPortSettingsSubSession*>(&ss)->UpdateL(pckg(), aMessage);
+ break;
+ }
+
+ case EBTRegistryDeleteCommPortSettings:
+ {
+ TPckgBuf<TBTCommPortSettings> pckg;
+ aMessage.ReadL(0, pckg);
+ static_cast<CBTCommPortSettingsSubSession*>(&ss)->DeleteL(pckg(), aMessage);
+ break;
+ }
+
+ case EBTRegistryUnpairView:
+ {
+ static_cast<CBTRegistrySubSession*>(&ss)->UnpairViewL(aMessage);
+ break;
+ }
+
+ case EBTRegistryCloseView:
+ {
+ static_cast<CBTRegistrySubSession*>(&ss)->CloseView(aMessage);
+ break;
+ }
+
+ case EBTRegistryNotifyViewChange:
+ {
+ ss.SetViewChangeNotificationMessage(aMessage);
+ break;
+ }
+
+ case EBTHostResolverDeviceRequest:
+ case EBTHostResolverDeviceModifyDevice:
+ default:
+ PanicClient(aMessage, EBTManBadRequest, this);
+ return;
+ }
+ }
+
+void CBTManSession::NewSubSessionL(TSubSessionType aType, const RMessage2 &aMessage)
+/**
+Create a subsession of type aType and add it to the object index.
+**/
+ {
+ LOG_FUNC
+ //Make new counter object
+ CBTManSubSession* ss = NULL;
+ switch (aType)
+ {
+ case ERegistry:
+ ss = CBTRegistrySubSession::NewL(*this, iRegistry);
+ break;
+ case ELocalDevice:
+ ss = CBTLocalDeviceSubSession::NewL(*this, iRegistry);
+ break;
+ case ECommPortSettings:
+ ss = CBTCommPortSettingsSubSession::NewL(*this, iRegistry);
+ break;
+ case EHostResolver:
+ default:
+ PanicServer(EBTManBadSubSessionType);
+ }
+
+ //add to container to generate unique id
+ //If anything goes wrong, make sure we close the subsession.
+ CleanupClosePushL(*ss);
+
+ iContainer->AddL(ss);
+
+ //add to object index - this returns a unique handle
+ // From inspection of CObjectIx::AddL(), it will can only leave BEFORE ss is added to the index.
+ // Therefore, we must close the subsession and leave if anything goes wrong,
+ // and NOT call CObjectIx::Remove().
+ TInt handle = 0;
+ handle = iSubSessions->AddL(ss);
+
+ //ss now has an owner so we can pop it off the cleanupstack
+ CleanupStack::Pop(); //ss
+
+ //Write handle to client
+ //If anything goes wrong, call CObjectIx::Remove(). This will close the subsession for us.
+ TPckg<TInt> pckg(handle);
+ TRAPD(err, aMessage.WriteL(3, pckg));
+ if (err!=KErrNone)
+ {
+ iSubSessions->Remove(handle);
+ User::Leave(err);
+ }
+ //increase resource count
+ iResourceCount++;
+ }
+
+void CBTManSession::DeleteSubsession(TInt aHandle, const RMessage2 &aMessage)
+ {
+ LOG_FUNC
+ //panic client if bad handle
+ CBTManSubSession* ss = (CBTManSubSession*)iSubSessions->At(aHandle);
+ if (ss == NULL)
+ {
+ PanicClient(aMessage, EBTManBadSubSessionRemove, this);
+ //Flag that Client has been panic'd
+ //so that the message is not completed twice
+ iClientPanic = ETrue;
+ }
+ else
+ {
+ iSubSessions->Remove(aHandle);
+ //decrement resource count
+ iResourceCount--;
+ }
+ }
+
+void CBTManSession::CloseSubSession(const RMessage2 &aMessage)
+ {
+ LOG_FUNC
+ // handle for subsession is in slot3
+ DeleteSubsession(aMessage.Int3(), aMessage);
+ }
+
+void CBTManSession::CompleteMessage(const RMessage2& aMessage, TInt aReason)
+/**
+Finds a message based on aMessage and completes it.
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* m = FindMessage(aMessage);
+ __ASSERT_DEBUG(m!=NULL, PanicServer(EBTManBadBTManMessage));
+ DoCompleteMessage(*m, aReason);
+ }
+
+void CBTManSession::CompleteMessage(MBTManHelper* aHelper, TInt aReason)
+/**
+Finds a message based on aHelper and completes it.
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* m = FindMessage(aHelper);
+ __ASSERT_DEBUG(m!=NULL, PanicServer(EBTManBadBTManMessage));
+ DoCompleteMessage(*m, aReason);
+ }
+
+void CBTManSession::DoCompleteMessage(CBTManMessage& aMessage, TInt aReason)
+/**
+ Actually does the completion
+**/
+ {
+ LOG_FUNC
+ if (aMessage.Message().Ptr2())
+ {
+ // notify clientAPI that we've serviced it - not needed if the client has
+ // not asked us to (typically for synchronous calls)
+ TBTManClientServerMessage clientMsg;
+ TPckg<TBTManClientServerMessage> clientMsgBuf(clientMsg);
+ TRAPD(err_read, aMessage.Message().ReadL(KBTManClientServerProtocolSlot, clientMsgBuf));
+ clientMsg.iClientBusy=EFalse;
+ TRAPD(err_write, aMessage.Message().WriteL(KBTManClientServerProtocolSlot, clientMsgBuf));
+
+ if(err_read != KErrNone || err_write != KErrNone)
+ {
+ PanicClient(aMessage.Message(),EBTManBadBTManMessage, this);
+ return;
+ }
+ }
+ // now tell the kernel
+ aMessage.Complete(aReason);
+ DeleteMessage(&aMessage);
+ }
+
+CBTManMessage* CBTManSession::FindMessage(const RMessage2& aMessage)
+/**
+Searches the array of CBTManMessages for the one dealing with aMessage.
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* ptr;
+ for (TInt i=0; i<iMessageArray->Count(); i++)
+ {
+ ptr = iMessageArray->At(i);
+ if(ptr->Message() == aMessage)
+ {
+ return ptr;
+ }
+ }
+ return NULL;
+ }
+
+CBTManMessage* CBTManSession::FindMessage(MBTManHelper* aHelper)
+/**
+Searches the array of CBTManMessages for the one containing a pointer to aHelper.
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* ptr;
+ for (TInt i=0; i<iMessageArray->Count(); i++)
+ {
+ ptr = iMessageArray->At(i);
+ if(ptr->Helper() == aHelper)
+ {
+ return ptr;
+ }
+ }
+ return NULL;
+ }
+
+void CBTManSession::DeleteMessage(CBTManMessage* aMessage)
+/**
+Find the CBTManMessage in the message array and delete it.
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* ptr;
+ TInt count = iMessageArray->Count();
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ ptr = iMessageArray->At(i);
+ if(ptr == aMessage)
+ {
+ //Delete the message first before removing from the array since a helper associated
+ //with the message will try to find the message by parsing the array as part of the
+ //destruction the message.
+ delete ptr;
+ iMessageArray->Delete(i);
+ ptr = NULL;
+ break;
+ }
+ }
+ //compress the array if the count is less than the length - granularity AND if the count != 0
+ if (iMessageArray->Count())
+ {
+ if (iMessageArray->Length() - iMessageArray->Count() >= KMessageArrayGranularity)
+ {
+ iMessageArray->Compress();
+ }
+ }
+ }
+
+void CBTManSession::CancelRequest(const RMessage2& aMessage)
+/**
+Cancels an asyncronous request.
+ We need to find the asynchronous message we are cancelling
+ - we can do this by comparing the TRequestStatus held
+ in Ptr2() of the message. This is ok since ALL asynchronous
+ requests to this server have the TRequestStatus passed over
+ in Ptr2() and only these may be cancelled. The TRequestStatus
+ is sent over in ptr0() of the cancel request so we don't confuse
+ the cancel message with the one we are trying to cancel.
+**/
+ {
+ LOG_FUNC
+ CBTManMessage* m;
+ TInt count = iMessageArray->Count();
+ for (TInt i=(count-1); i>=0; i--)
+ {
+ m = iMessageArray->At(i);
+ if (m->CancelPtr() == aMessage.Ptr0())
+ {
+ //Complete the message
+ m->Complete(KErrCancel);
+ //delete the message from the array
+ iMessageArray->Delete(i);
+ delete m;
+ m = NULL;
+ break;
+ }
+ }
+ //aMessage will be completed by CBTManSession::ServiceL()
+ }
+
+TBool CBTManSession::SubSessionHasOverlappingView(CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor)
+ {
+ LOG_FUNC
+ // Iterate over all subsessions apart from the view owner
+ TBool overlapFound = EFalse;
+ for (TInt i = 0; i < iContainer->Count(); i++)
+ {
+ CBTManSubSession* ss = static_cast<CBTManSubSession*>((*iContainer)[i]);
+ if (&aSubSessionViewOwner != ss)
+ {
+ if (ss->IsOverlappingView(aViewDescriptor))
+ {
+ // Overlaps - subsession will have completed the Notify message
+ // With bool return, we can test if indeed it did.
+ overlapFound = ETrue;
+ }
+ }
+ }
+
+ return overlapFound;
+ }
+
+
+//=====================================================================
+// CBTManSubSession
+//=====================================================================
+
+CBTManSubSession::CBTManSubSession(CBTManSession& aSession, CBTRegistry& aRegistry) :
+ iSession(aSession), iRegistry(aRegistry)
+ {
+ LOG_FUNC
+ }
+
+void CBTManSubSession::NotifyChange(TUint aTableChanged)
+ {
+ LOG_FUNC
+ iSession.Server().Publish(KPropertyKeyBluetoothGetRegistryTableChange,
+ aTableChanged);
+ }
+
+void CBTManSubSession::NotifyChange(TUint aTableChanged, CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor)
+ {
+ LOG_FUNC
+ NotifyChange(aTableChanged);
+ iSession.Server().NotifyViewChange(aSubSessionViewOwner, aViewDescriptor);
+ }
+
+/*virtual*/ TBool CBTManSubSession::IsOverlappingView(const TDesC& /*aViewDescriptor*/)
+ {
+ LOG_FUNC
+ // By default, not supported - so no overlapping view.
+ return EFalse;
+ }
+
+/*virtual*/ void CBTManSubSession::SetViewChangeNotificationMessage(const RMessage2& aMessage)
+ {
+ LOG_FUNC
+ // By default, not supported
+ iSession.CompleteMessage(aMessage, KErrNotSupported);
+ }
+
+#ifdef __BTMANSERVER_NO_PROCESSES__
+
+// The server binary is an "EPOCEXE" target type
+// Thus the server parameter passing and startup code for WINS and EPOC are
+// significantly different.
+//
+// In EKA1 WINS, the EPOCEXE target is a DLL with an entry point called WinsMain,
+// taking no parameters and returning TInt. This is not really valid as a thread
+// function which takes a TAny* parameter which we need.
+//
+// So the DLL entry-point WinsMain() is used to return a TInt representing the
+// real thread function within the DLL. This is good as long as
+// sizeof(TInt)>=sizeof(TThreadFunction).
+//
+
+static TInt ThreadFunction(TAny*)
+//
+// WINS thread entry-point function.
+//
+ {
+ LOG_FUNC
+ return E32Main();
+ }
+
+IMPORT_C TInt WinsMain();
+EXPORT_C TInt WinsMain()
+//
+// WINS DLL entry-point. Just return the real thread function
+// cast to TInt
+//
+ {
+ LOG_FUNC
+ return reinterpret_cast<TInt>(&ThreadFunction);
+ }
+
+TInt E32Dll(TDllReason)
+ {
+ LOG_FUNC
+ return KErrNone;
+ }
+
+#endif