diff options
| author | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
|---|---|---|
| committer | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
| commit | 79b3462799c28af8ba586349bd671b1b56e72353 (patch) | |
| tree | 3b06e36c390254c0dc7f3733a0d32af213d87293 /test/client-server | |
| download | archived-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.cpp | 445 | ||||
| -rw-r--r-- | test/client-server/client.h | 68 | ||||
| -rw-r--r-- | test/client-server/message_types.h | 77 | ||||
| -rw-r--r-- | test/client-server/socket_wrapper.cpp | 271 | ||||
| -rw-r--r-- | test/client-server/socket_wrapper.h | 106 |
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 |