forked from Xeeynamo/sonic-hybrid-rsdk
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
98 changes: 98 additions & 0 deletions
98
sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/ConnectionManager.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution. | ||
* Copyright (C) 2017-2024 by Eukaryot | ||
* | ||
* Published under the GNU GPLv3 open source software license, see license.txt | ||
* or https://www.gnu.org/licenses/gpl-3.0.en.html | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "oxygen_netcore/network/internal/SentPacketCache.h" | ||
#include "oxygen_netcore/network/internal/ReceivedPacket.h" | ||
#include "oxygen_netcore/network/VersionRange.h" | ||
#include "oxygen_netcore/base/HandleProvider.h" | ||
|
||
namespace lowlevel | ||
{ | ||
struct PacketBase; | ||
} | ||
struct ConnectionListenerInterface; | ||
|
||
|
||
class ConnectionManager | ||
{ | ||
friend class NetConnection; | ||
|
||
public: | ||
struct DebugSettings | ||
{ | ||
float mSendingPacketLoss = 0.0f; // Fraction of "lost" packets in sending | ||
float mReceivingPacketLoss = 0.0f; // Fraction of "lost" packets in receiving | ||
}; | ||
DebugSettings mDebugSettings; | ||
|
||
public: | ||
ConnectionManager(UDPSocket* udpSocket, TCPSocket* tcpListenSocket, ConnectionListenerInterface& listener, VersionRange<uint8> highLevelProtocolVersionRange); | ||
|
||
inline bool hasUDPSocket() const { return (nullptr != mUDPSocket); } | ||
inline UDPSocket* getUDPSocket() const { return mUDPSocket; } | ||
inline TCPSocket* getTCPListenSocket() const { return mTCPListenSocket; } | ||
|
||
inline ConnectionListenerInterface& getListener() const { return mListener; } | ||
inline size_t getNumActiveConnections() const { return mActiveConnections.size(); } | ||
|
||
inline VersionRange<uint8> getHighLevelProtocolVersionRange() const { return mHighLevelProtocolVersionRange; } | ||
|
||
void updateConnections(uint64 currentTimestamp); | ||
bool updateReceivePackets(); // TODO: This is meant to be executed by a thread later on | ||
|
||
void syncPacketQueues(); | ||
|
||
inline bool hasAnyPacket() const { return !mReceivedPackets.mSyncedQueue.empty(); } | ||
ReceivedPacket* getNextReceivedPacket(); | ||
std::list<TCPSocket>& getIncomingTCPConnections() { return mIncomingTCPConnections; } | ||
|
||
bool sendUDPPacketData(const std::vector<uint8>& data, const SocketAddress& remoteAddress); | ||
bool sendTCPPacketData(const std::vector<uint8>& data, TCPSocket& socket, bool isWebSocketServer); | ||
bool sendConnectionlessLowLevelPacket(lowlevel::PacketBase& lowLevelPacket, const SocketAddress& remoteAddress, uint16 localConnectionID, uint16 remoteConnectionID); | ||
|
||
NetConnection* findConnectionTo(uint64 senderKey) const; | ||
|
||
protected: | ||
// Only meant to be called from the NetConnection | ||
void addConnection(NetConnection& connection); | ||
void removeConnection(NetConnection& connection); | ||
SentPacket& rentSentPacket(); | ||
|
||
// Internal | ||
void receivedPacketInternal(const std::vector<uint8>& buffer, const SocketAddress& senderAddress, NetConnection* connection); | ||
|
||
private: | ||
struct SyncedPacketQueue | ||
{ | ||
std::deque<ReceivedPacket*> mWorkerQueue; // Used by the worker thread that adds packets | ||
std::deque<ReceivedPacket*> mSyncedQueue; // Used by the main thread that reads packets | ||
ReceivedPacket::Dump mToBeReturned; | ||
}; | ||
|
||
typedef HandleProvider<uint16, NetConnection*, 16> ConnectionsProvider; | ||
|
||
private: | ||
UDPSocket* mUDPSocket = nullptr; // Only set if UDP is used (or both UDP and TCP) | ||
TCPSocket* mTCPListenSocket = nullptr; // Only set if TCP is used (or both UDP and TCP) | ||
ConnectionListenerInterface& mListener; | ||
VersionRange<uint8> mHighLevelProtocolVersionRange = { 1, 1 }; | ||
|
||
std::unordered_map<uint16, NetConnection*> mActiveConnections; // Using local connection ID as key | ||
std::unordered_map<uint64, NetConnection*> mConnectionsBySender; // Using a sender key (= hash for the sender address + remote connection ID) as key | ||
ConnectionsProvider mConnectionsProvider; | ||
|
||
std::vector<NetConnection*> mTCPNetConnections; | ||
|
||
SyncedPacketQueue mReceivedPackets; | ||
std::list<TCPSocket> mIncomingTCPConnections; | ||
|
||
RentableObjectPool<SentPacket> mSentPacketPool; | ||
RentableObjectPool<ReceivedPacket> mReceivedPacketPool; | ||
}; |
60 changes: 60 additions & 0 deletions
60
sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/HighLevelPacketBase.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution. | ||
* Copyright (C) 2017-2024 by Eukaryot | ||
* | ||
* Published under the GNU GPLv3 open source software license, see license.txt | ||
* or https://www.gnu.org/licenses/gpl-3.0.en.html | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <rmxbase.h> | ||
|
||
|
||
namespace highlevel | ||
{ | ||
|
||
// All high-level packets are built upon "lowlevel::HighLevelPacket" as their shared header | ||
// -> Yes, that name sounds a bit dumb, bit it's a low-level packet after all... | ||
|
||
struct PacketBase | ||
{ | ||
public: | ||
bool serializePacket(VectorBinarySerializer& serializer, uint8 protocolVersion) | ||
{ | ||
serializeContent(serializer, protocolVersion); | ||
return !serializer.hasError(); | ||
} | ||
|
||
public: | ||
virtual uint32 getPacketType() const = 0; | ||
virtual bool isReliablePacket() const { return true; } | ||
|
||
protected: | ||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) = 0; | ||
|
||
public: | ||
static inline std::unordered_map<uint32, std::string> mPacketTypeRegistry; | ||
}; | ||
|
||
|
||
struct PacketTypeRegistration | ||
{ | ||
inline PacketTypeRegistration(uint32 packetType, const std::string& packetName) | ||
{ | ||
RMX_ASSERT(PacketBase::mPacketTypeRegistry.count(packetType) == 0, "Multiple definition of packet type '" << packetName << "'"); | ||
PacketBase::mPacketTypeRegistry[packetType] = packetName; | ||
} | ||
}; | ||
|
||
} | ||
|
||
|
||
#define HIGHLEVEL_PACKET_DEFINE_PACKET_TYPE(_name_) \ | ||
public: \ | ||
static inline const std::string PACKET_NAME = _name_; \ | ||
static const constexpr uint32 PACKET_TYPE = rmx::compileTimeFNV_32(_name_); \ | ||
virtual uint32 getPacketType() const override { return PACKET_TYPE; } \ | ||
private: \ | ||
static inline highlevel::PacketTypeRegistration mPacketTypeRegistration { PACKET_TYPE, PACKET_NAME }; \ | ||
public: |
37 changes: 37 additions & 0 deletions
37
sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/LagStopwatch.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution. | ||
* Copyright (C) 2017-2024 by Eukaryot | ||
* | ||
* Published under the GNU GPLv3 open source software license, see license.txt | ||
* or https://www.gnu.org/licenses/gpl-3.0.en.html | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <rmxbase.h> | ||
#include <chrono> | ||
|
||
|
||
class LagStopwatch | ||
{ | ||
public: | ||
inline LagStopwatch(const char* text, int maxMs = 2000) : mText(text), mMaximumMilliseconds(maxMs), mStartTime(std::chrono::steady_clock::now()) {} | ||
|
||
inline ~LagStopwatch() | ||
{ | ||
const uint64 milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - mStartTime).count(); | ||
if (milliseconds > mMaximumMilliseconds) | ||
RMX_LOG_INFO("LagStopwatch: " << mText << " took " << milliseconds << " ms"); | ||
} | ||
|
||
private: | ||
const char* mText; | ||
int mMaximumMilliseconds = 2000; | ||
std::chrono::steady_clock::time_point mStartTime; | ||
}; | ||
|
||
#ifdef OXYGEN_SERVER | ||
#define LAG_STOPWATCH(_text_, _maxMs_) LagStopwatch lagStopwatch_##LINE_NUMBER(_text_, _maxMs_) | ||
#else | ||
#define LAG_STOPWATCH(_text_, _maxMs_) | ||
#endif |
165 changes: 165 additions & 0 deletions
165
sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/LowLevelPackets.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
/* | ||
* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution. | ||
* Copyright (C) 2017-2024 by Eukaryot | ||
* | ||
* Published under the GNU GPLv3 open source software license, see license.txt | ||
* or https://www.gnu.org/licenses/gpl-3.0.en.html | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "oxygen_netcore/network/VersionRange.h" | ||
|
||
|
||
namespace lowlevel | ||
{ | ||
// Note that for all low-level packets, an additional six bytes is sent preceding the actual packet-specific content: | ||
// - the packet signature | ||
// - the connection IDs (local and remote, as seen from the sender's point of view) | ||
|
||
struct PacketBase | ||
{ | ||
public: | ||
static const constexpr VersionRange<uint8> LOWLEVEL_PROTOCOL_VERSIONS { 1, 1 }; | ||
|
||
public: | ||
bool serializePacket(VectorBinarySerializer& serializer, uint8 protocolVersion) | ||
{ | ||
serializeContent(serializer, protocolVersion); | ||
return !serializer.hasError(); | ||
} | ||
|
||
public: | ||
virtual uint16 getSignature() const = 0; | ||
|
||
protected: | ||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) = 0; | ||
}; | ||
|
||
|
||
struct StartConnectionPacket : public PacketBase | ||
{ | ||
VersionRange<uint8> mLowLevelProtocolVersionRange; | ||
VersionRange<uint8> mHighLevelProtocolVersionRange; | ||
|
||
static const constexpr uint16 SIGNATURE = 0x87a1; | ||
virtual uint16 getSignature() const override { return SIGNATURE; } | ||
|
||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) override | ||
{ | ||
mLowLevelProtocolVersionRange.serialize(serializer); | ||
mHighLevelProtocolVersionRange.serialize(serializer); | ||
} | ||
}; | ||
|
||
|
||
struct AcceptConnectionPacket : public PacketBase | ||
{ | ||
uint8 mLowLevelProtocolVersion = 0; | ||
uint8 mHighLevelProtocolVersion = 0; | ||
|
||
static const constexpr uint16 SIGNATURE = 0x1b22; | ||
virtual uint16 getSignature() const override { return SIGNATURE; } | ||
|
||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) override | ||
{ | ||
serializer.serialize(mLowLevelProtocolVersion); | ||
serializer.serialize(mHighLevelProtocolVersion); | ||
} | ||
}; | ||
|
||
|
||
struct ErrorPacket : public PacketBase | ||
{ | ||
enum class ErrorCode : uint8 | ||
{ | ||
// The errors marking with (*) are sent without an actual establishes connection - that means they do not include a proper local connection ID and just re-use the received remote connection ID | ||
UNKNOWN = 0, | ||
CONNECTION_INVALID = 1, // (*) Received a packet with an unknown connection ID | ||
UNSUPPORTED_VERSION = 2, // (*) Received a start connection packet that uses protocol versions that can't be supported | ||
TOO_MANY_CONNECTIONS = 3, // (*) Remote server / client has too many active connections already | ||
}; | ||
ErrorCode mErrorCode = ErrorCode::UNKNOWN; | ||
uint32 mParameter = 0; | ||
|
||
static const constexpr uint16 SIGNATURE = 0xf584; | ||
virtual uint16 getSignature() const override { return SIGNATURE; } | ||
|
||
inline ErrorPacket() {} | ||
inline ErrorPacket(ErrorCode errorCode, uint32 parameter = 0) : mErrorCode(errorCode), mParameter(parameter) {} | ||
|
||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) override | ||
{ | ||
serializer.serializeAs<uint8>(mErrorCode); | ||
} | ||
}; | ||
|
||
|
||
struct HighLevelPacket : public PacketBase | ||
{ | ||
struct Flags | ||
{ | ||
// None defined yet | ||
}; | ||
|
||
// This is only the header, afterwards comes the actual packet-specific content | ||
uint32 mPacketType = 0; | ||
uint8 mPacketFlags = 0; | ||
uint32 mUniquePacketID = 0; | ||
|
||
static const constexpr uint16 SIGNATURE = 0xe994; | ||
virtual uint16 getSignature() const override { return SIGNATURE; } | ||
|
||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) override | ||
{ | ||
serializer.serialize(mPacketType); | ||
serializer.serialize(mPacketFlags); | ||
serializer.serialize(mUniquePacketID); | ||
} | ||
}; | ||
|
||
|
||
struct RequestQueryPacket : public HighLevelPacket | ||
{ | ||
// No need for any custom members here | ||
|
||
static const constexpr uint16 SIGNATURE = 0x0c7a; | ||
virtual uint16 getSignature() const override { return SIGNATURE; } | ||
|
||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) override | ||
{ | ||
HighLevelPacket::serializeContent(serializer, protocolVersion); | ||
} | ||
}; | ||
|
||
|
||
struct RequestResponsePacket : public HighLevelPacket | ||
{ | ||
// Extension to the high level packet | ||
uint32 mUniqueRequestID = 0; | ||
|
||
static const constexpr uint16 SIGNATURE = 0xd028; | ||
virtual uint16 getSignature() const override { return SIGNATURE; } | ||
|
||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) override | ||
{ | ||
HighLevelPacket::serializeContent(serializer, protocolVersion); | ||
serializer.serialize(mUniqueRequestID); | ||
} | ||
}; | ||
|
||
|
||
struct ReceiveConfirmationPacket : public PacketBase | ||
{ | ||
uint32 mUniquePacketID = 0; | ||
|
||
static const constexpr uint16 SIGNATURE = 0x276f; | ||
virtual uint16 getSignature() const override { return SIGNATURE; } | ||
|
||
virtual void serializeContent(VectorBinarySerializer& serializer, uint8 protocolVersion) override | ||
{ | ||
serializer.serialize(mUniquePacketID); | ||
} | ||
}; | ||
|
||
} |