454 lines
12 KiB
C++
454 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2014, Oculus VR, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
|
|
#ifndef __RAKNET_SOCKET_2_H
|
|
#define __RAKNET_SOCKET_2_H
|
|
|
|
#include "RakNetTypes.hpp"
|
|
#include "MTUSize.hpp"
|
|
#include "LocklessTypes.hpp"
|
|
#include "RakThread.hpp"
|
|
#include "DS_ThreadsafeAllocatingQueue.hpp"
|
|
#include "Export.hpp"
|
|
|
|
// For CFSocket
|
|
// https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFSocketRef/Reference/reference.html
|
|
// Reason: http://sourceforge.net/p/open-dis/discussion/683284/thread/0929d6a0
|
|
#if defined(__APPLE__)
|
|
#import <CoreFoundation/CoreFoundation.hpp>
|
|
#include <sys/socket.hpp>
|
|
#include <netinet/in.hpp>
|
|
#endif
|
|
|
|
// #define TEST_NATIVE_CLIENT_ON_WINDOWS
|
|
|
|
#ifdef TEST_NATIVE_CLIENT_ON_WINDOWS
|
|
#define __native_client__
|
|
typedef int PP_Resource;
|
|
#endif
|
|
|
|
namespace RakNet
|
|
{
|
|
|
|
class RakNetSocket2;
|
|
struct RNS2_BerkleyBindParameters;
|
|
struct RNS2_SendParameters;
|
|
typedef int RNS2Socket;
|
|
|
|
enum RNS2BindResult
|
|
{
|
|
BR_SUCCESS,
|
|
BR_REQUIRES_RAKNET_SUPPORT_IPV6_DEFINE,
|
|
BR_FAILED_TO_BIND_SOCKET,
|
|
BR_FAILED_SEND_TEST,
|
|
};
|
|
|
|
typedef int RNS2SendResult;
|
|
|
|
enum RNS2Type
|
|
{
|
|
RNS2T_WINDOWS_STORE_8,
|
|
RNS2T_PS3,
|
|
RNS2T_PS4,
|
|
RNS2T_CHROME,
|
|
RNS2T_VITA,
|
|
RNS2T_XBOX_360,
|
|
RNS2T_XBOX_720,
|
|
RNS2T_WINDOWS,
|
|
RNS2T_LINUX
|
|
};
|
|
|
|
struct RNS2_SendParameters
|
|
{
|
|
RNS2_SendParameters() {ttl=0;}
|
|
char *data;
|
|
int length;
|
|
SystemAddress systemAddress;
|
|
int ttl;
|
|
};
|
|
|
|
struct RNS2RecvStruct
|
|
{
|
|
|
|
|
|
|
|
char data[MAXIMUM_MTU_SIZE];
|
|
|
|
int bytesRead;
|
|
SystemAddress systemAddress;
|
|
RakNet::TimeUS timeRead;
|
|
RakNetSocket2 *socket;
|
|
};
|
|
|
|
class RakNetSocket2Allocator
|
|
{
|
|
public:
|
|
static RakNetSocket2* AllocRNS2(void);
|
|
static void DeallocRNS2(RakNetSocket2 *s);
|
|
};
|
|
|
|
class RAK_DLL_EXPORT RNS2EventHandler
|
|
{
|
|
public:
|
|
RNS2EventHandler() {}
|
|
virtual ~RNS2EventHandler() {}
|
|
|
|
// bufferedPackets.Push(recvFromStruct);
|
|
// quitAndDataEvents.SetEvent();
|
|
virtual void OnRNS2Recv(RNS2RecvStruct *recvStruct)=0;
|
|
virtual void DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line)=0;
|
|
virtual RNS2RecvStruct *AllocRNS2RecvStruct(const char *file, unsigned int line)=0;
|
|
|
|
// recvFromStruct=bufferedPackets.Allocate( _FILE_AND_LINE_ );
|
|
// DataStructures::ThreadsafeAllocatingQueue<RNS2RecvStruct> bufferedPackets;
|
|
};
|
|
|
|
class RakNetSocket2
|
|
{
|
|
public:
|
|
RakNetSocket2();
|
|
virtual ~RakNetSocket2();
|
|
|
|
// In order for the handler to trigger, some platforms must call PollRecvFrom, some platforms this create an internal thread.
|
|
void SetRecvEventHandler(RNS2EventHandler *_eventHandler);
|
|
virtual RNS2SendResult Send( RNS2_SendParameters *sendParameters, const char *file, unsigned int line )=0;
|
|
RNS2Type GetSocketType(void) const;
|
|
void SetSocketType(RNS2Type t);
|
|
bool IsBerkleySocket(void) const;
|
|
SystemAddress GetBoundAddress(void) const;
|
|
unsigned int GetUserConnectionSocketIndex(void) const;
|
|
void SetUserConnectionSocketIndex(unsigned int i);
|
|
RNS2EventHandler * GetEventHandler(void) const;
|
|
|
|
// ----------- STATICS ------------
|
|
static void GetMyIP( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
static void DomainNameToIP( const char *domainName, char ip[65] );
|
|
|
|
protected:
|
|
RNS2EventHandler *eventHandler;
|
|
RNS2Type socketType;
|
|
SystemAddress boundAddress;
|
|
unsigned int userConnectionSocketIndex;
|
|
};
|
|
|
|
#if defined(WINDOWS_STORE_RT)
|
|
|
|
ref class ListenerContext;
|
|
|
|
// #include <collection.hpp>
|
|
//#include <map>
|
|
#include "DS_List.hpp"
|
|
class RNS2_WindowsStore8 : public RakNetSocket2
|
|
{
|
|
public:
|
|
RNS2_WindowsStore8();
|
|
~RNS2_WindowsStore8();
|
|
|
|
virtual RNS2SendResult Send( RNS2_SendParameters *sendParameters, const char *file, unsigned int line );
|
|
RNS2BindResult Bind( Platform::String ^localServiceName );
|
|
// ----------- STATICS ------------
|
|
static void GetMyIP( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
static void DomainNameToIP( const char *domainName, char ip[65] );
|
|
|
|
static int WinRTInet_Addr(const char * cp);
|
|
|
|
static int WinRTSetSockOpt(Windows::Networking::Sockets::DatagramSocket ^s,
|
|
int level,
|
|
int optname,
|
|
const char * optval,
|
|
socklen_t optlen);
|
|
|
|
static int WinRTIOCTLSocket(Windows::Networking::Sockets::DatagramSocket ^s,
|
|
long cmd,
|
|
unsigned long *argp);
|
|
|
|
static int WinRTGetSockName(Windows::Networking::Sockets::DatagramSocket ^s,
|
|
struct sockaddr *name,
|
|
socklen_t* namelen);
|
|
|
|
static RNS2_WindowsStore8 *GetRNS2FromDatagramSocket(Windows::Networking::Sockets::DatagramSocket^ s);
|
|
protected:
|
|
static DataStructures::List<RNS2_WindowsStore8*> rns2List;
|
|
static SimpleMutex rns2ListMutex;
|
|
|
|
Windows::Networking::Sockets::DatagramSocket^ listener;
|
|
// Platform::Collections::Map<Windows::Storage::Streams::IOutputStream> ^outputStreamMap;
|
|
// Platform::Collections::Map<String^, int>^ m;
|
|
//std::map<> m;
|
|
ListenerContext^ listenerContext;
|
|
};
|
|
#elif defined(__native_client__)
|
|
struct NativeClientBindParameters
|
|
{
|
|
_PP_Instance_ nativeClientInstance;
|
|
unsigned short port;
|
|
const char *forceHostAddress;
|
|
bool is_ipv6;
|
|
RNS2EventHandler *eventHandler;
|
|
};
|
|
class RNS2_NativeClient;
|
|
struct RNS2_SendParameters_NativeClient : public RNS2_SendParameters
|
|
{
|
|
RNS2_NativeClient *socket2;
|
|
};
|
|
class RNS2_NativeClient : public RakNetSocket2
|
|
{
|
|
public:
|
|
RNS2_NativeClient();
|
|
virtual ~RNS2_NativeClient();
|
|
RNS2BindResult Bind( NativeClientBindParameters *bindParameters, const char *file, unsigned int line );
|
|
RNS2SendResult Send( RNS2_SendParameters *sendParameters, const char *file, unsigned int line );
|
|
const NativeClientBindParameters *GetBindings(void) const;
|
|
|
|
// ----------- STATICS ------------
|
|
static bool IsPortInUse(unsigned short port, const char *hostAddress, unsigned short addressFamily, int type );
|
|
static void GetMyIP( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
|
|
// RNS2_NativeClient doesn't automatically call recvfrom in a thread - user must call Update() from the main thread
|
|
// This causes buffered sends to send, until send is asynch pending
|
|
// It causes recvfrom events to trigger the callback, and push a message to the event handler
|
|
//
|
|
// Example:
|
|
//
|
|
// DataStructures::List< RakNet::RakNetSocket2* > sockets;
|
|
// rakPeerInterface->GetSockets(sockets);
|
|
// for (unsigned int i=0; i < sockets.Size(); i++)
|
|
// {
|
|
// ((RNS2_NativeClient*)sockets[i])->Update();
|
|
// }
|
|
|
|
void Update(void);
|
|
protected:
|
|
void ProcessBufferedSend(void);
|
|
static void SendImmediate(RNS2_SendParameters_NativeClient *sp);
|
|
static void DeallocSP(RNS2_SendParameters_NativeClient *sp);
|
|
static RNS2_SendParameters_NativeClient* CloneSP(RNS2_SendParameters *sp, RNS2_NativeClient *socket2, const char *file, unsigned int line);
|
|
static void onRecvFrom(void* pData, int32_t dataSize);
|
|
void IssueReceiveCall(void);
|
|
static void onSocketBound(void* pData, int32_t dataSize);
|
|
static void onSendTo(void* pData, int32_t dataSize);
|
|
void BufferSend( RNS2_SendParameters *sendParameters, const char *file, unsigned int line );
|
|
PP_Resource rns2Socket;
|
|
NativeClientBindParameters binding;
|
|
bool sendInProgress;
|
|
SimpleMutex sendInProgressMutex;
|
|
|
|
enum BindState
|
|
{
|
|
BS_UNBOUND,
|
|
BS_IN_PROGRESS,
|
|
BS_BOUND,
|
|
BS_FAILED
|
|
} bindState;
|
|
DataStructures::Queue<RNS2_SendParameters_NativeClient*> bufferedSends;
|
|
SimpleMutex bufferedSendsMutex;
|
|
};
|
|
#else // defined(WINDOWS_STORE_RT)
|
|
|
|
struct RNS2_BerkleyBindParameters
|
|
{
|
|
// Input parameters
|
|
unsigned short port;
|
|
char *hostAddress;
|
|
unsigned short addressFamily; // AF_INET or AF_INET6
|
|
int type; // SOCK_DGRAM
|
|
int protocol; // 0
|
|
bool nonBlockingSocket;
|
|
int setBroadcast;
|
|
int setIPHdrIncl;
|
|
int doNotFragment;
|
|
int pollingThreadPriority;
|
|
RNS2EventHandler *eventHandler;
|
|
unsigned short remotePortRakNetWasStartedOn_PS3_PS4_PSP2;
|
|
};
|
|
|
|
// Every platform except Windows Store 8 can use the Berkley sockets interface
|
|
class IRNS2_Berkley : public RakNetSocket2
|
|
{
|
|
public:
|
|
// ----------- STATICS ------------
|
|
// For addressFamily, use AF_INET
|
|
// For type, use SOCK_DGRAM
|
|
static bool IsPortInUse(unsigned short port, const char *hostAddress, unsigned short addressFamily, int type );
|
|
|
|
// ----------- MEMBERS ------------
|
|
virtual RNS2BindResult Bind( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line )=0;
|
|
};
|
|
// Every platform that uses Berkley sockets, except native client, can compile some common functions
|
|
class RNS2_Berkley : public IRNS2_Berkley
|
|
{
|
|
public:
|
|
RNS2_Berkley();
|
|
virtual ~RNS2_Berkley();
|
|
int CreateRecvPollingThread(int threadPriority);
|
|
void SignalStopRecvPollingThread(void);
|
|
void BlockOnStopRecvPollingThread(void);
|
|
const RNS2_BerkleyBindParameters *GetBindings(void) const;
|
|
RNS2Socket GetSocket(void) const;
|
|
void SetDoNotFragment( int opt );
|
|
|
|
protected:
|
|
// Used by other classes
|
|
RNS2BindResult BindShared( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line );
|
|
RNS2BindResult BindSharedIPV4( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line );
|
|
RNS2BindResult BindSharedIPV4And6( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line );
|
|
|
|
static void GetSystemAddressIPV4 ( RNS2Socket rns2Socket, SystemAddress *systemAddressOut );
|
|
static void GetSystemAddressIPV4And6 ( RNS2Socket rns2Socket, SystemAddress *systemAddressOut );
|
|
|
|
// Internal
|
|
void SetNonBlockingSocket(unsigned long nonblocking);
|
|
void SetSocketOptions(void);
|
|
void SetBroadcastSocket(int broadcast);
|
|
void SetIPHdrIncl(int ipHdrIncl);
|
|
void RecvFromBlocking(RNS2RecvStruct *recvFromStruct);
|
|
void RecvFromBlockingIPV4(RNS2RecvStruct *recvFromStruct);
|
|
void RecvFromBlockingIPV4And6(RNS2RecvStruct *recvFromStruct);
|
|
|
|
RNS2Socket rns2Socket;
|
|
RNS2_BerkleyBindParameters binding;
|
|
|
|
unsigned RecvFromLoopInt(void);
|
|
RakNet::LocklessUint32_t isRecvFromLoopThreadActive;
|
|
volatile bool endThreads;
|
|
// Constructor not called!
|
|
|
|
#if defined(__APPLE__)
|
|
// http://sourceforge.net/p/open-dis/discussion/683284/thread/0929d6a0
|
|
CFSocketRef _cfSocket;
|
|
#endif
|
|
|
|
static RAK_THREAD_DECLARATION(RecvFromLoop);
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(__GNUC__) || defined(__GCCXML__) || defined(__S3E__)
|
|
class RNS2_Windows_Linux_360
|
|
{
|
|
public:
|
|
protected:
|
|
static RNS2SendResult Send_Windows_Linux_360NoVDP( RNS2Socket rns2Socket, RNS2_SendParameters *sendParameters, const char *file, unsigned int line );
|
|
};
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
class RAK_DLL_EXPORT SocketLayerOverride
|
|
{
|
|
public:
|
|
SocketLayerOverride() {}
|
|
virtual ~SocketLayerOverride() {}
|
|
|
|
/// Called when SendTo would otherwise occur.
|
|
virtual int RakNetSendTo( const char *data, int length, const SystemAddress &systemAddress )=0;
|
|
|
|
/// Called when RecvFrom would otherwise occur. Return number of bytes read. Write data into dataOut
|
|
// Return -1 to use RakNet's normal recvfrom, 0 to abort RakNet's normal recvfrom, and positive to return data
|
|
virtual int RakNetRecvFrom( char dataOut[ MAXIMUM_MTU_SIZE ], SystemAddress *senderOut, bool calledFromMainThread )=0;
|
|
};
|
|
|
|
class RNS2_Windows : public RNS2_Berkley, public RNS2_Windows_Linux_360
|
|
{
|
|
public:
|
|
RNS2_Windows();
|
|
virtual ~RNS2_Windows();
|
|
RNS2BindResult Bind( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line );
|
|
RNS2SendResult Send( RNS2_SendParameters *sendParameters, const char *file, unsigned int line );
|
|
void SetSocketLayerOverride(SocketLayerOverride *_slo);
|
|
SocketLayerOverride* GetSocketLayerOverride(void);
|
|
// ----------- STATICS ------------
|
|
static void GetMyIP( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
protected:
|
|
static void GetMyIPIPV4( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
static void GetMyIPIPV4And6( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
SocketLayerOverride *slo;
|
|
};
|
|
|
|
#else
|
|
class RNS2_Linux : public RNS2_Berkley, public RNS2_Windows_Linux_360
|
|
{
|
|
public:
|
|
RNS2BindResult Bind( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line );
|
|
RNS2SendResult Send( RNS2_SendParameters *sendParameters, const char *file, unsigned int line );
|
|
|
|
// ----------- STATICS ------------
|
|
static void GetMyIP( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
protected:
|
|
static void GetMyIPIPV4( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
static void GetMyIPIPV4And6( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] );
|
|
};
|
|
|
|
#endif // Linux
|
|
|
|
#endif // #elif !defined(WINDOWS_STORE_RT)
|
|
|
|
} // namespace RakNet
|
|
|
|
#endif // __RAKNET_SOCKET_2_H
|