--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/accessoryservices/remotecontrolfw/server/src/bulksession.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,359 @@
+// Copyright (c) 2008-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:
+// Remote Control bulk session implementation.
+//
+
+
+
+/**
+ @file
+ @internalComponent
+*/
+#include "bulksession.h"
+#include "remconserver.h"
+
+#include "bulkserver.h"
+#include "remconmessage.h"
+#include "utils.h"
+
+#include "messagequeue.h"
+
+#include <bluetooth/logger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCON_SERVER);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("bulksess");
+#endif
+
+CRemConBulkSession* CRemConBulkSession::NewL(CRemConBulkServer& aServer,
+ const RMessage2& aMessage)
+ {
+ LOG_STATIC_FUNC;
+ CRemConBulkSession* self = new(ELeave) CRemConBulkSession(aServer);
+ CleanupStack::PushL(self);
+ self->ConstructL(aMessage);
+ CLEANUPSTACK_POP1(self);
+ return self;
+ }
+
+CRemConBulkSession::CRemConBulkSession(CRemConBulkServer& aServer)
+ : iServer(aServer),
+ iId(KNullClientId)
+ {
+ LOG_FUNC;
+ }
+
+void CRemConBulkSession::ConstructL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Get the client's process ID.
+ RThread thread;
+ LEAVEIFERRORL(aMessage.Client(thread));
+ CleanupClosePushL(thread);
+ RProcess process;
+ LEAVEIFERRORL(thread.Process(process));
+ iClientInfo.ProcessId() = process.Id();
+ process.Close();
+ iClientInfo.SecureId() = thread.SecureId();
+ CleanupStack::PopAndDestroy(&thread);
+
+ // Tell the server about us.
+ LEAVEIFERRORL(iServer.ClientOpened(*this, iClientInfo.ProcessId()));
+ }
+
+CRemConBulkSession::~CRemConBulkSession()
+ {
+ LOG_FUNC;
+
+ iInterestedAPIs.Close();
+
+ // Tell the server we've gone away- it may start its shutdown timer.
+ iServer.ClientClosed(*this);
+ }
+
+void CRemConBulkSession::ServiceL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+ LOG1(_L8("\taMessage.Function() = %d"), aMessage.Function());
+
+ // Switch on the IPC number and call a 'message handler'. Message handlers
+ // complete aMessage (either with Complete or Panic), or make a note of
+ // the message for later asynchronous completion.
+ // Message handlers should not leave- the server does not have an Error
+ // function.
+
+ switch ( aMessage.Function() )
+ {
+ // Heap failure testing APIs.
+ case ERemConBulkDbgMarkHeap:
+#ifdef _DEBUG
+ LOG(_L8("\tmark heap"));
+ __UHEAP_MARK;
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConBulkDbgCheckHeap:
+#ifdef _DEBUG
+ LOG1(_L8("\tcheck heap (expecting %d cells)"), aMessage.Int0());
+ __UHEAP_CHECK(aMessage.Int0());
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConBulkDbgMarkEnd:
+#ifdef _DEBUG
+ LOG1(_L8("\tmark end (expecting %d cells)"), aMessage.Int0());
+ __UHEAP_MARKENDC(aMessage.Int0());
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConBulkDbgFailNext:
+#ifdef _DEBUG
+ {
+ LOG1(_L8("\tfail next (simulating failure after %d allocation(s))"), aMessage.Int0());
+ if ( aMessage.Int0() == 0 )
+ {
+ __UHEAP_RESET;
+ }
+ else
+ {
+ __UHEAP_FAILNEXT(aMessage.Int0());
+ }
+ }
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConBulkSend:
+ Send(aMessage);
+ break;
+
+ case ERemConBulkSendUnreliable:
+ SendUnreliable(aMessage);
+ break;
+
+ case ERemConBulkSendCancel:
+ SendCancel(aMessage);
+ ASSERT_DEBUG(aMessage.Handle() == 0);
+ break;
+
+ case ERemConBulkReceive:
+ Receive(aMessage);
+ break;
+
+ case ERemConBulkReceiveCancel:
+ ReceiveCancel(aMessage);
+ ASSERT_DEBUG(aMessage.Handle() == 0);
+ break;
+
+ default:
+ // Unknown message
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc);
+ break;
+ }
+ }
+
+void CRemConBulkSession::CompleteClient(const RMessage2& aMessage, TInt aError)
+ {
+ LOG1(_L("\tcompleting client message with %d"), aError);
+ TBool cleanClientInfoMessage = (iClientInfo.Message().Handle() == aMessage.Handle());
+ aMessage.Complete(aError);
+ if(cleanClientInfoMessage)
+ {
+ iClientInfo.Message() = RMessage2();
+ }
+ }
+
+TInt CRemConBulkSession::WriteMessageToClient(const CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(iReceiveMsg.Handle());
+
+ TInt err = KErrNone;
+ TPckg<TUint> uid(aMsg.InterfaceUid().iUid);
+
+ //check if our client is interested in this API
+ //Only need to check commands because it is safe to assume that we are interested
+ //in the response if we have sent out a command.
+
+ if(aMsg.MsgType() == ERemConCommand && iInterestedAPIs.Find(aMsg.InterfaceUid())==KErrNotFound)
+ {
+ //The server will clean up the resource allocated for this msg
+ err = KErrArgument;
+ }
+ else
+ {
+ err = iReceiveMsg.Write(0, uid);
+ }
+
+ if ( err == KErrNone )
+ {
+ TPckg<TUint> opId(aMsg.OperationId());
+ err = iReceiveMsg.Write(1, opId);
+ if ( err == KErrNone )
+ {
+ // This logging code left in for maintenance.
+ //LOG1(_L8("\t\tOperationData = \"%S\""), &aMsg.OperationData());
+ // Note that we do not panic the client if their descriptor is not
+ // big enough to hold the operation-specific data. If we did, then
+ // a buggy remote could take down a client of RemCon. Just error
+ // the client instead.
+ err = iReceiveMsg.Write(2, aMsg.OperationData());
+ }
+ }
+
+ CompleteClient(iReceiveMsg, err);
+ LOG1(_L8("\terr = %d"), err);
+
+ return err;
+ }
+
+void CRemConBulkSession::Receive(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ if ( iReceiveMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicReceiveAlreadyOutstanding);
+ return;
+ }
+
+ iReceiveMsg = aMessage;
+ // If there's anything waiting to be given to us, ReceiveRequest will call
+ // back to us with it.
+ iServer.ReceiveRequest(*this);
+ }
+
+void CRemConBulkSession::ReceiveCancel(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ if ( iReceiveMsg.Handle() )
+ {
+ CompleteClient(iReceiveMsg, KErrCancel);
+ }
+ CompleteClient(aMessage, KErrNone);
+ // At no point do we make any change to the processes going on underneath
+ // us- 'Cancel' APIs are just for cancelling interest in an async
+ // operation.
+ }
+
+void CRemConBulkSession::Send(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+ TRAPD(err, DoSendL(aMessage));
+ CompleteClient(aMessage, err);
+ }
+
+void CRemConBulkSession::DoSendL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ CRemConMessage* msg = DoCreateMessageL(aMessage, ETrue);
+ LEAVEIFERRORL(SendToServer(*msg));
+ }
+
+void CRemConBulkSession::SendUnreliable(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ CRemConMessage* msg = NULL;
+ TRAPD(err, msg = DoCreateMessageL(aMessage, EFalse));
+ CompleteClient(aMessage, err);
+ if (err == KErrNone)
+ {
+ static_cast<void>(SendToServer(*msg)); // unreliable so ignore error.
+ }
+ }
+
+CRemConMessage* CRemConBulkSession::DoCreateMessageL(const RMessage2& aMessage, TBool aReliable)
+ {
+ LOG_FUNC;
+
+ // Get the data the client wants to send.
+ const TUid interfaceUid = TUid::Uid(aMessage.Int0());
+ LOG1(_L8("\tinterfaceUid = 0x%08x"), interfaceUid);
+
+ const TUint operationId = aMessage.Int1();
+ LOG1(_L8("\toperationId = 0x%08x"), operationId);
+
+ const TUint dataLength = (TUint)aMessage.GetDesLengthL(2);
+ LOG1(_L8("\tdataLength = %d"), dataLength);
+
+ // If the client wanted to send some operation-associated data, read it
+ // from them.
+ RBuf8 sendDes;
+ if ( dataLength != 0 )
+ {
+ sendDes.CreateL(dataLength);
+ TInt err = aMessage.Read(
+ 2, // location of the descriptor in the client's message (as we expect them to have set it up)
+ sendDes, // descriptor to write to from client memory space
+ 0 // offset into our descriptor to put the client's data
+ );
+ // NB We don't do LEAVEIFERRORL(aMessage.Read) because a bad client
+ // descriptor is a panicking offence for them, not an 'error the
+ // request' offence.
+ if ( err != KErrNone )
+ {
+ LOG1(_L8("\taMessage.Read = %d"), err);
+ sendDes.Close();
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ LEAVEL(KErrBadDescriptor);
+ }
+ }
+ CleanupClosePushL(sendDes);
+
+ CRemConMessage* msg = CRemConMessage::NewL(
+ TRemConAddress(), // we don't know which remotes it's going to yet
+ ERemConResponse, // targets can only send responses
+ ERemConMessageDefault,
+ interfaceUid,
+ operationId,
+ sendDes, // msg takes ownership
+ Id(), // session id to match this response against the originating command
+ 0, // transaction id not yet known
+ aReliable);
+ CLEANUPSTACK_POP1(&sendDes); // now owned by msg
+
+ iClientInfo.Message() = aMessage;
+
+ return msg;
+ }
+
+TInt CRemConBulkSession::SendToServer(CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+ return iServer.SendResponse(aMsg, *this);
+ }
+
+void CRemConBulkSession::SendCancel(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // This is left as an actual function on the server for interface
+ // reasons. In fact the sending is (unlike in the control server)
+ // processed synchronously - so currently there is never be anything
+ // to cancel when this arrives.
+
+ CompleteClient(aMessage, KErrNone);
+ }
+