summaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Service
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/Service')
-rw-r--r--LibOVR/Src/Service/Service_NetClient.cpp275
-rw-r--r--LibOVR/Src/Service/Service_NetClient.h54
-rw-r--r--LibOVR/Src/Service/Service_NetSessionCommon.cpp276
-rwxr-xr-x[-rw-r--r--]LibOVR/Src/Service/Service_NetSessionCommon.h53
-rw-r--r--LibOVR/Src/Service/Service_Win32_FastIPC_Client.cpp228
-rw-r--r--LibOVR/Src/Service/Service_Win32_FastIPC_Client.h84
6 files changed, 646 insertions, 324 deletions
diff --git a/LibOVR/Src/Service/Service_NetClient.cpp b/LibOVR/Src/Service/Service_NetClient.cpp
index c6af2cd..22fea89 100644
--- a/LibOVR/Src/Service/Service_NetClient.cpp
+++ b/LibOVR/Src/Service/Service_NetClient.cpp
@@ -25,11 +25,12 @@ limitations under the License.
************************************************************************************/
#include "Service_NetClient.h"
-#include "../Net/OVR_MessageIDTypes.h"
+#include "Net/OVR_MessageIDTypes.h"
#if defined (OVR_OS_MAC) || defined(OVR_OS_LINUX)
#define GetCurrentProcessId getpid
#endif
+
OVR_DEFINE_SINGLETON(OVR::Service::NetClient);
namespace OVR { namespace Service {
@@ -37,13 +38,17 @@ namespace OVR { namespace Service {
using namespace OVR::Net;
+// Default connection timeout in milliseconds.
+static const int kDefaultConnectionTimeoutMS = 5000; // Timeout in Milliseconds
+
+
//// NetClient
NetClient::NetClient() :
- LatencyTesterAvailable(false),
- HMDCount(0),
- EdgeTriggeredHMDCount(false)
+ LatencyTesterAvailable(false), HMDCount(-1), EdgeTriggeredHMDCount(false)
{
+ SetDefaultParameters();
+
GetSession()->AddSessionListener(this);
// Register RPC functions
@@ -51,7 +56,7 @@ NetClient::NetClient() :
Start();
- // Must be at end of function
+ // Must be at end of function
PushDestroyCallbacks();
}
@@ -69,19 +74,40 @@ void NetClient::OnThreadDestroy()
onThreadDestroy();
}
+void NetClient::SetDefaultParameters()
+{
+ ServerOptional = false;
+ ExtraDebugging = false;
+ ConnectionTimeoutMS = kDefaultConnectionTimeoutMS;
+}
+
+void NetClient::ApplyParameters(ovrInitParams const* params)
+{
+ SetDefaultParameters();
+
+ // If connection timeout is specified,
+ if (params->ConnectionTimeoutMS > 0)
+ {
+ ConnectionTimeoutMS = params->ConnectionTimeoutMS;
+ }
+
+ ServerOptional = (params->Flags & ovrInit_ServerOptional) != 0;
+ ExtraDebugging = (params->Flags & ovrInit_Debug) != 0;
+}
+
int NetClient::Run()
{
SetThreadName("NetClient");
- while (!Terminated)
+ while (!Terminated.load(std::memory_order_relaxed))
{
- // Note: There is no watchdog here because the watchdog is part of the private code
+ // There is no watchdog here because the watchdog is part of the private code.
GetSession()->Poll(false);
if (GetSession()->GetActiveSocketsCount() == 0)
{
- Thread::MSleep(10);
+ Thread::MSleep(100);
}
}
@@ -107,8 +133,22 @@ void NetClient::OnConnected(Connection* conn)
{
OVR_UNUSED(conn);
- OVR_DEBUG_LOG(("[NetClient] Connected to a server running version %d.%d.%d (my version=%d.%d.%d)",
+ OVR_DEBUG_LOG(("[NetClient] Connected to the server running SDK version " \
+ "(prod=%d).%d.%d(req=%d).%d(build=%d), RPC version %d.%d.%d. " \
+ "Client SDK version (prod=%d).%d.%d(req=%d).%d.(build=%d), RPC version=%d.%d.%d",
+ conn->RemoteCodeVersion.ProductVersion,
+ conn->RemoteCodeVersion.MajorVersion,
+ conn->RemoteCodeVersion.MinorVersion,
+ conn->RemoteCodeVersion.RequestedMinorVersion,
+ conn->RemoteCodeVersion.PatchVersion,
+ conn->RemoteCodeVersion.BuildNumber,
conn->RemoteMajorVersion, conn->RemoteMinorVersion, conn->RemotePatchVersion,
+ OVR_PRODUCT_VERSION,
+ OVR_MAJOR_VERSION,
+ OVR_MINOR_VERSION,
+ RuntimeSDKVersion.RequestedMinorVersion,
+ OVR_PATCH_VERSION,
+ OVR_BUILD_NUMBER,
RPCVersion_Major, RPCVersion_Minor, RPCVersion_Patch));
EdgeTriggeredHMDCount = false;
@@ -116,12 +156,18 @@ void NetClient::OnConnected(Connection* conn)
bool NetClient::Connect(bool blocking)
{
+ // If server is optional,
+ if (ServerOptional && !Session::IsSingleProcess())
+ {
+ blocking = false; // Poll: Do not block
+ }
+
// Set up bind parameters
- OVR::Net::BerkleyBindParameters bbp;
- bbp.Address = "::1"; // Bind to localhost only!
- bbp.blockingTimeout = 5000;
- OVR::Net::SockAddr sa;
- sa.Set("::1", VRServicePort, SOCK_STREAM);
+ OVR::Net::BerkleyBindParameters bbp;
+ bbp.Address = "::1"; // Bind to localhost only!
+ bbp.blockingTimeout = ConnectionTimeoutMS;
+ OVR::Net::SockAddr sa;
+ sa.Set("::1", VRServicePort, SOCK_STREAM);
// Attempt to connect
OVR::Net::SessionResult result = GetSession()->ConnectPTCP(&bbp, &sa, blocking);
@@ -140,7 +186,7 @@ void NetClient::Disconnect()
bool NetClient::IsConnected(bool attemptReconnect, bool blockOnReconnect)
{
// If it was able to connect,
- if (GetSession()->GetConnectionCount() > 0)
+ if (GetSession()->ConnectionSuccessful())
{
return true;
}
@@ -150,7 +196,7 @@ bool NetClient::IsConnected(bool attemptReconnect, bool blockOnReconnect)
Connect(blockOnReconnect);
// If it connected,
- if (GetSession()->GetConnectionCount() > 0)
+ if (GetSession()->ConnectionSuccessful())
{
return true;
}
@@ -182,21 +228,39 @@ bool NetClient::GetRemoteProtocolVersion(int& major, int& minor, int& patch)
return false;
}
+void NetClient::GetLocalSDKVersion(SDKVersion& requestedSDKVersion)
+{
+ requestedSDKVersion = RuntimeSDKVersion;
+}
+
+bool NetClient::GetRemoteSDKVersion(SDKVersion& remoteSDKVersion)
+{
+ Ptr<Connection> conn = GetSession()->GetConnectionAtIndex(0);
+
+ if (conn)
+ {
+ remoteSDKVersion = conn->RemoteCodeVersion;
+ return true;
+ }
+
+ return false;
+}
+
//// NetClient API
const char* NetClient::GetStringValue(VirtualHmdId hmd, const char* key, const char* default_val)
{
- if (!IsConnected(true, true))
+ // If a null value is provided,
+ if (!default_val)
{
- return "";
+ default_val = "";
}
- // If a null value is provided,
- if (!default_val)
- {
- default_val = "";
- }
+ if (!IsConnected(true, true))
+ {
+ return default_val;
+ }
ProfileGetValue1_Str = default_val;
@@ -206,11 +270,11 @@ const char* NetClient::GetStringValue(VirtualHmdId hmd, const char* key, const c
bsOut.Write(default_val);
if (!GetRPC1()->CallBlocking("GetStringValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
{
- return "";
+ return default_val;
}
if (!returnData.Read(ProfileGetValue1_Str))
{
- OVR_ASSERT(false);
+ OVR_ASSERT(false); //This assert will hit if you tamper or restart the service mid-call.
}
return ProfileGetValue1_Str.ToCStr();
}
@@ -227,12 +291,12 @@ bool NetClient::GetBoolValue(VirtualHmdId hmd, const char* key, bool default_val
bsOut.Write(default_val);
if (!GetRPC1()->CallBlocking("GetBoolValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
{
- return default_val;
+ return default_val;
}
uint8_t out = 0;
if (!returnData.Read(out))
{
- OVR_ASSERT(false);
+ OVR_ASSERT(false); //This assert will hit if you tamper or restart the service mid-call.
}
return out != 0;
}
@@ -249,12 +313,12 @@ int NetClient::GetIntValue(VirtualHmdId hmd, const char* key, int default_val)
bsOut.Write(default_val);
if (!GetRPC1()->CallBlocking("GetIntValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
{
- return default_val;
+ return default_val;
}
int32_t out = (int32_t)default_val;
if (!returnData.Read(out))
{
- OVR_ASSERT(false);
+ OVR_ASSERT(false); //This assert will hit if you tamper or restart the service mid-call.
}
return out;
}
@@ -271,10 +335,13 @@ double NetClient::GetNumberValue(VirtualHmdId hmd, const char* key, double defau
bsOut.Write(default_val);
if (!GetRPC1()->CallBlocking("GetNumberValue_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
{
- return default_val;
+ return default_val;
}
double out = 0.;
- returnData.Read(out);
+ if (!returnData.Read(out))
+ {
+ OVR_ASSERT(false); //This assert will hit if you tamper or restart the service mid-call.
+ }
return out;
}
int NetClient::GetNumberValues(VirtualHmdId hmd, const char* key, double* values, int num_vals)
@@ -293,7 +360,7 @@ int NetClient::GetNumberValues(VirtualHmdId hmd, const char* key, double* values
if (!GetRPC1()->CallBlocking("GetNumberValues_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
{
- return 0;
+ return 0;
}
int32_t out = 0;
@@ -439,7 +506,7 @@ int NetClient::Hmd_Detect()
{
if (!IsConnected(true, false))
{
- return 0;
+ return -1;
}
// If using edge-triggered HMD counting,
@@ -451,21 +518,21 @@ int NetClient::Hmd_Detect()
// Otherwise: We need to ask the first time
- OVR::Net::BitStream bsOut, returnData;
+ OVR::Net::BitStream bsOut, returnData;
- if (!GetRPC1()->CallBlocking("Hmd_Detect_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
- {
- return 0;
- }
+ if (!GetRPC1()->CallBlocking("Hmd_Detect_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
+ {
+ return -1;
+ }
int32_t out = 0;
if (!returnData.Read(out))
{
- OVR_ASSERT(false);
+ OVR_ASSERT(false); //This assert will hit if you tamper or restart the service mid-call.
}
HMDCount = out;
EdgeTriggeredHMDCount = true;
- return out;
+ return out;
}
bool NetClient::Hmd_Create(int index, HMDNetworkInfo* netInfo)
@@ -475,21 +542,21 @@ bool NetClient::Hmd_Create(int index, HMDNetworkInfo* netInfo)
return false;
}
- OVR::Net::BitStream bsOut, returnData;
+ OVR::Net::BitStream bsOut, returnData;
int32_t w = (int32_t)index;
- bsOut.Write(w);
+ bsOut.Write(w);
// Need the Pid for driver mode
pid_t pid = GetCurrentProcessId();
bsOut.Write(pid);
- if (!GetRPC1()->CallBlocking("Hmd_Create_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
- {
- return false;
- }
+ if (!GetRPC1()->CallBlocking("Hmd_Create_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
+ {
+ return false;
+ }
- return netInfo->Deserialize(&returnData);
+ return netInfo->Serialize(&returnData, false);
}
bool NetClient::GetDriverMode(bool& driverInstalled, bool& compatMode, bool& hideDK1Mode)
@@ -566,15 +633,19 @@ bool NetClient::Hmd_AttachToWindow(VirtualHmdId hmd, void* hWindow)
OVR::Net::BitStream bsOut;
bsOut.Write(hmd);
+ uint64_t hWinWord = 0;
#ifdef OVR_OS_LINUX
- if (hWindow == NULL)
- {
- return false;
- }
- unsigned long hWinWord = *(unsigned long *)hWindow;
+ if (hWindow == NULL)
+ {
+ return false;
+ }
+ hWinWord = *(uint64_t *)&hWindow;
+ #elif defined(OVR_OS_WIN32)
+ hWinWord = (UPInt)hWindow;
#else
- UInt64 hWinWord = (UPInt)hWindow;
+ OVR_UNUSED(hWindow);
#endif
+
bsOut.Write(hWinWord);
if (!GetRPC1()->CallBlocking("Hmd_AttachToWindow_1", &bsOut, GetSession()->GetConnectionAtIndex(0)))
@@ -592,9 +663,9 @@ void NetClient::Hmd_Release(VirtualHmdId hmd)
return;
}
- OVR::Net::BitStream bsOut;
- bsOut.Write(hmd);
- bool result = GetRPC1()->CallBlocking("Hmd_Release_1", &bsOut, GetSession()->GetConnectionAtIndex(0));
+ OVR::Net::BitStream bsOut;
+ bsOut.Write(hmd);
+ bool result = GetRPC1()->CallBlocking("Hmd_Release_1", &bsOut, GetSession()->GetConnectionAtIndex(0));
OVR_ASSERT_AND_UNUSED(result, result);
}
@@ -612,16 +683,16 @@ const char* NetClient::Hmd_GetLastError(VirtualHmdId hmd)
}
OVR::Net::BitStream bsOut, returnData;
- bsOut.Write(hmd);
+ bsOut.Write(hmd);
if (!GetRPC1()->CallBlocking("Hmd_GetLastError_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
- {
- return Hmd_GetLastError_Str.ToCStr();
- }
+ {
+ return Hmd_GetLastError_Str.ToCStr();
+ }
if (!returnData.Read(Hmd_GetLastError_Str))
{
OVR_ASSERT(false);
}
- return Hmd_GetLastError_Str.ToCStr();
+ return Hmd_GetLastError_Str.ToCStr();
}
@@ -634,14 +705,14 @@ bool NetClient::Hmd_GetHmdInfo(VirtualHmdId hmd, HMDInfo* hmdInfo)
return false;
}
- OVR::Net::BitStream bsOut, returnData;
- bsOut.Write(hmd);
- if (!GetRPC1()->CallBlocking("Hmd_GetHmdInfo_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
- {
- return false;
- }
+ OVR::Net::BitStream bsOut, returnData;
+ bsOut.Write(hmd);
+ if (!GetRPC1()->CallBlocking("Hmd_GetHmdInfo_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
+ {
+ return false;
+ }
- return NetSessionCommon::DeserializeHMDInfo(&returnData, hmdInfo);
+ return NetSessionCommon::SerializeHMDInfo(&returnData, hmdInfo, false);
}
@@ -653,19 +724,19 @@ unsigned int NetClient::Hmd_GetEnabledCaps(VirtualHmdId hmd)
return 0;
}
- OVR::Net::BitStream bsOut, returnData;
- bsOut.Write(hmd);
- if (!GetRPC1()->CallBlocking("Hmd_GetEnabledCaps_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
- {
- return 0;
- }
+ OVR::Net::BitStream bsOut, returnData;
+ bsOut.Write(hmd);
+ if (!GetRPC1()->CallBlocking("Hmd_GetEnabledCaps_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
+ {
+ return 0;
+ }
uint32_t c = 0;
if (!returnData.Read(c))
{
- OVR_ASSERT(false);
+ OVR_ASSERT(false); //This assert will hit if you tamper or restart the service mid-call.
}
- return c;
+ return c;
}
// Returns new caps after modification
@@ -676,21 +747,21 @@ unsigned int NetClient::Hmd_SetEnabledCaps(VirtualHmdId hmd, unsigned int hmdCap
return 0;
}
- OVR::Net::BitStream bsOut, returnData;
- bsOut.Write(hmd);
+ OVR::Net::BitStream bsOut, returnData;
+ bsOut.Write(hmd);
uint32_t c = (uint32_t)hmdCaps;
- bsOut.Write(c);
+ bsOut.Write(c);
- if (!GetRPC1()->CallBlocking("Hmd_SetEnabledCaps_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
- {
- return 0;
- }
+ if (!GetRPC1()->CallBlocking("Hmd_SetEnabledCaps_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
+ {
+ return 0;
+ }
c = 0;
if (!returnData.Read(c))
{
- OVR_ASSERT(false);
+ OVR_ASSERT(false); //This assert will hit if you tamper or restart the service mid-call.
}
return c;
}
@@ -706,18 +777,18 @@ bool NetClient::Hmd_ConfigureTracking(VirtualHmdId hmd, unsigned supportedCaps,
return false;
}
- OVR::Net::BitStream bsOut, returnData;
- bsOut.Write(hmd);
+ OVR::Net::BitStream bsOut, returnData;
+ bsOut.Write(hmd);
uint32_t w_sc = supportedCaps;
bsOut.Write(w_sc);
uint32_t w_rc = requiredCaps;
bsOut.Write(w_rc);
- if (!GetRPC1()->CallBlocking("Hmd_ConfigureTracking_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
- {
- return false;
- }
+ if (!GetRPC1()->CallBlocking("Hmd_ConfigureTracking_1", &bsOut, GetSession()->GetConnectionAtIndex(0), &returnData))
+ {
+ return false;
+ }
uint8_t b;
if (!returnData.Read(b))
@@ -725,23 +796,28 @@ bool NetClient::Hmd_ConfigureTracking(VirtualHmdId hmd, unsigned supportedCaps,
OVR_ASSERT(false);
}
- return b != 0;
+ return b != 0;
}
-void NetClient::Hmd_ResetTracking(VirtualHmdId hmd)
+void NetClient::Hmd_ResetTracking(VirtualHmdId hmd, bool visionReset)
{
if (!IsConnected(false, false))
{
return;
}
- OVR::Net::BitStream bsOut;
- bsOut.Write(hmd);
- if (!GetRPC1()->CallBlocking("Hmd_ResetTracking_1", &bsOut, GetSession()->GetConnectionAtIndex(0)))
- {
- return;
- }
+ OVR::Net::BitStream bsOut;
+ bsOut.Write(hmd);
+
+ int32_t w_visionReset;
+ w_visionReset = visionReset ? 1 : 0;
+ bsOut.Write(w_visionReset);
+
+ if (!GetRPC1()->CallBlocking("Hmd_ResetTracking_1", &bsOut, GetSession()->GetConnectionAtIndex(0)))
+ {
+ return;
+ }
}
bool NetClient::LatencyUtil_ProcessInputs(double startTestSeconds, unsigned char rgbColorOut[3])
@@ -817,7 +893,8 @@ bool NetClient::ShutdownServer()
void NetClient::registerRPC()
{
#define RPC_REGISTER_SLOT(observerScope, functionName) \
- observerScope.SetHandler(OVR::Net::Plugins::RPCSlot::FromMember<NetClient, &NetClient::functionName>(this)); pRPC->RegisterSlot(OVR_STRINGIZE(functionName), observerScope);
+ observerScope.SetHandler(OVR::Net::Plugins::RPCSlot::FromMember<NetClient, &NetClient::functionName>(this)); \
+ pRPC->RegisterSlot(OVR_STRINGIZE(functionName), &observerScope);
// Register RPC functions:
RPC_REGISTER_SLOT(InitialServerStateScope, InitialServerState_1);
diff --git a/LibOVR/Src/Service/Service_NetClient.h b/LibOVR/Src/Service/Service_NetClient.h
index ab7906e..508c485 100644
--- a/LibOVR/Src/Service/Service_NetClient.h
+++ b/LibOVR/Src/Service/Service_NetClient.h
@@ -27,11 +27,11 @@ limitations under the License.
#ifndef OVR_Service_NetClient_h
#define OVR_Service_NetClient_h
-#include "../Net/OVR_NetworkTypes.h"
+#include "Net/OVR_NetworkTypes.h"
#include "Service_NetSessionCommon.h"
-#include "../Kernel/OVR_System.h"
-#include "../OVR_CAPI.h"
-#include "../Util/Util_Render_Stereo.h"
+#include "Kernel/OVR_System.h"
+#include "OVR_CAPI.h"
+#include "Util/Util_Render_Stereo.h"
namespace OVR { namespace Service {
@@ -48,28 +48,22 @@ class NetClient : public NetSessionCommon,
OVR_DECLARE_SINGLETON(NetClient);
virtual void OnThreadDestroy();
- // Status
- bool LatencyTesterAvailable;
- int HMDCount;
- bool EdgeTriggeredHMDCount;
-
- virtual void OnReceive(Net::ReceivePayload* pPayload, Net::ListenerReceiveResult* lrrOut);
- virtual void OnDisconnected(Net::Connection* conn);
- virtual void OnConnected(Net::Connection* conn);
-
- virtual int Run();
-
public:
bool Connect(bool blocking);
bool IsConnected(bool attemptReconnect, bool blockOnReconnect);
void Disconnect();
void GetLocalProtocolVersion(int& major, int& minor, int& patch);
- // This function may fail if it is not connected
+ void GetLocalSDKVersion(SDKVersion& requestedSDKVersion);
+
+ // These functions may fail if it is not connected
bool GetRemoteProtocolVersion(int& major, int& minor, int& patch);
+ bool GetRemoteSDKVersion(SDKVersion& remoteSDKVersion);
void SetLastError(String str);
+ void ApplyParameters(ovrInitParams const* params);
+
public:
// Persistent key-value storage
const char* GetStringValue(VirtualHmdId hmd, const char* key, const char* default_val);
@@ -112,7 +106,7 @@ public:
// *** Tracking Setup
bool Hmd_ConfigureTracking(VirtualHmdId hmd, unsigned supportedCaps, unsigned requiredCaps);
- void Hmd_ResetTracking(VirtualHmdId hmd);
+ void Hmd_ResetTracking(VirtualHmdId hmd, bool visionReset);
// TBD: Camera frames
bool LatencyUtil_ProcessInputs(double startTestSeconds, unsigned char rgbColorOut[3]);
@@ -121,25 +115,43 @@ public:
bool ShutdownServer();
protected:
+ // Status
+ bool LatencyTesterAvailable;
+ int HMDCount;
+ bool EdgeTriggeredHMDCount;
+
String Hmd_GetLastError_Str;
String LatencyUtil_GetResultsString_Str;
String ProfileGetValue1_Str, ProfileGetValue3_Str;
+ // Parameters passed to ovr_Initialize()
+ bool ServerOptional; // Server connection is optional?
+ bool ExtraDebugging; // Extra debugging enabled?
+ int ConnectionTimeoutMS; // Connection timeout in milliseconds
+
+ void SetDefaultParameters();
+
protected:
+ virtual void OnReceive(Net::ReceivePayload* pPayload, Net::ListenerReceiveResult* lrrOut);
+ virtual void OnDisconnected(Net::Connection* conn);
+ virtual void OnConnected(Net::Connection* conn);
+
+ virtual int Run();
+
//// Push Notifications:
void registerRPC();
- ObserverScope<Net::Plugins::RPCSlot> InitialServerStateScope;
+ CallbackListener<Net::Plugins::RPCSlot> InitialServerStateScope;
void InitialServerState_1(BitStream* userData, ReceivePayload* pPayload);
- ObserverScope<Net::Plugins::RPCSlot> LatencyTesterAvailableScope;
+ CallbackListener<Net::Plugins::RPCSlot> LatencyTesterAvailableScope;
void LatencyTesterAvailable_1(BitStream* userData, ReceivePayload* pPayload);
- ObserverScope<Net::Plugins::RPCSlot> DefaultLogOutputScope;
+ CallbackListener<Net::Plugins::RPCSlot> DefaultLogOutputScope;
void DefaultLogOutput_1(BitStream* userData, ReceivePayload* pPayload);
- ObserverScope<Net::Plugins::RPCSlot> HMDCountUpdateScope;
+ CallbackListener<Net::Plugins::RPCSlot> HMDCountUpdateScope;
void HMDCountUpdate_1(BitStream* userData, ReceivePayload* pPayload);
};
diff --git a/LibOVR/Src/Service/Service_NetSessionCommon.cpp b/LibOVR/Src/Service/Service_NetSessionCommon.cpp
index ba2c773..4a9fda6 100644
--- a/LibOVR/Src/Service/Service_NetSessionCommon.cpp
+++ b/LibOVR/Src/Service/Service_NetSessionCommon.cpp
@@ -30,7 +30,8 @@ limitations under the License.
namespace OVR { namespace Service {
-//// NetSessionCommon
+//-----------------------------------------------------------------------------
+// NetSessionCommon
NetSessionCommon::NetSessionCommon() :
Terminated(false)
@@ -57,14 +58,14 @@ NetSessionCommon::~NetSessionCommon()
pRPC = NULL;
}
- Terminated = true;
+ Terminated.store(true, std::memory_order_relaxed);
OVR_ASSERT(IsFinished());
}
void NetSessionCommon::onSystemDestroy()
{
- Terminated = true;
+ Terminated.store(true, std::memory_order_relaxed);
Join();
@@ -73,93 +74,106 @@ void NetSessionCommon::onSystemDestroy()
void NetSessionCommon::onThreadDestroy()
{
- Terminated = true;
+ Terminated.store(true, std::memory_order_relaxed);
if (pSession)
{
pSession->Shutdown();
}
}
-void NetSessionCommon::SerializeHMDInfo(Net::BitStream *bitStream, HMDInfo* hmdInfo)
+template<typename T>
+static bool SerializeUInt32(bool write, Net::BitStream* bitStream, T& data)
{
- bitStream->Write(hmdInfo->ProductName);
- bitStream->Write(hmdInfo->Manufacturer);
-
- int32_t w = hmdInfo->Version;
- bitStream->Write(w);
-
- w = hmdInfo->HmdType;
- bitStream->Write(w);
-
- w = hmdInfo->ResolutionInPixels.w;
- bitStream->Write(w);
-
- w = hmdInfo->ResolutionInPixels.h;
- bitStream->Write(w);
+ int32_t w = 0;
+ bool result = false;
- w = hmdInfo->ShimInfo.DeviceNumber;
- bitStream->Write(w);
+ if (write)
+ {
+ w = (int32_t)data;
+ result = bitStream->Serialize(write, w);
+ }
+ else
+ {
+ result = bitStream->Serialize(write, w);
+ data = (T)w;
+ }
- w = hmdInfo->ShimInfo.NativeWidth;
- bitStream->Write(w);
+ return result;
+}
- w = hmdInfo->ShimInfo.NativeHeight;
- bitStream->Write(w);
+static bool SerializeBool(bool write, Net::BitStream* bitStream, bool& data)
+{
+ uint8_t x = 0;
+ bool result = false;
- w = hmdInfo->ShimInfo.Rotation;
- bitStream->Write(w);
+ if (write)
+ {
+ x = data ? 1 : 0;
+ result = bitStream->Serialize(write, x);
+ }
+ else
+ {
+ result = bitStream->Serialize(write, x);
+ data = (x != 0);
+ }
- bitStream->Write(hmdInfo->ScreenSizeInMeters.w);
- bitStream->Write(hmdInfo->ScreenSizeInMeters.h);
- bitStream->Write(hmdInfo->ScreenGapSizeInMeters);
- bitStream->Write(hmdInfo->CenterFromTopInMeters);
- bitStream->Write(hmdInfo->LensSeparationInMeters);
+ return result;
+}
- w = hmdInfo->DesktopX;
- bitStream->Write(w);
+bool NetSessionCommon::SerializeHMDInfo(Net::BitStream *bitStream, HMDInfo* hmdInfo, bool write)
+{
+ bool result = false;
- w = hmdInfo->DesktopY;
- bitStream->Write(w);
+ bitStream->Serialize(write, hmdInfo->ProductName);
+ bitStream->Serialize(write, hmdInfo->Manufacturer);
- w = hmdInfo->Shutter.Type;
- bitStream->Write(w);
+ SerializeUInt32(write, bitStream, hmdInfo->Version);
+ SerializeUInt32(write, bitStream, hmdInfo->HmdType);
+ SerializeUInt32(write, bitStream, hmdInfo->ResolutionInPixels.w);
+ SerializeUInt32(write, bitStream, hmdInfo->ResolutionInPixels.h);
+ SerializeUInt32(write, bitStream, hmdInfo->ShimInfo.DeviceNumber);
+ SerializeUInt32(write, bitStream, hmdInfo->ShimInfo.NativeWidth);
+ SerializeUInt32(write, bitStream, hmdInfo->ShimInfo.NativeHeight);
+ SerializeUInt32(write, bitStream, hmdInfo->ShimInfo.Rotation);
- bitStream->Write(hmdInfo->Shutter.VsyncToNextVsync);
- bitStream->Write(hmdInfo->Shutter.VsyncToFirstScanline);
- bitStream->Write(hmdInfo->Shutter.FirstScanlineToLastScanline);
- bitStream->Write(hmdInfo->Shutter.PixelSettleTime);
- bitStream->Write(hmdInfo->Shutter.PixelPersistence);
- bitStream->Write(hmdInfo->DisplayDeviceName);
+ bitStream->Serialize(write, hmdInfo->ScreenSizeInMeters.w);
+ bitStream->Serialize(write, hmdInfo->ScreenSizeInMeters.h);
+ bitStream->Serialize(write, hmdInfo->ScreenGapSizeInMeters);
+ bitStream->Serialize(write, hmdInfo->CenterFromTopInMeters);
+ bitStream->Serialize(write, hmdInfo->LensSeparationInMeters);
- w = hmdInfo->DisplayId;
- bitStream->Write(w);
+ SerializeUInt32(write, bitStream, hmdInfo->DesktopX);
+ SerializeUInt32(write, bitStream, hmdInfo->DesktopY);
+ SerializeUInt32(write, bitStream, hmdInfo->Shutter.Type);
- bitStream->Write(hmdInfo->PrintedSerial);
+ bitStream->Serialize(write, hmdInfo->Shutter.VsyncToNextVsync);
+ bitStream->Serialize(write, hmdInfo->Shutter.VsyncToFirstScanline);
+ bitStream->Serialize(write, hmdInfo->Shutter.FirstScanlineToLastScanline);
+ bitStream->Serialize(write, hmdInfo->Shutter.PixelSettleTime);
+ bitStream->Serialize(write, hmdInfo->Shutter.PixelPersistence);
+ bitStream->Serialize(write, hmdInfo->DisplayDeviceName);
- uint8_t b = hmdInfo->InCompatibilityMode ? 1 : 0;
- bitStream->Write(b);
+ SerializeUInt32(write, bitStream, hmdInfo->DisplayId);
- w = hmdInfo->VendorId;
- bitStream->Write(w);
+ bitStream->Serialize(write, hmdInfo->PrintedSerial);
- w = hmdInfo->ProductId;
- bitStream->Write(w);
+ SerializeBool(write, bitStream, hmdInfo->InCompatibilityMode);
- bitStream->Write(hmdInfo->CameraFrustumFarZInMeters);
- bitStream->Write(hmdInfo->CameraFrustumHFovInRadians);
- bitStream->Write(hmdInfo->CameraFrustumNearZInMeters);
- bitStream->Write(hmdInfo->CameraFrustumVFovInRadians);
+ SerializeUInt32(write, bitStream, hmdInfo->VendorId);
+ SerializeUInt32(write, bitStream, hmdInfo->ProductId);
- w = hmdInfo->FirmwareMajor;
- bitStream->Write(w);
+ bitStream->Serialize(write, hmdInfo->CameraFrustumFarZInMeters);
+ bitStream->Serialize(write, hmdInfo->CameraFrustumHFovInRadians);
+ bitStream->Serialize(write, hmdInfo->CameraFrustumNearZInMeters);
+ bitStream->Serialize(write, hmdInfo->CameraFrustumVFovInRadians);
- w = hmdInfo->FirmwareMinor;
- bitStream->Write(w);
+ SerializeUInt32(write, bitStream, hmdInfo->FirmwareMajor);
+ SerializeUInt32(write, bitStream, hmdInfo->FirmwareMinor);
- bitStream->Write(hmdInfo->PelOffsetR.x);
- bitStream->Write(hmdInfo->PelOffsetR.y);
- bitStream->Write(hmdInfo->PelOffsetB.x);
- bitStream->Write(hmdInfo->PelOffsetB.y);
+ bitStream->Serialize(write, hmdInfo->PelOffsetR.x);
+ bitStream->Serialize(write, hmdInfo->PelOffsetR.y);
+ bitStream->Serialize(write, hmdInfo->PelOffsetB.x);
+ result = bitStream->Serialize(write, hmdInfo->PelOffsetB.y);
// Important please read before modifying!
// ----------------------------------------------------
@@ -167,138 +181,30 @@ void NetSessionCommon::SerializeHMDInfo(Net::BitStream *bitStream, HMDInfo* hmdI
// Otherwise we will break backwards compatibility
// and e.g. 0.4.4 runtime will not work with 0.4.3 SDK.
- // Please also update the DeserializeHMDInfo() function
- // below also and make sure that the members you added
- // are initialized properly in the HMDInfo constructor.
-
// Note that whenever new fields are added here you
// should also update the minor version of the RPC
// protocol in OVR_Session.h so that clients fail at
// a version check instead of when this data is
// found to be truncated from the server.
-}
-
-bool NetSessionCommon::DeserializeHMDInfo(Net::BitStream *bitStream, HMDInfo* hmdInfo)
-{
- bitStream->Read(hmdInfo->ProductName);
- bitStream->Read(hmdInfo->Manufacturer);
-
- int32_t w = 0;
- if (!bitStream->Read(w))
- {
- // This indicates that no HMD could be found
- return false;
- }
- hmdInfo->Version = w;
-
- bitStream->Read(w);
- hmdInfo->HmdType = (HmdTypeEnum)w;
-
- bitStream->Read(w);
- hmdInfo->ResolutionInPixels.w = w;
-
- bitStream->Read(w);
- hmdInfo->ResolutionInPixels.h = w;
-
- bitStream->Read(w);
- hmdInfo->ShimInfo.DeviceNumber = w;
-
- bitStream->Read(w);
- hmdInfo->ShimInfo.NativeWidth = w;
-
- bitStream->Read(w);
- hmdInfo->ShimInfo.NativeHeight = w;
-
- bitStream->Read(w);
- hmdInfo->ShimInfo.Rotation = w;
-
- bitStream->Read(hmdInfo->ScreenSizeInMeters.w);
- bitStream->Read(hmdInfo->ScreenSizeInMeters.h);
- bitStream->Read(hmdInfo->ScreenGapSizeInMeters);
- bitStream->Read(hmdInfo->CenterFromTopInMeters);
- bitStream->Read(hmdInfo->LensSeparationInMeters);
-
- bitStream->Read(w);
- hmdInfo->DesktopX = w;
-
- bitStream->Read(w);
- hmdInfo->DesktopY = w;
-
- bitStream->Read(w);
- hmdInfo->Shutter.Type = (HmdShutterTypeEnum)w;
-
- bitStream->Read(hmdInfo->Shutter.VsyncToNextVsync);
- bitStream->Read(hmdInfo->Shutter.VsyncToFirstScanline);
- bitStream->Read(hmdInfo->Shutter.FirstScanlineToLastScanline);
- bitStream->Read(hmdInfo->Shutter.PixelSettleTime);
- bitStream->Read(hmdInfo->Shutter.PixelPersistence);
- bitStream->Read(hmdInfo->DisplayDeviceName);
-
- bitStream->Read(w);
- hmdInfo->DisplayId = w;
-
- bitStream->Read(hmdInfo->PrintedSerial);
-
- uint8_t b = 0;
- bitStream->Read(b);
- hmdInfo->InCompatibilityMode = (b != 0);
-
- bitStream->Read(w);
- hmdInfo->VendorId = w;
-
- bitStream->Read(w);
- hmdInfo->ProductId = w;
-
- bitStream->Read(hmdInfo->CameraFrustumFarZInMeters);
- bitStream->Read(hmdInfo->CameraFrustumHFovInRadians);
- bitStream->Read(hmdInfo->CameraFrustumNearZInMeters);
- bitStream->Read(hmdInfo->CameraFrustumVFovInRadians);
-
- bitStream->Read(w);
- hmdInfo->FirmwareMajor = w;
-
- if (!bitStream->Read(w))
- {
- OVR_ASSERT(false);
- return false;
- }
- hmdInfo->FirmwareMinor = w;
-
- bitStream->Read(hmdInfo->PelOffsetR.x);
- bitStream->Read(hmdInfo->PelOffsetR.y);
- bitStream->Read(hmdInfo->PelOffsetB.x);
- if (!bitStream->Read(hmdInfo->PelOffsetB.y))
- {
- OVR_ASSERT(false);
- return false;
- }
-
- // Important please read before modifying!
- // ----------------------------------------------------
- // Please add new serialized data to the end, here.
- // Otherwise we will break backwards compatibility
- // and e.g. 0.4.4 runtime will not work with 0.4.3 SDK.
-
- // Be sure to check that the very last one read properly
- // since HMD Info truncation should be caught here.
- return true;
+ // The result of the final serialize should be returned to the caller.
+ return result;
}
// Prefix key names with this to pass through to server
static const char* BypassPrefix = "server:";
static const char* KeyNames[][NetSessionCommon::ENumTypes] = {
- /* EGetStringValue */ { "CameraSerial", "CameraUUID", 0 },
- /* EGetBoolValue */ { "ReleaseDK2Sensors", "ReleaseLegacySensors", 0 },
- /* EGetIntValue */ { 0 },
- /* EGetNumberValue */{ "CenterPupilDepth", "LoggingMask", 0 },
- /* EGetNumberValues */{ "NeckModelVector3f", 0 },
- /* ESetStringValue */ { 0 },
- /* ESetBoolValue */ { "ReleaseDK2Sensors", "ReleaseLegacySensors", 0 },
- /* ESetIntValue */ { 0 },
- /* ESetNumberValue */{ "CenterPupilDepth", "LoggingMask", 0 },
- /* ESetNumberValues */{ "NeckModelVector3f", 0 },
+ /* EGetStringValue */ { "CameraSerial", "CameraUUID", 0 },
+ /* EGetBoolValue */ { "ReleaseDK2Sensors", "ReleaseLegacySensors", 0 },
+ /* EGetIntValue */ { 0 },
+ /* EGetNumberValue */ { "CenterPupilDepth", "LoggingMask", 0 },
+ /* EGetNumberValues */ { "NeckModelVector3f", 0 },
+ /* ESetStringValue */ { 0 },
+ /* ESetBoolValue */ { "ReleaseDK2Sensors", "ReleaseLegacySensors", 0 },
+ /* ESetIntValue */ { 0 },
+ /* ESetNumberValue */ { "CenterPupilDepth", "LoggingMask", 0 },
+ /* ESetNumberValues */ { "NeckModelVector3f", 0 },
};
bool IsInStringArray(const char* a[], const char* key)
diff --git a/LibOVR/Src/Service/Service_NetSessionCommon.h b/LibOVR/Src/Service/Service_NetSessionCommon.h
index 79c0cfb..eefc292 100644..100755
--- a/LibOVR/Src/Service/Service_NetSessionCommon.h
+++ b/LibOVR/Src/Service/Service_NetSessionCommon.h
@@ -27,11 +27,14 @@ limitations under the License.
#ifndef OVR_Service_NetSessionCommon_h
#define OVR_Service_NetSessionCommon_h
-#include "../OVR_CAPI.h"
-#include "../Net/OVR_RPC1.h"
-#include "../Kernel/OVR_Threads.h"
-#include "../Net/OVR_BitStream.h"
-#include "../Kernel/OVR_System.h"
+#include <atomic>
+
+#include "OVR_CAPI.h"
+#include "Kernel/OVR_Threads.h"
+#include "Kernel/OVR_System.h"
+#include "Net/OVR_RPC1.h"
+#include "Net/OVR_BitStream.h"
+
namespace OVR {
@@ -52,6 +55,13 @@ static const int32_t InvalidVirtualHmdId = -1;
// Localhost-bound TCP port that the service listens on for VR apps
static const int VRServicePort = 30322; // 0x7672 = "vr" little-endian
+// Stores the names of shared memory regions
+struct SharedMemoryNames
+{
+ String Hmd;
+ String Camera;
+};
+
// HMDInfo section related to networking
struct HMDNetworkInfo
{
@@ -63,19 +73,25 @@ struct HMDNetworkInfo
// Network identifier for HMD
VirtualHmdId NetId;
- // Name of the shared memory object
- String SharedMemoryName;
+ // Names of the shared memory objects
+ SharedMemoryNames SharedMemoryName;
- void Serialize(Net::BitStream* bs)
+ bool Serialize(Net::BitStream* bs, bool write = true)
{
- bs->Write(NetId);
- bs->Write(SharedMemoryName);
- }
- bool Deserialize(Net::BitStream* bs)
- {
- bs->Read(NetId);
- return bs->Read(SharedMemoryName);
+ bs->Serialize(write, NetId);
+ bs->Serialize(write, SharedMemoryName.Hmd);
+ if (!bs->Serialize(write, SharedMemoryName.Camera))
+ return false;
+ return true;
}
+
+ // Assignment operator
+ HMDNetworkInfo& operator=(HMDNetworkInfo const & rhs)
+ {
+ NetId = rhs.NetId;
+ SharedMemoryName = rhs.SharedMemoryName;
+ return *this;
+ }
};
@@ -103,8 +119,7 @@ public:
return pSession;
}
- static void SerializeHMDInfo(Net::BitStream* bitStream, HMDInfo* hmdInfo);
- static bool DeserializeHMDInfo(Net::BitStream* bitStream, HMDInfo* hmdInfo);
+ static bool SerializeHMDInfo(Net::BitStream* bitStream, HMDInfo* hmdInfo, bool write = true);
public:
// Getter/setter tools
@@ -131,9 +146,9 @@ public:
static bool IsServiceProperty(EGetterSetters e, const char* key);
protected:
- bool Terminated; // Thread termination flag
+ std::atomic<bool> Terminated; // Thread termination flag
Net::Session* pSession; // Networking session
- Net::Plugins::RPC1* pRPC; // Remote procedure calls object
+ Net::Plugins::RPC1* pRPC; // Remote procedure calls object
};
diff --git a/LibOVR/Src/Service/Service_Win32_FastIPC_Client.cpp b/LibOVR/Src/Service/Service_Win32_FastIPC_Client.cpp
new file mode 100644
index 0000000..22a0b4a
--- /dev/null
+++ b/LibOVR/Src/Service/Service_Win32_FastIPC_Client.cpp
@@ -0,0 +1,228 @@
+/************************************************************************************
+
+Filename : Service_Win32_FastIPC_Client.cpp
+Content : Client side of connectionless fast IPC
+Created : Sept 16, 2014
+Authors : Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.2
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include "Service_Win32_FastIPC_Client.h"
+
+namespace OVR { namespace Service { namespace Win32 {
+
+using namespace OVR::Net;
+
+
+//// FastIPCClient
+
+FastIPCClient::FastIPCClient()
+{
+}
+
+bool FastIPCClient::ReadInitialData(const char* buffer)
+{
+ uint32_t magic = *(uint32_t*)(buffer);
+ uint32_t verMajor = *(uint32_t*)(buffer + 4);
+ uint32_t verMinor = *(uint32_t*)(buffer + 8);
+
+ if (magic != Magic)
+ {
+ LogError("Magic does not match");
+ return false;
+ }
+
+ if (verMajor != MajorVersion)
+ {
+ LogError("Major version mismatch");
+ return false;
+ }
+
+ if (verMinor < MinorVersion)
+ {
+ LogError("Remote minor version too old for our feature level");
+ return false;
+ }
+
+ HANDLE remoteDataEvent = (HANDLE)*(uint64_t*)(buffer + 12);
+ HANDLE remoteReturnEvent = (HANDLE)*(uint64_t*)(buffer + 20);
+ pid_t serverProcessId = (pid_t) *(uint64_t*)(buffer + 28);
+ OVR_UNUSED(serverProcessId);
+
+ if (!remoteDataEvent || !remoteReturnEvent)
+ {
+ LogError("Handshake was malformed. It seems like a version mismatch.");
+ return false;
+ }
+
+ DataEvent.Attach(remoteDataEvent);
+ ReturnEvent.Attach(remoteReturnEvent);
+
+ return true;
+}
+
+bool FastIPCClient::Initialize(const char* sharedMemoryName)
+{
+ SharedMemory::OpenParameters params;
+ params.accessMode = SharedMemory::AccessMode_ReadWrite;
+ params.globalName = sharedMemoryName;
+ params.minSizeBytes = RegionSize;
+ params.openMode = SharedMemory::OpenMode_OpenOnly;
+ params.remoteMode = SharedMemory::RemoteMode_ReadWrite;
+ Scratch = SharedMemoryFactory::GetInstance()->Open(params);
+ IPCMessageIndex = 1;
+
+ if (!Scratch || Scratch->GetSizeI() < RegionSize)
+ {
+ OVR_ASSERT(false);
+ LogError("Unable to open shared memory region");
+ return false;
+ }
+
+ char* data = (char*)Scratch->GetData();
+
+ // If unable to read handshake,
+ if (!ReadInitialData(data))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+FastIPCClient::~FastIPCClient()
+{
+}
+
+bool FastIPCClient::Call(Net::BitStream* parameters, Net::BitStream* returnData, int timeoutMs)
+{
+ // If not initialized,
+ if (!ReturnEvent.IsValid())
+ {
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ volatile unsigned char* scratch = (unsigned char*)Scratch->GetData();
+
+ uint32_t bytesUsed = ((uint32_t)parameters->GetNumberOfBitsUsed() + 7) / 8;
+
+ // If data is too long,
+ if (bytesUsed > RegionSize - 4)
+ {
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ // First 4 bytes will be the size of the parameters
+ // Note that this is for IPC so endian-ness is not important
+ *(uint32_t*)(scratch + 4) = bytesUsed;
+
+ // Copy data into place
+ memcpy((char*)scratch + 8, parameters->GetData(), bytesUsed);
+
+ // Don't allow read/write operations to move around this point
+ MemoryBarrier();
+
+ // Write message index
+ *(volatile uint32_t*)scratch = IPCMessageIndex;
+
+ // Wake the remote thread to service our request
+ if (!::SetEvent(DataEvent.Get()))
+ {
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ // Wait for result of call:
+
+ ++IPCMessageIndex;
+
+ // Use the GetTickCount() API for low-resolution timing
+ DWORD t0 = ::GetTickCount();
+ int remaining = timeoutMs;
+
+ // Forever,
+ for (;;)
+ {
+ // Wait on the return event
+ DWORD result = ::WaitForSingleObject(ReturnEvent.Get(), timeoutMs < 0 ? INFINITE : remaining);
+
+ if (result == WAIT_FAILED)
+ {
+ int err = GetLastError();
+ LogError("[FastIPC] Wait failed with error %d", err);
+ }
+
+ // If wait succeeded,
+ if (result == WAIT_OBJECT_0)
+ {
+ if (*(volatile uint32_t*)scratch != IPCMessageIndex)
+ {
+ double callTimeoutStart = Timer::GetSeconds();
+
+ while (*(volatile uint32_t*)scratch != IPCMessageIndex)
+ {
+ if (Timer::GetSeconds() - callTimeoutStart > 1.)
+ {
+ LogError("[FastIPC] Timed out waiting for remote IPC message to be written.");
+ OVR_ASSERT(false);
+ return false;
+ }
+
+ Thread::YieldCurrentThread();
+ }
+ }
+
+ _ReadBarrier();
+
+ // Wrap the scratch buffer
+ uint32_t len = *(uint32_t*)(scratch + 4);
+ returnData->WrapBuffer((unsigned char*)scratch + 8, len);
+
+ ++IPCMessageIndex;
+
+ // Return true for success
+ return true;
+ }
+
+ // If not waiting forever,
+ if (timeoutMs > 0)
+ {
+ // If wait time has elapsed,
+ int elapsed = ::GetTickCount() - t0;
+ if (elapsed >= timeoutMs)
+ {
+ // Break out of loop returning false
+ break;
+ }
+
+ // Calculate remaining wait time
+ remaining = timeoutMs - elapsed;
+ }
+
+ // Continue waiting
+ }
+
+ return false;
+}
+
+
+}}} // namespace OVR::Service::Win32
diff --git a/LibOVR/Src/Service/Service_Win32_FastIPC_Client.h b/LibOVR/Src/Service/Service_Win32_FastIPC_Client.h
new file mode 100644
index 0000000..984da06
--- /dev/null
+++ b/LibOVR/Src/Service/Service_Win32_FastIPC_Client.h
@@ -0,0 +1,84 @@
+/************************************************************************************
+
+Filename : OVR_Service_Win32_FastIPC_Client.h
+Content : Client side of connectionless fast IPC
+Created : Sept 16, 2014
+Authors : Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.2
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#ifndef OVR_Service_Win32_FastIPC_Client_h
+#define OVR_Service_Win32_FastIPC_Client_h
+
+#include "Kernel/OVR_SharedMemory.h"
+#include "Net/OVR_RPC1.h"
+#include "Kernel/OVR_Win32_IncludeWindows.h"
+
+namespace OVR { namespace Service { namespace Win32 {
+
+
+//-----------------------------------------------------------------------------
+// FastIPCClient
+//
+// This class implements the client side for connectionless IPC messaging.
+//
+// The client reads the shared memory name provided and retrieves the data
+// and return event handles. It can push data to the server synchronously
+// by signaling the data handle and waiting on the return handle.
+
+class FastIPCClient
+{
+ String SharedMemoryName;
+ Ptr<SharedMemory> Scratch;
+ ScopedEventHANDLE DataEvent, ReturnEvent;
+ uint32_t IPCMessageIndex;
+
+protected:
+ bool ReadInitialData(const char* buffer);
+
+public:
+ static const int RegionSize = 4096;
+ static const uint32_t Magic = 0xfe67bead;
+
+ // Semantic versioning
+ static const uint32_t MajorVersion = 1;
+ static const uint32_t MinorVersion = 0;
+
+public:
+ FastIPCClient();
+ ~FastIPCClient();
+
+ String GetSharedMemoryName() const
+ {
+ return SharedMemoryName;
+ }
+
+ // Call this to initialize the shared memory section
+ bool Initialize(const char* sharedMemoryName);
+
+ // Make a blocking call to the server
+ // Pass -1 for the timeout to wait forever
+ bool Call(Net::BitStream* bread, Net::BitStream* toast, int timeoutMs = -1);
+};
+
+
+}}} // namespace OVR::Service::Win32
+
+#endif // OVR_Service_Win32_FastIPC_Client_h