summaryrefslogtreecommitdiff
path: root/test/client-server
diff options
context:
space:
mode:
authorJason Maskell <[email protected]>2016-05-09 10:39:54 +0200
committerJason Maskell <[email protected]>2016-05-09 10:39:54 +0200
commit79b3462799c28af8ba586349bd671b1b56e72353 (patch)
tree3b06e36c390254c0dc7f3733a0d32af213d87293 /test/client-server
downloadarchived-waveworks-archive-79b3462799c28af8ba586349bd671b1b56e72353.tar.xz
archived-waveworks-archive-79b3462799c28af8ba586349bd671b1b56e72353.zip
Initial commit with PS4 and XBone stuff trimmed.
Diffstat (limited to 'test/client-server')
-rw-r--r--test/client-server/client.cpp445
-rw-r--r--test/client-server/client.h68
-rw-r--r--test/client-server/message_types.h77
-rw-r--r--test/client-server/socket_wrapper.cpp271
-rw-r--r--test/client-server/socket_wrapper.h106
5 files changed, 967 insertions, 0 deletions
diff --git a/test/client-server/client.cpp b/test/client-server/client.cpp
new file mode 100644
index 0000000..d5161ff
--- /dev/null
+++ b/test/client-server/client.cpp
@@ -0,0 +1,445 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#define _HAS_EXCEPTIONS 0
+
+#include "client.h"
+
+#include "socket_wrapper.h"
+#include "message_types.h"
+
+#include <winsock.h>
+
+#include <D3dx9.h>
+
+#include <vector>
+#include <assert.h>
+
+namespace
+{
+ int ConnectServerSocket(SOCKET socket)
+ {
+ std::string commandLineRemoteHostName;
+ LPCSTR remoteHostName = "localhost"; // default
+
+ // Parse the command-line and look for host address
+ int nNumArgs;
+ LPWSTR* pstrArgList = CommandLineToArgvW( GetCommandLineW(), &nNumArgs );
+ for( int iArg = 1; iArg < nNumArgs; iArg++ )
+ {
+ LPWSTR arg = pstrArgList[iArg];
+ if( *arg == L'/' || *arg == L'-' )
+ {
+ ++arg;
+ LPCWSTR hostAddrKeyword = L"hostaddr:";
+ if(NULL != wcsstr(arg,hostAddrKeyword)) {
+
+ LPCWSTR hostAddrValue = arg + wcslen(hostAddrKeyword);
+
+ // Convert the host address
+ size_t char_count;
+ if(0 == wcstombs_s(&char_count,NULL,0,hostAddrValue,0)) {
+ commandLineRemoteHostName.resize(char_count);
+ wcstombs_s(&char_count,&commandLineRemoteHostName[0],char_count+1,hostAddrValue,char_count);
+ remoteHostName = commandLineRemoteHostName.c_str();
+ }
+
+ }
+ }
+ }
+ LocalFree( pstrArgList );
+
+ // Host lookup
+ hostent* host = gethostbyname(remoteHostName);
+ if(0 == host) {
+ printf("ERROR: Failed to lookup host %s\n",remoteHostName);
+ return -1;
+ }
+
+ if(host->h_addrtype != AF_INET) {
+ printf("ERROR: host %s is not IPv4\n",remoteHostName);
+ return -1;
+ }
+
+ if(host->h_length != sizeof(in_addr)) {
+ printf("ERROR: host address for %s is not a sockaddr_in\n",remoteHostName);
+ return -1;
+ }
+
+ if(NULL == host->h_addr_list) {
+ printf("ERROR: host address for %s is empty\n",remoteHostName);
+ return -1;
+ }
+
+ in_addr* pAddr = (in_addr*)*(host->h_addr_list);
+ if(NULL == pAddr) {
+ printf("ERROR: host address for %s is NULL\n",remoteHostName);
+ return -1;
+ }
+
+ // Connect to host
+ sockaddr_in sock_addr;
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_port = htons(ServerPort);
+ sock_addr.sin_addr = *pAddr;
+
+ if(connect(socket,(sockaddr*)&sock_addr,sizeof(sock_addr))) {
+ printf("ERROR: failed to connect to host %s\n",remoteHostName);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ void CleanupServerSocket(SOCKET socket)
+ {
+ if(socket != INVALID_SOCKET) {
+ closesocket(socket);
+ WSACleanup();
+ }
+ }
+
+ const int kNumRemoteMarkerRequestsInFlight = 3; // Don't flood the client-server pipe
+}
+
+struct ClientImpl
+{
+ ClientImpl(SOCKET_TYPE platformSocket) :
+ m_socket(platformSocket),
+ m_sockwrap(platformSocket),
+ m_LastWallclockTime(0),
+ m_QPFTicksPerSec(0),
+ m_simulationTime(0.0),
+ m_pMarkerPositions(NULL),
+ m_numMarkerPositions(0),
+ m_numRemoteMarkerRequestsInFlight(0)
+ {
+ InitWallclockTimer();
+ }
+
+ ~ClientImpl()
+ {
+ CleanupServerSocket(m_socket);
+ if(m_pMarkerPositions) {
+ delete [] m_pMarkerPositions;
+ }
+ }
+
+ // Member functions
+ void InitWallclockTimer();
+ float GetElapsedWallclockTime();
+
+ int DoOneTimeSyncToServer();
+
+ void UpdateRemoteMarkerPositions(const gfsdk_float4* pPositions, int num_markers);
+
+ // Member variables
+ SOCKET_TYPE m_socket;
+ SocketWrapper m_sockwrap;
+ std::vector<int> m_recvMessages;
+
+ LONGLONG m_LastWallclockTime;
+ LONGLONG m_QPFTicksPerSec;
+
+ double m_simulationTime;
+
+ SimulationConfig simulationConfig;
+
+ gfsdk_float4* m_pMarkerPositions;
+ int m_numMarkerPositions;
+ int m_numRemoteMarkerRequestsInFlight;
+};
+
+void ClientImpl::InitWallclockTimer()
+{
+ // Record tick frequency
+ LARGE_INTEGER qwTicksPerSec;
+ QueryPerformanceFrequency( &qwTicksPerSec );
+ m_QPFTicksPerSec = qwTicksPerSec.QuadPart;
+
+ // Record last-time, so that we are zero-based
+ LARGE_INTEGER qwTime;
+ QueryPerformanceCounter( &qwTime );
+ m_LastWallclockTime = qwTime.QuadPart;
+}
+
+float ClientImpl::GetElapsedWallclockTime()
+{
+ LARGE_INTEGER qwTime;
+ QueryPerformanceCounter( &qwTime );
+
+ const float result = ( qwTime.QuadPart - m_LastWallclockTime ) / (float) m_QPFTicksPerSec;
+ m_LastWallclockTime = qwTime.QuadPart;
+
+ return result;
+}
+
+int ClientImpl::DoOneTimeSyncToServer()
+{
+ // Sync to 0 by default, in case we early-out for some reason
+ m_simulationTime = 0.0;
+
+ if(!m_sockwrap.is_usable()) {
+ return -1;
+ }
+
+ // Use Christian's algorithm to initialise time
+ int msg = MessageTypeID_ClientRequestTimeFromServer;
+ m_sockwrap.enqueue_send_message(&msg, sizeof(msg));
+
+ // Zero the 'last time', so that the next call will give us the time delta
+ GetElapsedWallclockTime();
+
+ // Hey look, this is a busy wait - intentional, we want to measure the intrinsic latency on the round trip,
+ // any extrinsic latency is therefore undesirable
+ while(!m_sockwrap.has_recv_message() && m_sockwrap.is_usable()) {
+ m_sockwrap.pump();
+ }
+
+ if(m_sockwrap.has_recv_message())
+ {
+ const float round_trip_time = GetElapsedWallclockTime(); // Note that the next elapsed will be delta'd
+ // relative to this moment, when we did the sync
+ // which is as it should be
+
+ void* raw_msg = m_sockwrap.recv_message();
+ int* pMsgType = (int*)raw_msg;
+ switch(*pMsgType)
+ {
+ case MessageTypeID_ServerSendTimeToClient:
+ {
+ Message<double>* pMsg = (Message<double>*)raw_msg;
+ m_simulationTime = pMsg->payload + 0.5 * round_trip_time; // Christian's algo1
+ m_sockwrap.consume_recv_message();
+ }
+ break;
+ }
+ }
+
+ // Next, request simulation config
+ if(m_sockwrap.is_usable())
+ {
+ msg = MessageTypeID_ClientRequestConfigFromServer;
+ m_sockwrap.enqueue_send_message(&msg, sizeof(msg));
+
+ // A less busy wait
+ m_sockwrap.pump();
+ while(!m_sockwrap.has_recv_message() && m_sockwrap.is_usable()) {
+ Sleep(1);
+ m_sockwrap.pump();
+ }
+
+ if(m_sockwrap.has_recv_message())
+ {
+ void* raw_msg = m_sockwrap.recv_message();
+ int* pMsgType = (int*)raw_msg;
+ switch(*pMsgType)
+ {
+ case MessageTypeID_ServerSendConfigToClient:
+ {
+ // We got config, apply it
+ Message<SimulationConfig>* pMsg = (Message<SimulationConfig>*)raw_msg;
+ simulationConfig = pMsg->payload;
+ m_sockwrap.consume_recv_message();
+ }
+ break;
+ }
+ }
+ }
+
+ return m_sockwrap.is_usable() ? 0 : -1;
+}
+
+void ClientImpl::UpdateRemoteMarkerPositions(const gfsdk_float4* pPositions, int num_markers)
+{
+ // Update markers allocation if necessary
+ if(num_markers > m_numMarkerPositions) {
+ delete [] m_pMarkerPositions;
+ m_pMarkerPositions = new gfsdk_float4[num_markers];
+ }
+ m_numMarkerPositions = num_markers;
+
+ for(int markerIx = 0; markerIx != num_markers; ++markerIx) {
+ m_pMarkerPositions[markerIx] = pPositions[markerIx];
+ }
+ --m_numRemoteMarkerRequestsInFlight;
+}
+
+Client* Client::Create()
+{
+ // Start networking
+ WSADATA wsData;
+ if(WSAStartup(0x202,&wsData)) {
+ printf("ERROR: WSAStartup failed\n");
+ return NULL;
+ }
+
+ // Init server socket
+ SOCKET serverSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
+ if(INVALID_SOCKET == serverSocket) {
+ printf("ERROR: Failed to create server socket\n");
+ WSACleanup();
+ return NULL;
+ }
+
+ if(ConnectServerSocket(serverSocket)) {
+ CleanupServerSocket(serverSocket);
+ return NULL;
+ }
+
+ // We have a connected socket, sync it
+ ClientImpl* pImpl = new ClientImpl(serverSocket);
+ if(pImpl->DoOneTimeSyncToServer()) {
+ delete pImpl;
+ return NULL;
+ }
+
+ // All done, return wrapper
+ Client* pResult = new Client();
+ pResult->pImpl = pImpl;
+ return pResult;
+}
+
+Client::~Client()
+{
+ delete pImpl;
+}
+
+void Client::Destroy(Client* pClient)
+{
+ if(pClient) {
+ delete pClient;
+ }
+}
+
+bool Client::IsUsable() const
+{
+ return pImpl->m_sockwrap.is_usable();
+}
+
+void Client::Tick()
+{
+ pImpl->m_simulationTime += pImpl->GetElapsedWallclockTime();
+
+ while(SocketWrapper::PumpResult_Traffic == pImpl->m_sockwrap.pump())
+ {
+ while(pImpl->m_sockwrap.has_recv_message())
+ {
+ void* raw_msg = pImpl->m_sockwrap.recv_message();
+ int* pMsgType = (int*)raw_msg;
+ int msgType = *pMsgType;
+ switch(msgType)
+ {
+ case MessageTypeID_ServerSendConfigToClient:
+ {
+ Message<SimulationConfig>* pMsg = (Message<SimulationConfig>*)raw_msg;
+ pImpl->simulationConfig = pMsg->payload;
+ }
+ break;
+ case MessageTypeID_ServerSendMarkersToClient:
+ {
+ // Markers incoming, update them
+ struct Payload
+ {
+ int num_markers;
+ int pad1;
+ int pad2;
+ int pad3;
+ gfsdk_float4 marker_positions;
+ };
+
+ Message<Payload>* pMsg = (Message<Payload>*)raw_msg;
+ pImpl->UpdateRemoteMarkerPositions(&pMsg->payload.marker_positions,pMsg->payload.num_markers);
+ }
+ break;
+ }
+
+ pImpl->m_sockwrap.consume_recv_message();
+
+ pImpl->m_recvMessages.push_back(msgType);
+ }
+ }
+}
+
+bool Client::HasPendingMessage() const
+{
+ return !pImpl->m_recvMessages.empty();
+}
+
+int Client::ConsumePendingMessage()
+{
+ const int result = pImpl->m_recvMessages.front();
+ pImpl->m_recvMessages.erase(pImpl->m_recvMessages.begin());
+ return result;
+}
+
+const SimulationConfig& Client::GetSimulationConfig() const
+{
+ return pImpl->simulationConfig;
+}
+
+double Client::GetSimulationTime() const
+{
+ return pImpl->m_simulationTime;
+}
+
+bool Client::GetRemoteMarkerPositions(const gfsdk_float4*& pPositions, size_t& numMarkers) const
+{
+ if(NULL == pImpl->m_pMarkerPositions) {
+ return false;
+ }
+
+ pPositions = pImpl->m_pMarkerPositions;
+ numMarkers = pImpl->m_numMarkerPositions;
+
+ return true;
+}
+
+void Client::RequestRemoteMarkerPositions(const gfsdk_float2* pMarkerCoords, size_t numMarkers)
+{
+ if(pImpl->m_sockwrap.is_usable() && pImpl->m_numRemoteMarkerRequestsInFlight < kNumRemoteMarkerRequestsInFlight)
+ {
+ // Send a request for marker positions
+ struct Request
+ {
+ int num_markers;
+ int pad;
+ gfsdk_float2 marker_coords;
+ };
+
+ const size_t msg_alloc = sizeof(Message<Request>) + numMarkers * sizeof(gfsdk_float2);
+ Message<Request>* pMessage = (Message<Request>*)malloc(msg_alloc);
+ pMessage->messageTypeID = MessageTypeID_ClientRequestMarkersFromServer;
+ pMessage->payload.num_markers = (int)numMarkers;
+ memcpy(&pMessage->payload.marker_coords, pMarkerCoords, numMarkers * sizeof(pMessage->payload.marker_coords));
+
+ pImpl->m_sockwrap.enqueue_send_message(pMessage, (unsigned int)msg_alloc);
+ ++pImpl->m_numRemoteMarkerRequestsInFlight;
+ free(pMessage);
+ }
+} \ No newline at end of file
diff --git a/test/client-server/client.h b/test/client-server/client.h
new file mode 100644
index 0000000..0daaf2c
--- /dev/null
+++ b/test/client-server/client.h
@@ -0,0 +1,68 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+#include "GFSDK_WaveWorks.h"
+
+struct ClientImpl;
+struct SimulationConfig;
+
+/*********************************************************************************
+ Re-usable class that takes care of client-side of duties in client-server test apps
+*********************************************************************************/
+class Client
+{
+public:
+
+ static Client* Create();
+ static void Destroy(Client* pClient);
+
+ bool IsUsable() const;
+
+ void Tick();
+
+ bool HasPendingMessage() const;
+ int ConsumePendingMessage();
+
+ const SimulationConfig& GetSimulationConfig() const;
+
+ double GetSimulationTime() const;
+
+ bool GetRemoteMarkerPositions(const gfsdk_float4*& pPositions, size_t& numMarkers) const;
+
+ void RequestRemoteMarkerPositions(const gfsdk_float2* pMarkerCoords, size_t numMarkers);
+
+private:
+
+ ~Client();
+ ClientImpl* pImpl;
+};
+
+#endif // _MESSAGETYPES_H
diff --git a/test/client-server/message_types.h b/test/client-server/message_types.h
new file mode 100644
index 0000000..e412ece
--- /dev/null
+++ b/test/client-server/message_types.h
@@ -0,0 +1,77 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#ifndef _MESSAGETYPES_H
+#define _MESSAGETYPES_H
+
+// Message types for client-server test framework in WaveWorks
+enum MessageTypeID {
+ MessageTypeID_ClientRequestMarkersFromServer = 0,
+ MessageTypeID_ServerSendMarkersToClient,
+ MessageTypeID_ClientRequestTimeFromServer,
+ MessageTypeID_ServerSendTimeToClient,
+ MessageTypeID_ClientRequestConfigFromServer,
+ MessageTypeID_ServerSendConfigToClient
+};
+
+enum {
+ ServerPort = 1982
+};
+
+template<class PayloadType>
+struct Message
+{
+ int messageTypeID;
+ int pad1; // In case the payload is 128b aligned
+ int pad2;
+ int pad3;
+ PayloadType payload;
+};
+
+struct SimulationConfig
+{
+ // Assumes use_Beaufort_scale = true
+ float wind_dir_x;
+ float wind_dir_y;
+ float wind_speed;
+ float wind_dependency;
+ float time_scale;
+ float small_wave_fraction;
+};
+
+inline void UpdateWaveWorksParams(GFSDK_WaveWorks_Simulation_Params& dst, const SimulationConfig& src)
+{
+ dst.wind_speed = src.wind_speed;
+ dst.wind_dependency = src.wind_dependency;
+ dst.time_scale = src.time_scale;
+ dst.small_wave_fraction = src.small_wave_fraction;
+ dst.wind_dir.x = src.wind_dir_x;
+ dst.wind_dir.y = src.wind_dir_y;
+}
+
+#endif // _MESSAGETYPES_H
diff --git a/test/client-server/socket_wrapper.cpp b/test/client-server/socket_wrapper.cpp
new file mode 100644
index 0000000..ab759ba
--- /dev/null
+++ b/test/client-server/socket_wrapper.cpp
@@ -0,0 +1,271 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#include "socket_wrapper.h"
+#include <stdio.h>
+
+
+////////////////////////////////////////////////////////////////////////////////
+#if defined(__linux__) || defined(__ORBIS__)
+////////////////////////////////////////////////////////////////////////////////
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+
+#include <errno.h>
+
+bool wouldblock()
+{
+ return EWOULDBLOCK == errno || EAGAIN == errno;
+}
+
+int init_networking() { return 0; }
+int term_networking() { return 0; }
+
+#define SOCKET_ERROR (-1)
+
+////////////////////////////////////////////////////////////////////////////////
+#endif // __linux__ || __ORBIS__
+////////////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////////////
+#if defined(__linux__)
+////////////////////////////////////////////////////////////////////////////////
+
+#include <netdb.h>
+
+int set_non_blocking(SOCKET_TYPE s)
+{
+ int flags = fcntl(s, F_GETFL, 0);
+ return fcntl(s, F_SETFL, flags | O_NONBLOCK);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+#elif defined(__ORBIS__)
+////////////////////////////////////////////////////////////////////////////////
+
+#include <libnetctl.h>
+#include <string.h>
+
+int set_non_blocking(SOCKET_TYPE s)
+{
+ const int nonzero = -1;
+ return setsockopt(s,SCE_NET_SOL_SOCKET,SCE_NET_SO_NBIO,&nonzero,sizeof(nonzero));
+}
+
+int gethostname(char* buff, int buffsize)
+{
+ SceNetCtlInfo ci;
+ if(sceNetCtlGetInfo(SCE_NET_CTL_INFO_DHCP_HOSTNAME,&ci))
+ {
+ return -1;
+ }
+
+ if(strlen(ci.dhcp_hostname) >= buffsize)
+ {
+ return -1;
+ }
+
+ if(0 == ci.dhcp_hostname[0])
+ {
+ // Effectively no name
+ return -1;
+ }
+
+ strcpy(buff,ci.dhcp_hostname);
+
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+#else // !__linux__ && !__ORBIS__
+////////////////////////////////////////////////////////////////////////////////
+
+#include <winsock2.h>
+
+int set_non_blocking(SOCKET_TYPE s)
+{
+ u_long iMode=1;
+ return ioctlsocket(s,FIONBIO,&iMode);
+}
+
+bool wouldblock()
+{
+ const int lse = WSAGetLastError();
+ return WSAEWOULDBLOCK == lse;
+}
+
+int init_networking()
+{
+ // Start networking
+ WSADATA wsData;
+ if(WSAStartup(0x202,&wsData)) {
+ fprintf(stderr,"ERROR: WSAStartup failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int term_networking()
+{
+ WSACleanup();
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
+////////////////////////////////////////////////////////////////////////////////
+
+
+#define _HAS_EXCEPTIONS 0
+#include <vector>
+#include <assert.h>
+
+struct SocketWrapperImpl
+{
+ SOCKET_TYPE socket;
+ std::vector<char> recvMessageBytes;
+ std::vector<char> sendMessageBytes;
+
+ bool hasError;
+ bool isConnected;
+};
+
+SocketWrapper::SocketWrapper(SOCKET_TYPE platformSocket) :
+ pImpl(new SocketWrapperImpl)
+{
+ pImpl->socket = platformSocket;
+ pImpl->hasError = false;
+
+ // Assume connected and error-free until we know otherwise
+ pImpl->isConnected = true;
+
+ // Set the socket to non-blocking mode
+ if(set_non_blocking(pImpl->socket)) {
+ fprintf(stderr,"ERROR: Failed to set socket to non-blocking\n");
+ pImpl->hasError = true;
+ }
+}
+
+SocketWrapper::~SocketWrapper()
+{
+ delete pImpl;
+}
+
+void SocketWrapper::enqueue_send_message(void* msgData, unsigned int msgLength)
+{
+ // We add in bytes for the message length, which makes the message longer...
+ unsigned int modifiedMsgLength = sizeof(msgLength) + msgLength;
+
+ pImpl->sendMessageBytes.insert(pImpl->sendMessageBytes.end(),(char*)&modifiedMsgLength,((char*)&modifiedMsgLength)+sizeof(modifiedMsgLength));
+ pImpl->sendMessageBytes.insert(pImpl->sendMessageBytes.end(),(char*)msgData,((char*)msgData)+msgLength);
+}
+
+bool SocketWrapper::is_usable() const
+{
+ return pImpl->isConnected && !pImpl->hasError;
+}
+
+bool SocketWrapper::has_recv_message() const
+{
+ if(pImpl->recvMessageBytes.size() > sizeof(unsigned int)) {
+ unsigned int* pMessageLength = (unsigned int*)&pImpl->recvMessageBytes[0];
+ if(pImpl->recvMessageBytes.size() >= *pMessageLength) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+unsigned int SocketWrapper::recv_message_length() const
+{
+ assert(has_recv_message());
+
+ unsigned int* pMessageLength = (unsigned int*)&pImpl->recvMessageBytes[0];
+ return *pMessageLength;
+}
+
+void* SocketWrapper::recv_message() const
+{
+ assert(has_recv_message());
+ return &pImpl->recvMessageBytes[sizeof(unsigned int)];
+}
+
+void SocketWrapper::consume_recv_message()
+{
+ assert(has_recv_message());
+
+ unsigned int* pMessageLength = (unsigned int*)&pImpl->recvMessageBytes[0];
+ pImpl->recvMessageBytes.erase(pImpl->recvMessageBytes.begin(),pImpl->recvMessageBytes.begin()+*pMessageLength);
+}
+
+SocketWrapper::PumpResult SocketWrapper::pump()
+{
+ PumpResult result = pImpl->recvMessageBytes.empty() ? PumpResult_NoTraffic : PumpResult_Traffic;
+
+ // Always check recv
+ char recvbuffer[256];
+ int recvresult = recv(pImpl->socket, recvbuffer, sizeof(recvbuffer), 0);
+ if(SOCKET_ERROR == recvresult) {
+ if(!wouldblock()) {
+ fprintf(stderr,"ERROR: Failed to recv client socket\n");
+ pImpl->hasError = true;
+ result = PumpResult_Error;
+ }
+ } else if(0 == recvresult) {
+ pImpl->isConnected = false;
+ } else {
+ result = PumpResult_Traffic;
+ pImpl->recvMessageBytes.insert(pImpl->recvMessageBytes.end(), recvbuffer, recvbuffer + recvresult);
+ }
+
+ // Only need to pump send when there is stuff to send
+ if(!pImpl->sendMessageBytes.empty()) {
+ result = PumpResult_Traffic; // Just attempting to send qualifies as traffic
+ int sendresult = send(pImpl->socket,(char*)&pImpl->sendMessageBytes[0],(int)pImpl->sendMessageBytes.size(),0);
+ if(SOCKET_ERROR == sendresult) {
+ if(!wouldblock()) {
+ fprintf(stderr,"ERROR: Failed to send on client socket\n");
+ pImpl->hasError = true;
+ result = PumpResult_Error;
+ }
+ } else {
+ pImpl->sendMessageBytes.erase(pImpl->sendMessageBytes.begin(),pImpl->sendMessageBytes.begin()+sendresult);
+ }
+ }
+
+ return result;
+}
diff --git a/test/client-server/socket_wrapper.h b/test/client-server/socket_wrapper.h
new file mode 100644
index 0000000..a18e679
--- /dev/null
+++ b/test/client-server/socket_wrapper.h
@@ -0,0 +1,106 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#ifndef _SOCKET_WRAPPER_H
+#define _SOCKET_WRAPPER_H
+
+struct SocketWrapperImpl;
+
+#if defined(__linux__ ) || defined(__ORBIS__)
+typedef int SOCKET_TYPE;
+#else
+typedef int socklen_t;
+#if defined(_WIN64)
+ typedef unsigned __int64 SOCKET_TYPE;
+#else
+ typedef unsigned int SOCKET_TYPE;
+#endif
+#endif
+
+int init_networking();
+int term_networking();
+int set_non_blocking(SOCKET_TYPE s);
+bool wouldblock();
+
+/*********************************************************************************
+ Super-simple wrapper class for doing send/receive on non-blocking sockets
+*********************************************************************************/
+class SocketWrapper
+{
+public:
+
+ SocketWrapper(SOCKET_TYPE platformSocket);
+ ~SocketWrapper();
+
+ bool is_usable() const;
+
+ void enqueue_send_message(void* msgData, unsigned int msgLength);
+
+ bool has_recv_message() const;
+ unsigned int recv_message_length() const;
+ void* recv_message() const;
+ void consume_recv_message();
+
+ enum PumpResult
+ {
+ PumpResult_NoTraffic = 0, // The internal send/recv queues are both empty, and there was no new traffic on this pump
+ PumpResult_Traffic,
+ PumpResult_Error
+ };
+
+ PumpResult pump();
+
+private:
+
+ SocketWrapperImpl* pImpl;
+};
+
+/*********************************************************************************
+ Misc x-plat helpers...
+*********************************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////
+#if defined(__linux__) || defined(__ORBIS__)
+////////////////////////////////////////////////////////////////////////////////
+#define closesocket close
+#define INVALID_SOCKET (-1)
+////////////////////////////////////////////////////////////////////////////////
+#endif
+////////////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////////////
+#if defined(__ORBIS__)
+////////////////////////////////////////////////////////////////////////////////
+int gethostname(char* buff, int buffsize);
+#define SOMAXCONN 128
+////////////////////////////////////////////////////////////////////////////////
+#endif
+////////////////////////////////////////////////////////////////////////////////
+
+#endif // _MESSAGETYPES_H