--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/accessoryservices/remotecontrolfw/client/inner/src/session.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,503 @@
+// Copyright (c) 2004-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include <e32base.h>
+#include "remconserver.h"
+#include <remconaddress.h>
+#include "remconclient.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCON_INNER);
+#endif
+
+/**
+Starts the server process.
+*/
+static TInt StartServer()
+ {
+ LOG_STATIC_FUNC
+ const TUidType serverUid(KNullUid, KNullUid, KRemConSrvUid);
+
+ //
+ // EPOC and EKA2 is easy, we just 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;
+ TInt err = server.Create(KRemConServerImg, KNullDesC, serverUid);
+
+ if ( err != KErrNone )
+ {
+ return err;
+ }
+
+ TRequestStatus stat;
+ server.Rendezvous(stat);
+
+ if ( stat != KRequestPending )
+ {
+ server.Kill(0); // abort startup
+ }
+ else
+ {
+ server.Resume(); // logon OK - start the server
+ }
+
+ User::WaitForRequest(stat); // wait for start or death
+
+ // 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
+ err = (server.ExitType() == EExitPanic) ? KErrServerTerminated : stat.Int();
+
+ server.Close();
+
+ return err;
+ }
+
+RRemCon::RRemCon(TRemConClientType aClientType)
+: iClientType(aClientType),
+ iNumRemotesPckg(0),
+ iReceivePckg(TRemConClientReceivePackage())
+ {
+ LOG_FUNC
+ }
+
+EXPORT_C TVersion RRemCon::Version() const
+ {
+ LOG_FUNC
+ return(TVersion( KRemConSrvMajorVersionNumber,
+ KRemConSrvMinorVersionNumber,
+ KRemConSrvBuildNumber
+ )
+ );
+ }
+
+EXPORT_C TInt RRemCon::Connect()
+ {
+ LOG_FUNC
+
+ TInt err = DoConnect();
+ if ( err == KErrNone )
+ {
+ err = SetClientType();
+ if ( err != KErrNone )
+ {
+ // For this API to be clean, we must clean up the session handle
+ // already successfully created.
+ Close();
+ }
+ }
+ return err;
+ }
+
+EXPORT_C TInt RRemCon::Connect(const TPlayerType& aClientType, const TPlayerSubType& aClientSubType, const TDesC8& aName)
+ {
+ LOG_FUNC
+
+ TInt err = DoConnect();
+ if ( err == KErrNone )
+ {
+ err = SetClientType(aClientType,aClientSubType,aName);
+ if ( err != KErrNone )
+ {
+ // For this API to be clean, we must clean up the session handle
+ // already successfully created.
+ Close();
+ }
+ }
+ return err;
+ }
+/**
+Connects the session, starting the server if necessary. This involves two IPC
+calls, the first to connect the session to the server, the second to set the
+server-side session's type correctly (controller or target).
+@return Error.
+*/
+TInt RRemCon::DoConnect()
+ {
+ LOG_FUNC
+ TInt retry = 2;
+
+ FOREVER
+ {
+ // 4 is the number of asynchronous APIs which may be outstanding
+ // simultaneously.
+ TInt err = CreateSession(KRemConServerName, Version(), 4);
+
+ if ((err != KErrNotFound) && (err != KErrServerTerminated))
+ {
+ return err;
+ }
+
+ if (--retry == 0)
+ {
+ return err;
+ }
+
+ err = StartServer();
+
+ if ((err != KErrNone) && (err != KErrAlreadyExists))
+ {
+ return err;
+ }
+ }
+ }
+
+/**
+Does IPC with the server to set the type of the session from our member (set
+at construction time).
+@return Error.
+*/
+TInt RRemCon::SetClientType()
+ {
+ LOG_FUNC
+ return SendReceive(ERemConSetClientType, TIpcArgs(iClientType));
+ }
+
+TInt RRemCon::SetClientType(const TPlayerType& aClientType, const TPlayerSubType& aClientSubType, const TDesC8& aName)
+ {
+ LOG_FUNC
+ TIpcArgs args;
+ args.Set(0,iClientType);
+ iPlayerTypePckg().iPlayerType = aClientType;
+ iPlayerTypePckg().iPlayerSubType = aClientSubType;
+ args.Set(1,&iPlayerTypePckg);
+ args.Set(2,aName.Length());
+ args.Set(3, &aName);
+ return SendReceive(ERemConSetClientType, args);
+ }
+
+EXPORT_C TInt RRemCon::SendUnreliable(TUid aInterfaceUid,
+ TUint aOperationId,
+ TRemConMessageSubType aSubType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+ TIpcArgs args;
+ iOpInfoPckg().iOperationId = aOperationId;
+ iOpInfoPckg().iMessageSubType = aSubType;
+
+ args.Set(0, aInterfaceUid.iUid);
+ args.Set(1, &iOpInfoPckg);
+ args.Set(2, &aData);
+ TInt err = SendReceive(ERemConSendUnreliable, args);
+ return err;
+ }
+
+
+EXPORT_C void RRemCon::Send(TRequestStatus& aStatus,
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ TUint& aNumRemotes,
+ TRemConMessageSubType aSubType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ TIpcArgs args;
+ iOpInfoPckg().iOperationId = aOperationId;
+ iOpInfoPckg().iMessageSubType = aSubType;
+ args.Set(0, aInterfaceUid.iUid);
+ args.Set(1, &iOpInfoPckg);
+ iNumRemotesPckg.Set((TUint8*)&aNumRemotes, sizeof(TUint), sizeof(TUint));
+ args.Set(2, &iNumRemotesPckg);
+ args.Set(3, &aData);
+
+ SendReceive(ERemConSend,
+ args,
+ aStatus
+ );
+ }
+
+/**
+Sends a notify command to the remote device.
+
+@see RRemCon::Send()
+*/
+EXPORT_C void RRemCon::SendNotify(TRequestStatus& aStatus,
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ TRemConMessageSubType aSubType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ TIpcArgs args;
+ iOpInfoPckg().iOperationId = aOperationId;
+ iOpInfoPckg().iMessageSubType = aSubType;
+ args.Set(0, aInterfaceUid.iUid);
+ args.Set(1, &iOpInfoPckg);
+ args.Set(2, &aData);
+
+ SendReceive(ERemConSendNotify,
+ args,
+ aStatus
+ );
+ }
+
+EXPORT_C TInt RRemCon::SendCancel()
+ {
+ LOG_FUNC
+
+ //Ignore Return code because
+ // a) It'll mostly be other than KErrNone because the server has terminated, in which
+ // case the original async request will have completed with the error anyway!
+ // b) It's meaningless to the client whatever the return code is.
+ (void)SendReceive(ERemConSendCancel);
+
+ return KErrNone;
+ }
+
+EXPORT_C void RRemCon::Receive(TRequestStatus& aStatus,
+ TRemConClientReceivePackage& aReceivePackage,
+ TDes8& aData)
+ {
+ LOG_FUNC
+
+ TIpcArgs args;
+ iReceivePckg.Set(reinterpret_cast<TUint8*>(&aReceivePackage), sizeof(TRemConClientReceivePackage), sizeof(TRemConClientReceivePackage));
+ args.Set(0, &iReceivePckg);
+ args.Set(1, &aData);
+
+ SendReceive(ERemConReceive,
+ args,
+ aStatus);
+ }
+
+EXPORT_C TInt RRemCon::ReceiveCancel()
+ {
+ LOG_FUNC
+
+ // See RRemCon::SendCancel() for comment
+ (void)SendReceive(ERemConReceiveCancel);
+
+ return KErrNone;
+ }
+
+EXPORT_C TInt RRemCon::GetConnections(TSglQue<TRemConAddress>& aConnections)
+ {
+ LOG_FUNC
+
+ // Plan:
+ // 1/ Empty the given queue (in case of any subsequent error).
+ // 2/ First IPC call: get the current number of connections from the
+ // server and allocate a buffer to read their statuses into.
+ // 3/ Second IPC call: read the connections into that buffer, and translate
+ // them into the client's queue.
+ // What if the set of connections changes between these 2 IPC calls? The
+ // server-side session needs to remember the set of connection statuses at
+ // the point in time of the 1st IPC call, to correctly answer the 2nd IPC
+ // call. This means the server-side session has to queue connection state
+ // changes that occur in the meantime, which can fail due to memory
+ // allocation. This is OK because (a) they can fail a new connection
+ // indication back to the bearer, and (b) they can make sure they can
+ // handle a disconnection indication by pre-allocating (at connection
+ // establishment time) enough memory to be able to remember its future
+ // disconnection.
+
+ // 1/
+ aConnections.Reset();
+
+ // 2/
+ TUint connCount = 0;
+ TPckg<TUint> countBuf(connCount);
+ TInt err = SendReceive(ERemConGetConnectionCount, TIpcArgs(&countBuf));
+ // Only bother to get the statuses if there are some to get- otherwise
+ // just give the client back their empty queue and KErrNone.
+ if ( err == KErrNone && connCount != 0 )
+ {
+ RBuf8 buf;
+ err = buf.Create(connCount * sizeof(TRemConAddress));
+ if ( err == KErrNone )
+ {
+ // 3/
+ err = SendReceive(ERemConGetConnections, TIpcArgs(&buf));
+ if ( err == KErrNone )
+ {
+ // Read the statuses into the client's array.
+ for ( TUint ii = 0 ; ii < connCount ; ii++ )
+ {
+ // Divide the data in to TRemConAddress portions
+ TRemConAddress* tempAddr = new TRemConAddress();
+ if (tempAddr)
+ {
+ Mem::Copy((TAny*)(tempAddr),(TAny*)(buf.Ptr()+(ii*sizeof(TRemConAddress))) , sizeof(TRemConAddress));
+ aConnections.AddLast(*tempAddr);
+ }
+ else
+ {
+ // Perform the cleanup in case of error
+ TSglQueIter<TRemConAddress> iter(aConnections);
+ iter.SetToFirst();
+ TRemConAddress* addr;
+ while (( addr = iter++ ) != NULL )
+ {
+ aConnections.Remove(*addr);
+ delete addr;
+ };
+
+ err = KErrNoMemory;
+ break;
+ }
+ }
+ }
+ // The data that was in buf is passed into small appBuf's
+ // and it is now owned by the client (via their TSglQue).
+ }
+ // Cleanup the allocated buffer for statuses info
+ buf.Close();
+ }
+ return err;
+ }
+
+EXPORT_C void RRemCon::NotifyConnectionsChange(TRequestStatus& aStatus)
+ {
+ LOG_FUNC
+
+ SendReceive(ERemConNotifyConnectionsChange,
+ aStatus);
+ }
+
+EXPORT_C TInt RRemCon::NotifyConnectionsChangeCancel()
+ {
+ LOG_FUNC
+
+ // See RRemCon::SendCancel() for comment
+ (void)SendReceive(ERemConNotifyConnectionsChangeCancel);
+
+ return KErrNone;
+ }
+
+EXPORT_C TInt RRemCon::RegisterInterestedAPIs(const TDesC8& aAPIs)
+ {
+ LOG_FUNC
+ return SendReceive(ERemConRegisterInterestedAPIs, TIpcArgs(&aAPIs));
+ }
+
+EXPORT_C TInt RRemCon::__DbgMarkHeap()
+ {
+ LOG_FUNC
+#ifdef _DEBUG
+ return SendReceive(ERemConDbgMarkHeap);
+#else
+ return KErrNone;
+#endif
+ }
+
+EXPORT_C TInt RRemCon::__DbgCheckHeap(TInt aCount)
+ {
+ LOG_FUNC
+#ifdef _DEBUG
+ return SendReceive(ERemConDbgCheckHeap, TIpcArgs(aCount));
+#else
+ (void)aCount;
+ return KErrNone;
+#endif
+ }
+
+EXPORT_C TInt RRemCon::__DbgMarkEnd(TInt aCount)
+ {
+ LOG_FUNC
+#ifdef _DEBUG
+ return SendReceive(ERemConDbgMarkEnd, TIpcArgs(aCount));
+#else
+ (void)aCount;
+ return KErrNone;
+#endif
+ }
+
+EXPORT_C TInt RRemCon::__DbgFailNext(TInt aCount)
+ {
+ LOG_FUNC
+#ifdef _DEBUG
+ return SendReceive(ERemConDbgFailNext, TIpcArgs(aCount));
+#else
+ (void)aCount;
+ return KErrNone;
+#endif
+ }
+
+EXPORT_C RRemConController::RRemConController()
+: RRemCon(ERemConClientTypeController)
+ {
+ LOG_FUNC
+ }
+
+EXPORT_C TInt RRemConController::GoConnectionOriented(const TRemConAddress& aConnection)
+ {
+ LOG_FUNC
+
+ return SendReceive(ERemConGoConnectionOriented,
+ TIpcArgs(aConnection.BearerUid().iUid,
+ &aConnection.Addr())
+ );
+ }
+
+EXPORT_C TInt RRemConController::GoConnectionless()
+ {
+ LOG_FUNC
+
+ return SendReceive(ERemConGoConnectionless);
+ }
+
+EXPORT_C void RRemConController::ConnectBearer(TRequestStatus& aStatus)
+ {
+ LOG_FUNC
+
+ SendReceive(ERemConConnectBearer,
+ aStatus);
+ }
+
+EXPORT_C TInt RRemConController::ConnectBearerCancel()
+ {
+ LOG_FUNC
+
+ // See RRemCon::SendCancel() for comment
+ (void)SendReceive(ERemConConnectBearerCancel);
+
+ return KErrNone;
+ }
+
+EXPORT_C void RRemConController::DisconnectBearer(TRequestStatus& aStatus)
+ {
+ LOG_FUNC
+
+ SendReceive(ERemConDisconnectBearer,
+ aStatus);
+ }
+
+EXPORT_C TInt RRemConController::DisconnectBearerCancel()
+ {
+ LOG_FUNC
+
+ // See RRemCon::SendCancel() for comment
+ (void)SendReceive(ERemConDisconnectBearerCancel);
+
+ return KErrNone;
+ }
+
+EXPORT_C RRemConTarget::RRemConTarget()
+: RRemCon(ERemConClientTypeTarget)
+ {
+ LOG_FUNC
+ }
+