--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/sts/stsproxy/src/rstssession.cpp Thu May 27 13:20:50 2010 +0300
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2010 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:
+ * The file provides the implementation of the client side session
+ * to the STS Server.
+ */
+
+#include "rstssession.h"
+#include "stsclientservercommon.h"
+
+const TUint KNumSlots = 30;
+
+/*static*/TInt RStsSession::CallBackThreadMain(TAny* aSession)
+ {
+ TInt err = KErrNoMemory;
+
+ RThread myThread;
+ myThread.SetPriority(EPriorityAbsoluteHigh);
+ myThread.Close();
+
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+
+ if (cleanup)
+ {
+ // Run the server and request a thread rendezvous.
+ TRAP( err, ((RStsSession*)aSession)->RunThreadL() );
+ delete cleanup;
+ }
+
+ return err;
+ }
+
+void RStsSession::RunThreadL()
+ {
+ iState = ERunning;
+ // Initialisation complete, now signal the client, if requested.
+ RThread::Rendezvous(KErrNone);
+ TRequestStatus queueStatus = KRequestPending;
+ iMsgQueue.NotifyDataAvailable(queueStatus);
+
+ RThread server;
+ TInt err = server.Open(iServerThreadId);
+ TRequestStatus serverStatus = KRequestPending;
+ server.Logon(serverStatus);
+
+ while (iState == ERunning)
+ {
+ TStsCallBack message;
+ // Using ReceiveBlocking here would block forever if the executive thread
+ // dies, so instead wait for either a data available notification or a
+ // notification that the executive thread has died.
+ User::WaitForRequest(queueStatus, serverStatus);
+
+ if (queueStatus != KRequestPending)
+ {
+ TInt err = iMsgQueue.Receive(message);
+ if (err == KErrNone)
+ {
+ HandleMessage(message);
+ }
+ else
+ {
+ //TODO:Log a message
+ }
+ queueStatus = KRequestPending;
+ iMsgQueue.NotifyDataAvailable(queueStatus);
+ }
+ if (serverStatus != KRequestPending && iState == ERunning)
+ {
+ //TODO: Log a message
+ //Restart the server
+ SignalObservers();
+ server.Close();
+ CreateServerSession();
+ TInt err = server.Open(iServerThreadId);
+ TRequestStatus serverStatus = KRequestPending;
+ server.Logon(serverStatus);
+ }
+ }
+
+ iMsgQueue.CancelDataAvailable();
+ server.LogonCancel(serverStatus);
+ server.Close();
+ }
+
+void RStsSession::HandleMessage(TStsCallBack& aMessage)
+ {
+ TStsCallBackType type = aMessage.callBackType;
+ if (type == EStsPlayAlarmComplete)
+ {
+ MStsPlayAlarmObserver* observer = aMessage.observer;
+ unsigned int context = aMessage.alarmContext;
+ iObserverMutex.Wait();
+ if (observer == iObserverMap[context])
+ {
+ observer->PlayAlarmComplete(aMessage.alarmContext);
+ }
+ else
+ {
+ //TODO: Log a message
+ }
+ iObserverMap.erase(context);
+ iObserverMutex.Signal();
+ }
+ else if (type == EStsShutdown)
+ {
+ iState = EStopping;
+ }
+ else
+ {
+ //TODO: Log error message
+ }
+ }
+
+TInt RStsSession::StartServer()
+ {
+ TInt err = KErrNone;
+
+ // Launch the server executable (i.e. in it its own process).
+
+ // Create a new server process. Simultaneous launching of two such processes
+ // should be detected when the second one attempts to create the server
+ // object, failing with KErrAlreadyExists.
+ RProcess server;
+ err = server.Create(KStsServerFile, KNullDesC);
+
+ if (err == KErrNone)
+ {
+ TRequestStatus rendezvousStatus;
+ server.Rendezvous(rendezvousStatus);
+ server.Resume();
+
+ // wait for start or death
+ User::WaitForRequest(rendezvousStatus);
+
+ // we can't use the 'exit reason' if the server panicked as this
+ // is the panic 'reason' and may be '0' which cannot be distinguished
+ // from KErrNone
+ if (server.ExitType() == EExitPanic)
+ {
+ err = KErrGeneral;
+ }
+ else
+ {
+ err = rendezvousStatus.Int();
+ }
+ }
+ server.Close();
+
+ return err;
+ }
+
+TInt RStsSession::StartThread()
+ {
+ TInt result = iThread.Create(KNullDesC, RStsSession::CallBackThreadMain,
+ KDefaultStackSize, &User::Heap(), (TAny*) this);
+
+ if (result == KErrNone)
+ {
+ TRequestStatus rendezvousStatus = KRequestPending;
+
+ // Register for rendezvous notification when thread is started.
+ iThread.Rendezvous(rendezvousStatus);
+
+ // Start the thread execution
+ iThread.Resume();
+
+ // Wait for thread to start.
+ User::WaitForRequest(rendezvousStatus);
+
+ result = rendezvousStatus.Int();
+
+ if (result != KErrNone)
+ {
+ iThread.Kill(result);
+ }
+ }
+
+ return result;
+ }
+
+TInt RStsSession::CreateServerSession()
+ {
+ // Try to create a session with the server
+ TInt result = CreateSession(KStsServerName, TVersion(
+ KStsServerMajorVersion, KStsServerMinorVersion, KStsServerBuild),
+ KNumSlots, EIpcSession_Sharable);
+
+ // If the server wasn't found, start the server and try creating a session again
+ if (result == KErrNotFound || result == KErrServerTerminated)
+ {
+ result = StartServer();
+ if (result == KErrNone || result == KErrAlreadyExists)
+ {
+ result = CreateSession(KStsServerName, TVersion(
+ KStsServerMajorVersion, KStsServerMinorVersion,
+ KStsServerBuild), KNumSlots, EIpcSession_Sharable);
+ }
+ }
+
+ if (result == KErrNone)
+ {
+ TPckg<TThreadId> idPckg(iServerThreadId);
+ result = SendReceive(StsMsg_RegisterMsgQueue, TIpcArgs(iMsgQueue,
+ &idPckg));
+ }
+
+ return result;
+ }
+
+TInt RStsSession::Connect()
+ {
+ iState = EInitializing;
+
+ // Create a nameless global message queue, then pass the handle to the queue to the server.
+ TInt result = iMsgQueue.CreateGlobal(KNullDesC, 30);
+
+ // Create thread for receiving asynch callbacks from the server
+ if (result == KErrNone)
+ {
+ result = CreateServerSession();
+ if (result == KErrNone)
+ {
+ result = StartThread();
+ if (result == KErrNone)
+ {
+ result = iObserverMutex.CreateLocal();
+ }
+ }
+ }
+
+ return result;
+ }
+
+void RStsSession::Close()
+ {
+ TRequestStatus logonStatus = KRequestPending;
+ iThread.Logon(logonStatus);
+ RSessionBase::Close();
+ User::WaitForRequest(logonStatus);
+ iThread.Close();
+ iMsgQueue.Close();
+ CleanUpObservers();
+ iObserverMutex.Close();
+ }
+
+void RStsSession::SendPlayTone(CSystemToneService::TToneType aTone)
+ {
+ TInt err = SendReceive(StsMsg_PlayTone, TIpcArgs(aTone));
+ if (err != KErrNone)
+ {
+ //TODO: Log a message
+ }
+ }
+
+void RStsSession::SendPlayAlarm(CSystemToneService::TAlarmType aAlarm,
+ unsigned int& aAlarmContext, MStsPlayAlarmObserver& aObserver)
+ {
+ TPckg<unsigned int> alarmContextPckg(aAlarmContext);
+ TInt err = SendReceive(StsMsg_PlayAlarm, TIpcArgs(aAlarm,
+ &alarmContextPckg, &aObserver));
+ if (err != KErrNone)
+ {
+ //TODO: Log a message
+ aObserver.PlayAlarmComplete(aAlarmContext);
+ }
+ else
+ {
+ iObserverMutex.Wait();
+ iObserverMap[aAlarmContext] = &aObserver;
+ iObserverMutex.Signal();
+ }
+ }
+
+void RStsSession::SendStopAlarm(unsigned int aAlarmContext)
+ {
+ iObserverMutex.Wait();
+ iObserverMap.erase(aAlarmContext);
+ iObserverMutex.Signal();
+ TInt err = SendReceive(StsMsg_StopAlarm, TIpcArgs(aAlarmContext));
+ if (err != KErrNone)
+ {
+ //TODO: Log a message
+ }
+ }
+
+void RStsSession::CleanUpObservers()
+ {
+ iObserverMutex.Wait();
+ while (!iObserverMap.empty())
+ {
+ //TODO: Add trace here
+ unsigned int context = iObserverMap.begin()->first;
+ iObserverMap.erase(context);
+ }
+ iObserverMutex.Signal();
+ }
+
+void RStsSession::SignalObservers()
+ {
+ iObserverMutex.Wait();
+ while (!iObserverMap.empty())
+ {
+ //TODO: Add trace here
+ unsigned int context = iObserverMap.begin()->first;
+ iObserverMap[context]->PlayAlarmComplete(context);
+ iObserverMap.erase(context);
+ }
+ iObserverMutex.Signal();
+ }