aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/EmRPC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/EmRPC.cpp')
-rw-r--r--SrcShared/EmRPC.cpp451
1 files changed, 451 insertions, 0 deletions
diff --git a/SrcShared/EmRPC.cpp b/SrcShared/EmRPC.cpp
new file mode 100644
index 0000000..3fb1b6e
--- /dev/null
+++ b/SrcShared/EmRPC.cpp
@@ -0,0 +1,451 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 1999-2001 Palm, Inc. or its subsidiaries.
+ All rights reserved.
+
+ This file is part of the Palm OS Emulator.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+\* ===================================================================== */
+
+#include "EmCommon.h"
+#include "EmRPC.h"
+
+#include "EmPalmStructs.h" // SysPktRPCParamType, SysPktRPCType, SysPktRPC2Type
+#include "EmSession.h" // SuspendByExternal
+#include "HostControl.h" // hostErrTimeout
+#include "Logging.h" // LogAppendMsg
+#include "Miscellaneous.h" // CountBits
+#include "Platform.h" // Platform::GetMilliseconds
+#include "PreferenceMgr.h" // Preference
+#include "EmMemory.h" // CEnableFullAccess
+#include "SLP.h" // SLP::EventCallback
+#include "SocketMessaging.h" // CTCPSocket
+#include "SystemPacket.h" // SystemPacket::
+
+
+struct SLPTimeout
+{
+ // Default constructor for the creation of STL collections.
+ // CodeWarrior needed this; VC++ didn't.
+ SLPTimeout () :
+ fSLP (),
+ fStart (0),
+ fTimeout (0)
+ {
+ }
+
+ SLPTimeout (SLP& slp, long timeout) :
+ fSLP (slp),
+ fStart (Platform::GetMilliseconds ()),
+ fTimeout (timeout)
+ {
+ }
+
+ SLP fSLP;
+ uint32 fStart;
+ uint32 fTimeout;
+};
+
+typedef vector<SLPTimeout> SLPTimeoutList;
+
+static SLPTimeoutList gSLPTimeouts;
+static SLP* gCurrentPacket;
+static omni_mutex gMutex;
+
+#define PRINTF if (true) ; else LogAppendMsg
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::Startup
+ *
+ * DESCRIPTION: Create all the sockets we'll need for the application
+ * and start them listening for clients. Call this once
+ * at application startup.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void RPC::Startup (void)
+{
+ RPC::CreateNewListener ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::Shutdown
+ *
+ * DESCRIPTION: Call this once at application shutdown.
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void RPC::Shutdown (void)
+{
+}
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::Idle
+ *
+ * DESCRIPTION: DESCRIPTION
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void RPC::Idle (void)
+{
+ omni_mutex_lock lock (gMutex);
+
+ uint32 now = Platform::GetMilliseconds ();
+
+ SLPTimeoutList::iterator iter = gSLPTimeouts.begin ();
+
+ while (iter != gSLPTimeouts.end ())
+ {
+ SLP& slp = iter->fSLP;
+ uint32 start = iter->fStart;
+ uint32 timeout = iter->fTimeout;
+
+ if (now - start > timeout)
+ {
+ PRINTF ("RPC::Idle: Timing out.");
+
+ EmAssert (slp.HavePacket ());
+
+ slp.DeferReply (false);
+
+ EmProxySysPktBodyType& response = slp.Body ();
+ if (response.command == sysPktRPCCmd)
+ {
+ EmAliasSysPktRPCType<LAS> response (slp.Body().GetPtr());
+
+ response.command = sysPktRPCRsp;
+ response._filler = 0;
+
+ response.resultD0 = (UInt32) hostErrTimeout;
+ response.resultA0 = 0;
+ }
+ else
+ {
+ EmAliasSysPktRPC2Type<LAS> response (slp.Body().GetPtr());
+
+ response.command = sysPktRPC2Rsp;
+ response._filler = 0;
+
+ response.resultD0 = (UInt32) hostErrTimeout;
+ response.resultA0 = 0;
+ response.resultException = 0;
+ }
+
+ long bodySize = slp.GetPacketSize () - (slp.Header().GetSize() + slp.Footer().GetSize());
+
+ slp.SendPacket (response.GetPtr (), bodySize);
+
+ iter = gSLPTimeouts.erase (iter);
+ continue;
+ }
+
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::SignalWaiters
+ *
+ * DESCRIPTION: DESCRIPTION
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void RPC::SignalWaiters (HostSignalType signal)
+{
+ omni_mutex_lock lock (gMutex);
+
+ PRINTF ("RPC::SignalWaiters: Entering");
+
+ Bool signalledOne = false;
+ SLPTimeoutList::iterator iter = gSLPTimeouts.begin ();
+
+ while (iter != gSLPTimeouts.end ())
+ {
+ PRINTF ("RPC::SignalWaiters: Signaling");
+
+ SLP& slp = iter->fSLP;
+
+ EmAssert (slp.HavePacket ());
+
+ slp.DeferReply (false);
+
+ EmProxySysPktBodyType& response = slp.Body ();
+ if (response.command == sysPktRPCCmd)
+ {
+ EmAliasSysPktRPCType<LAS> response (slp.Body().GetPtr());
+
+ response.command = sysPktRPCRsp;
+ response._filler = 0;
+
+ response.resultD0 = errNone;
+ response.resultA0 = 0;
+
+ EmAliasSysPktRPCParamType<LAS> param (response.param.GetPtr ());
+
+ param.asLong = signal;
+ }
+ else
+ {
+ EmAliasSysPktRPC2Type<LAS> response (slp.Body().GetPtr());
+
+ response.command = sysPktRPC2Rsp;
+ response._filler = 0;
+
+ response.resultD0 = errNone;
+ response.resultA0 = 0;
+ response.resultException = 0;
+
+ int numRegs = ::CountBits(response.DRegMask) +
+ ::CountBits(response.ARegMask);
+ UInt16* numParams = ((UInt16*) response.Regs.GetPtr ()) + numRegs;
+ EmAliasSysPktRPCParamType<LAS> param (numParams + 1);
+
+ param.asLong = signal;
+ }
+
+ long bodySize = slp.GetPacketSize () - (slp.Header().GetSize() + slp.Footer().GetSize());
+
+ ErrCode result = slp.SendPacket (response.GetPtr (), bodySize);
+
+ if (result == errNone)
+ {
+ signalledOne = true;
+ }
+
+ ++iter;
+ }
+
+ gSLPTimeouts.clear ();
+
+ // gSession may be NULL if we're signally a hostSignalQuit.
+
+ if (signalledOne && gSession)
+ {
+ gSession->ScheduleSuspendExternal ();
+ }
+
+ PRINTF ("RPC::SignalWaiters: Exiting");
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::HandleNewPacket
+ *
+ * DESCRIPTION: Completely handle a packet sent from an external
+ * client, setting any state and sending a reply if
+ * necessary.
+ *
+ * PARAMETERS: slp - a reference to a SerialLink Protocol object that
+ * contains the packet information and the horse...uh,
+ * socket it rode in on.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+ErrCode RPC::HandleNewPacket (SLP& slp)
+{
+ ErrCode result = errNone;
+
+ EmAssert (slp.Header ().dest == slkSocketRPC);
+
+ gCurrentPacket = &slp;
+
+ CEnableFullAccess munge; // Remove blocks on memory access.
+
+ try
+ {
+ switch (slp.Body ().command)
+ {
+ case sysPktReadMemCmd:
+ result = SystemPacket::ReadMem (slp);
+ break;
+
+ case sysPktWriteMemCmd:
+ result = SystemPacket::WriteMem (slp);
+ break;
+
+ case sysPktRPCCmd:
+ result = SystemPacket::RPC (slp);
+ break;
+
+ case sysPktRPC2Cmd:
+ result = SystemPacket::RPC2 (slp);
+ break;
+
+ default:
+ break;
+ }
+ }
+ catch (...)
+ {
+ gCurrentPacket = NULL;
+ throw;
+ }
+
+ gCurrentPacket = NULL;
+
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::HandlingPacket
+ *
+ * DESCRIPTION: DESCRIPTION
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+Bool RPC::HandlingPacket (void)
+{
+ return gCurrentPacket != NULL;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::DeferCurrentPacket
+ *
+ * DESCRIPTION: DESCRIPTION
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void RPC::DeferCurrentPacket (long timeout)
+{
+ omni_mutex_lock lock (gMutex);
+
+ PRINTF ("RPC::DeferCurrentPacket: Entering");
+
+ EmAssert (gCurrentPacket);
+
+ gCurrentPacket->DeferReply (true);
+ gSLPTimeouts.push_back (SLPTimeout (*gCurrentPacket, timeout));
+
+ PRINTF ("RPC::DeferCurrentPacket: Exiting");
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::EventCallback
+ *
+ * DESCRIPTION: Callback function for RPC-related sockets. When an RPC
+ * socket connects, we instantly create a new listener.
+ * When an RPC socket disconnects, we delete it.
+ *
+ * PARAMETERS: s - the socket that connected, disconnected, or received
+ * some data.
+ *
+ * event - a code indicating what happened.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void RPC::EventCallback (CSocket* s, int event)
+{
+ switch (event)
+ {
+ case CSocket::kConnected:
+ {
+ RPC::CreateNewListener ();
+ break;
+ }
+
+ case CSocket::kDataReceived:
+ {
+ break;
+ }
+
+ case CSocket::kDisconnected:
+ {
+ // A socket just disconnected. If we had anything on that
+ // socket waiting for us to signal it, forget about it.
+
+ SLPTimeoutList::iterator iter = gSLPTimeouts.begin ();
+
+ while (iter != gSLPTimeouts.end ())
+ {
+ if (iter->fSLP.HasSocket (s))
+ {
+ gSLPTimeouts.erase (iter);
+ iter = gSLPTimeouts.begin ();
+ continue;
+ }
+
+ ++iter;
+ }
+
+ s->Delete ();
+ }
+ }
+
+ SLP::EventCallback (s, event);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: RPC::CreateNewListener
+ *
+ * DESCRIPTION: Create a new socket for listening for RPC clients.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void RPC::CreateNewListener (void)
+{
+ Preference<long> portPref (kPrefKeyRPCSocketPort);
+
+ if (*portPref != 0)
+ {
+ CSocket* rpcSocket = new CTCPSocket (&RPC::EventCallback, *portPref);
+ ErrCode err = rpcSocket->Open ();
+ if (err != errNone)
+ {
+ rpcSocket->Delete ();
+ rpcSocket = NULL;
+ }
+ }
+}
+
+