Nazara Engine  0.4
A fast, complete, cross-platform API designed for game development
RUdpConnection.hpp
1 // Copyright (C) 2017 Jérôme Leclercq
2 // This file is part of the "Nazara Engine - Network module"
3 // For conditions of distribution and use, see copyright notice in Config.hpp
4 
5 #pragma once
6 
7 #ifndef NAZARA_RUDPSERVER_HPP
8 #define NAZARA_RUDPSERVER_HPP
9 
10 #include <Nazara/Prerequesites.hpp>
11 #include <Nazara/Core/Bitset.hpp>
12 #include <Nazara/Core/Clock.hpp>
13 #include <Nazara/Network/IpAddress.hpp>
14 #include <Nazara/Network/NetPacket.hpp>
15 #include <Nazara/Network/RUdpMessage.hpp>
16 #include <Nazara/Network/UdpSocket.hpp>
17 #include <deque>
18 #include <queue>
19 #include <random>
20 #include <set>
21 #include <unordered_map>
22 
23 namespace Nz
24 {
25  class NAZARA_NETWORK_API RUdpConnection
26  {
27  friend class Network;
28 
29  public:
30  using SequenceIndex = UInt16;
31 
33  RUdpConnection(const RUdpConnection&) = delete;
34  RUdpConnection(RUdpConnection&&) = default;
35  ~RUdpConnection() = default;
36 
37  inline void Close();
38 
39  bool Connect(const IpAddress& remoteAddress);
40  bool Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr);
41  inline void Disconnect();
42 
43  inline IpAddress GetBoundAddress() const;
44  inline UInt16 GetBoundPort() const;
45  inline SocketError GetLastError() const;
46 
47  inline bool Listen(NetProtocol protocol, UInt16 port = 64266);
48  bool Listen(const IpAddress& address);
49 
50  bool PollMessage(RUdpMessage* message);
51 
52  bool Send(const IpAddress& clientIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet);
53 
54  inline void SetProtocolId(UInt32 protocolId);
55  inline void SetTimeBeforeAck(UInt32 ms);
56 
57  inline void SimulateNetwork(double packetLoss);
58 
59  void Update();
60 
61  RUdpConnection& operator=(const RUdpConnection&) = delete;
62  RUdpConnection& operator=(RUdpConnection&&) = default;
63 
64  static constexpr std::size_t MessageHeader = sizeof(UInt16) + 2 * sizeof(SequenceIndex) + sizeof(UInt32); //< Protocol ID (begin) + Sequence ID + Remote Sequence ID + Ack bitfield
65  static constexpr std::size_t MessageFooter = sizeof(UInt16); //< Protocol ID (end)
66 
67  // Signals:
68  NazaraSignal(OnConnectedToPeer, RUdpConnection* /*connection*/);
69  NazaraSignal(OnPeerAcknowledged, RUdpConnection* /*connection*/, const IpAddress& /*adress*/);
70  NazaraSignal(OnPeerConnection, RUdpConnection* /*connection*/, const IpAddress& /*adress*/);
71  NazaraSignal(OnPeerDisconnected, RUdpConnection* /*connection*/, const IpAddress& /*adress*/);
72 
73  private:
74  struct PeerData;
75  struct PendingAckPacket;
76  struct PendingPacket;
77 
78  enum PeerState
79  {
80  PeerState_Aknowledged, //< A connection request from this peer has been received, we're waiting for another packet to validate
81  PeerState_Connected, //< Connection is working in both-ways
82  PeerState_Connecting, //< A connection request has been made
83  PeerState_WillAck //< Connected, received one or more packets and has no packets to send, waiting before sending an empty ack packet
84  };
85 
86  void DisconnectPeer(std::size_t peerIndex);
87  void EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet);
88  void EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data);
89  bool InitSocket(NetProtocol protocol);
90  void ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits);
91  PeerData& RegisterPeer(const IpAddress& address, PeerState state);
92  void OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token);
93  void OnPacketLost(PeerData& peer, PendingAckPacket&& packet);
94  void OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet);
95  void SendPacket(PeerData& peer, PendingPacket&& packet);
96 
97  static inline unsigned int ComputeSequenceDifference(SequenceIndex sequence, SequenceIndex sequence2);
98  static inline bool HasPendingPackets(PeerData& peer);
99  static bool Initialize();
100  static inline bool IsAckMoreRecent(SequenceIndex ack, SequenceIndex ack2);
101  static inline bool IsReliable(PacketReliability reliability);
102  static void Uninitialize();
103 
104  struct PendingPacket
105  {
106  PacketPriority priority;
107  PacketReliability reliability;
108  NetPacket data;
109  };
110 
111  struct PendingAckPacket
112  {
113  PacketPriority priority;
114  PacketReliability reliability;
115  NetPacket data;
116  SequenceIndex sequenceId;
117  UInt64 timeSent;
118  };
119 
120  struct PeerData //TODO: Move this to RUdpClient
121  {
122  PeerData() = default;
123  PeerData(PeerData&& other) = default;
124  PeerData& operator=(PeerData&& other) = default;
125 
126  std::array<std::vector<PendingPacket>, PacketPriority_Max + 1> pendingPackets;
127  std::deque<PendingAckPacket> pendingAckQueue;
128  std::set<UInt16> receivedQueue;
129  std::size_t index;
130  PeerState state;
131  IpAddress address;
132  SequenceIndex localSequence;
133  SequenceIndex remoteSequence;
134  UInt32 roundTripTime;
135  UInt64 lastPacketTime;
136  UInt64 lastPingTime;
137  UInt64 stateData1;
138  };
139 
140  std::bernoulli_distribution m_packetLossProbability;
141  std::queue<RUdpMessage> m_receivedMessages;
142  std::size_t m_peerIterator;
143  std::unordered_map<IpAddress, std::size_t> m_peerByIP;
144  std::vector<PeerData> m_peers;
145  Bitset<UInt64> m_activeClients;
146  Clock m_clock;
147  SocketError m_lastError;
148  UdpSocket m_socket;
149  UInt32 m_forceAckSendTime;
150  UInt32 m_pingInterval;
151  UInt32 m_protocol;
152  UInt32 m_timeBeforePing;
153  UInt32 m_timeBeforeTimeOut;
154  UInt64 m_currentTime;
155  bool m_isSimulationEnabled;
156  bool m_shouldAcceptConnections;
157 
158  static std::mt19937_64 s_randomGenerator;
159  };
160 }
161 
162 #include <Nazara/Network/RUdpConnection.inl>
163 
164 #endif // NAZARA_RUDPSERVER_HPP
Utility class that measure the elapsed time.
Definition: Clock.hpp:20
TODO: Inherit SoundEmitter from Node.
Definition: Algorithm.hpp:12
Network class that represents an IP address.
Definition: IpAddress.hpp:21
Core class that represents a string.
Definition: String.hpp:22
Network class that represents a packet.
Definition: NetPacket.hpp:18
Network class that represents the module initializer of Network.
Definition: Network.hpp:15
Network class that represents a UDP socket, allowing for sending/receiving datagrams.
Definition: UdpSocket.hpp:19
Network class that represents a reliable UDP connection.
Definition: RUdpConnection.hpp:25