You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
345 lines
12 KiB
C++
345 lines
12 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
// Description : Service network interface
|
|
|
|
|
|
#ifndef CRYINCLUDE_CRYCOMMON_ISERVICENETWORK_H
|
|
#define CRYINCLUDE_CRYCOMMON_ISERVICENETWORK_H
|
|
#pragma once
|
|
|
|
|
|
#include <CryExtension/CryGUID.h>
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Service network is a simple abstract interface for connecting between instances
|
|
// of the editor and game running on various platforms. It implements it's own
|
|
// small message based communication layer and shall not be used for raw communication
|
|
// with anything else.
|
|
//
|
|
// Features currently implemented by the service network:
|
|
// - Completely thread safe (so can be used from within other threads)
|
|
// - Completely asynchronous (only one thread)
|
|
// - Message based approach (both on the send and receive ends)
|
|
// - Automatic and transparent reconnection
|
|
// - Debug-friendly (will not time-out easily when one of the endpoints is being debugged)
|
|
// - Easy to use
|
|
//
|
|
// Usage case (server)
|
|
// - Create listener (IServiceListener) on some pre-defined port
|
|
// - Poll the incoming connections by calling Accept() method
|
|
// - Service the traffic by calling connection's ReceiveMessage()/SendMessage() methods
|
|
// - Close() and Release() connections
|
|
// - Close() and Release() listener
|
|
//
|
|
// Usage case (client)
|
|
// - Connect to a remote listener by calling Connect() method
|
|
// - Service the traffic by calling connection's ReceiveMessage()/SendMessage() methods
|
|
// - Close() and Release() connection
|
|
//
|
|
// Both sending and receiving is asynchronous. Calling the SendMessage()/ReceiveMessage() methods
|
|
// only pushes/pops the message buffers to/from the queue.
|
|
// NOTE: Message buffers are internally reference counted by the network system and they are kept around
|
|
// untill they are sent (in case of outgoing traffic) or untill they are polled by ReceiveMessage().
|
|
// Be aware that this can cause memory spikes, especially when incoming traffic is not serviced fast enough.
|
|
// There are customizable limits (around 1MB) on the amount of data that can be buffered internally by
|
|
// the service network before the new messages are rejected.
|
|
// It's up to the higher layer to ensure damage control in such situation.
|
|
//
|
|
// NOTE: connection is also a reference counted object, make sure to call Close() before calling Release().
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// Network address abstraction
|
|
class ServiceNetworkAddress
|
|
{
|
|
public:
|
|
struct StringAddress
|
|
{
|
|
char m_data[32];
|
|
|
|
ILINE const char* c_str() const
|
|
{
|
|
return m_data;
|
|
}
|
|
};
|
|
|
|
struct Address
|
|
{
|
|
uint8 m_ip0;
|
|
uint8 m_ip1;
|
|
uint8 m_ip2;
|
|
uint8 m_ip3;
|
|
uint16 m_port;
|
|
|
|
ILINE Address()
|
|
: m_ip0(0)
|
|
, m_ip1(0)
|
|
, m_ip2(0)
|
|
, m_ip3(0)
|
|
, m_port(0)
|
|
{}
|
|
};
|
|
|
|
private:
|
|
Address m_address;
|
|
|
|
public:
|
|
// By default creates ("invalid address")
|
|
ILINE ServiceNetworkAddress()
|
|
{
|
|
}
|
|
|
|
// Copy (with optional port change)
|
|
ILINE ServiceNetworkAddress(const ServiceNetworkAddress& other, uint16 newPort = 0)
|
|
: m_address(other.m_address)
|
|
{
|
|
if (newPort != 0)
|
|
{
|
|
m_address.m_port = newPort;
|
|
}
|
|
}
|
|
|
|
// Initialize from ip:host pattern (if you want to initialize from host name use the DebugNetwork interface)
|
|
ILINE ServiceNetworkAddress(uint8 ip0, uint8 ip1, uint8 ip2, uint8 ip3, uint16 port)
|
|
{
|
|
m_address.m_ip0 = ip0;
|
|
m_address.m_ip1 = ip1;
|
|
m_address.m_ip2 = ip2;
|
|
m_address.m_ip3 = ip3;
|
|
m_address.m_port = port;
|
|
}
|
|
|
|
// Set new port value
|
|
ILINE void SetPort(uint16 port)
|
|
{
|
|
m_address.m_port = port;
|
|
}
|
|
|
|
// Is this a valid address
|
|
ILINE bool IsValid() const
|
|
{
|
|
return (m_address.m_ip0 != 0) &&
|
|
(m_address.m_ip1 != 1) &&
|
|
(m_address.m_ip2 != 1) &&
|
|
(m_address.m_ip3 != 1) &&
|
|
(m_address.m_port != 0);
|
|
}
|
|
|
|
// Convert to human readable string
|
|
ILINE StringAddress ToString() const
|
|
{
|
|
// format the string buffer
|
|
StringAddress ret;
|
|
sprintf_s(ret.m_data, sizeof(ret.m_data),
|
|
"%d.%d.%d.%d:%d",
|
|
m_address.m_ip0, m_address.m_ip1, m_address.m_ip2, m_address.m_ip3,
|
|
m_address.m_port);
|
|
|
|
// return as managed string
|
|
return ret;
|
|
}
|
|
|
|
// Get the literal data
|
|
ILINE const Address& GetAddress() const
|
|
{
|
|
return m_address;
|
|
}
|
|
|
|
public:
|
|
// Compare base address (IP only) of two connections
|
|
static bool CompareBaseAddress(const ServiceNetworkAddress& a, const ServiceNetworkAddress& b)
|
|
{
|
|
return (a.m_address.m_ip0 == b.m_address.m_ip0) &&
|
|
(a.m_address.m_ip1 == b.m_address.m_ip1) &&
|
|
(a.m_address.m_ip2 == b.m_address.m_ip2) &&
|
|
(a.m_address.m_ip3 == b.m_address.m_ip3);
|
|
}
|
|
|
|
// Compare full address (IP+port) of two connections
|
|
static bool CompareFullAddress(const ServiceNetworkAddress& a, const ServiceNetworkAddress& b)
|
|
{
|
|
return (a.m_address.m_ip0 == b.m_address.m_ip0) &&
|
|
(a.m_address.m_ip1 == b.m_address.m_ip1) &&
|
|
(a.m_address.m_ip2 == b.m_address.m_ip2) &&
|
|
(a.m_address.m_ip3 == b.m_address.m_ip3) &&
|
|
(a.m_address.m_port == b.m_address.m_port);
|
|
}
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// Message buffer used by the network system
|
|
struct IServiceNetworkMessage
|
|
{
|
|
protected:
|
|
IServiceNetworkMessage() {};
|
|
virtual ~IServiceNetworkMessage() {};
|
|
|
|
public:
|
|
// Get unique message ID (message ID is used just once)
|
|
virtual uint32 GetId() const = 0;
|
|
|
|
// Get the size of message buffer
|
|
virtual uint32 GetSize() const = 0;
|
|
|
|
// Get pointer to the message data
|
|
virtual void* GetPointer() = 0;
|
|
|
|
// Get pointer to the message data
|
|
virtual const void* GetPointer() const = 0;
|
|
|
|
// Create reader interface for reading message data, returned object is not
|
|
// reference counted but it will hold a reference to the message.
|
|
virtual struct IDataReadStream* CreateReader() const = 0;
|
|
|
|
// Add reference (buffer is internally refcounted)
|
|
virtual void AddRef() = 0;
|
|
|
|
// Release reference
|
|
virtual void Release() = 0;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// General network TCP/IP connection
|
|
struct IServiceNetworkConnection
|
|
{
|
|
protected:
|
|
IServiceNetworkConnection() {};
|
|
virtual ~IServiceNetworkConnection() {};
|
|
|
|
public:
|
|
static const uint32 kDefaultFlushTime = 10000; // ms
|
|
|
|
// Get the unique connection ID (is shared between host and client)
|
|
virtual const CryGUID& GetGUID() const = 0;
|
|
|
|
// Get remote endpoint address
|
|
virtual const ServiceNetworkAddress& GetRemoteAddress() const = 0;
|
|
|
|
// Get local endpoint address
|
|
virtual const ServiceNetworkAddress& GetLocalAddress() const = 0;
|
|
|
|
// Add a message buffer to the connection send queue.
|
|
// Connection can refuse to send the buffer if it's full or invalid.
|
|
// If a message is rejected this function returns false.
|
|
virtual bool SendMsg(IServiceNetworkMessage* message) = 0;
|
|
|
|
// Get a message from connection receive queue.
|
|
// If there are no pending messages a NULL is returned.
|
|
// Since message is a ref-counted you need to call Release() when you are done with the buffer.
|
|
virtual IServiceNetworkMessage* ReceiveMsg() = 0;
|
|
|
|
// Checks if connection is still alive.
|
|
// Returns false only if connection has been damaged beyond repair.
|
|
virtual bool IsAlive() const = 0;
|
|
|
|
// Get number of messages sent by this connection so far
|
|
virtual uint32 GetMessageSendCount() const = 0;
|
|
|
|
// Get number of messages received by this connection so far
|
|
virtual uint32 GetMessageReceivedCount() const = 0;
|
|
|
|
// Get size of data sent by this connection so far
|
|
virtual uint64 GetMessageSendDataSize() const = 0;
|
|
|
|
// Get size of data received by this connection so far
|
|
virtual uint64 GetMessageReceivedDataSize() const = 0;
|
|
|
|
// Request connection to be closed but not before sending out all of the pending messages. Incoming messages are ignored.
|
|
// Processing and sending the messages is done on the networking thread so this function will not block.
|
|
// As an option, connection can be forcefully closed after given amount of time (in ms).
|
|
virtual void FlushAndClose(const uint32 timeoutMs = kDefaultFlushTime) = 0;
|
|
|
|
// Synchronous wait for the connection to send all outgoing messages
|
|
virtual void FlushAndWait() = 0;
|
|
|
|
// Request connection to be closed now. All pending messages are discarded.
|
|
virtual void Close() = 0;
|
|
|
|
// Add reference (connection is an internally reference counted object)
|
|
virtual void AddRef() = 0;
|
|
|
|
// Release reference
|
|
virtual void Release() = 0;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// General listening socket (async)
|
|
struct IServiceNetworkListener
|
|
{
|
|
protected:
|
|
IServiceNetworkListener() {};
|
|
virtual ~IServiceNetworkListener() {};
|
|
|
|
public:
|
|
// Get the local address
|
|
virtual const ServiceNetworkAddress& GetLocalAddress() const = 0;
|
|
|
|
// Get number of active connections handled by this listener
|
|
virtual uint GetConnectionCount() const = 0;
|
|
|
|
// Accept incoming connection (asynchronously)
|
|
// Will return NULL if there's nothing to accept
|
|
// Will return new IDebugNetworkConnection if something was received
|
|
virtual IServiceNetworkConnection* Accept() = 0;
|
|
|
|
// Is listener able to accept connections ?
|
|
virtual bool IsAlive() const = 0;
|
|
|
|
// Request listener to be closed (closes the socket)
|
|
virtual void Close() = 0;
|
|
|
|
// Add reference (listener is an internally reference counted object)
|
|
virtual void AddRef() = 0;
|
|
|
|
// Release reference
|
|
virtual void Release() = 0;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/// General service (background) network interface
|
|
struct IServiceNetwork
|
|
{
|
|
public:
|
|
virtual ~IServiceNetwork() {};
|
|
|
|
// Set verbosity level of debug messages that got printed to log, levels 0-3 are commonly used
|
|
virtual void SetVerbosityLevel(const uint32 level) = 0;
|
|
|
|
// Allocate empty message buffer of given size, message buffer is a reference counted object
|
|
virtual IServiceNetworkMessage* AllocMessageBuffer(const uint32 size) = 0;
|
|
|
|
// Create general message writer stream, object is not reference counted
|
|
virtual struct IDataWriteStream* CreateMessageWriter() = 0;
|
|
|
|
// Create general message reader stream and initialize it with data
|
|
virtual struct IDataReadStream* CreateMessageReader(const void* pData, const uint32 dataSize) = 0;
|
|
|
|
// Translate host address (string:port) to network address
|
|
virtual ServiceNetworkAddress GetHostAddress(const string& addressString, uint16 optionalPort = 0) const = 0;
|
|
|
|
// Create network listener on given local port, listening and accepting connections is done on network thread
|
|
virtual IServiceNetworkListener* CreateListener(uint16 localPort) = 0;
|
|
|
|
// Connect to remote address (will block until connection is made or refused)
|
|
virtual IServiceNetworkConnection* Connect(const ServiceNetworkAddress& remoteAddress) = 0;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#endif // CRYINCLUDE_CRYCOMMON_ISERVICENETWORK_H
|