diff -r 000000000000 -r 4e1aa6a622a0 accessoryservices/remotecontrolfw/client/inner/src/session.cpp --- /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 +#include +#include "remconserver.h" +#include +#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(&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& 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 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 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 + } +