| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /* Copyright The kNet Project.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License. */
- #pragma once
- /** @file UDPMessageConnection.h
- @brief The UDPMessageConnection class. */
- // Modified by Lasse Oorni for Urho3D
- #include "MessageConnection.h"
- #include "SequentialIntegerSet.h"
- #include "Array.h"
- #include "OrderedHashTable.h"
- /*
- UDP packet format: 3 bytes if InOrder=false. 5-6 bytes if InOrder=true.
- 1bit - InOrder packet. This packet contains InOrder messages.
- 1bit - Reliable packet. This packet is expected to be Acked by the receiver.
- 6 bits - The six lowest bits of the PacketID.
- u16 The 16 next bits of the PacketID. This gives 22 bits of the PacketID in total.
- * u8 InOrder array length.
- * N x u8-u16 InOrder PacketID delta counter. VLE-encoded 1.7/8 Only present if InOrder=true.
- .Message.
- .Message.
- ...
- .Message.
- Message format: 2 bytes if FRGSTART=FRAGMENT=false.
- 1bit - FRGSTART. This is the first fragment of the message (offset=0)
- 1bit - FRAGMENT. This message is a fragment of a bigger message -flag. If FRGSTART=true, this field is not read and is assumed to be true.
- 1bit - InOrder. This message may be processed by the application only after all the previous InOrder messages have been processed.
- * 1bit - InOrder. This message may be processed by the application only after all the previous InOrder messages have been processed.
- * 1bit - InOrder. This message may be processed by the application only after all the previous InOrder messages have been processed.
- (Old: 1bit - Unused.)
- (Old: 1bit - Unused.)
- 11 bits Content length (includes both the length of MessageID and Content Data fields)
- * u8 InOrder array index. Only present if InOrder=7 (111 in base 2).
- u8-u32 # of Fragments in whole message VLE-encoded 1.7/1.7/16 Only present if FRGSTART=true.
- u8 Fragment Transfer ID Only present if FRAGMENT=true or FRGSTART=true.
- * New: u8-u32 Fragment number VLE-encoded 1.7/1.7/16 Only present if FRAGMENT=true and FRGSTART=false.
- (Old: u8-u16 Fragment number VLE-encoded 1.7/8 Only present if FRAGMENT=true.)
- .Content.
- Content format:
- u8-u32 MessageID VLE-encoded 1.7/1.7/16
- N bytes Content data
- */
- namespace kNet
- {
- class UDPMessageConnection : public MessageConnection
- {
- public:
- UDPMessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState);
- ~UDPMessageConnection();
- float RetransmissionTimeout() const { return retransmissionTimeout; }
- float DatagramSendRate() const { return datagramSendRate; }
- void SetDatagramSendRate(float newRateDgramsPerSecond) { datagramSendRate = newRateDgramsPerSecond; }
- float SmoothedRtt() const { return smoothedRTT; }
- float RttVariation() const { return rttVariation; }
- size_t NumOutboundUnackedDatagrams() const { return outboundPacketAckTrack.Size(); }
- size_t NumReceivedUnackedDatagrams() const { return inboundPacketAckTrack.size(); }
- float PacketLossCount() const { return packetLossCount; }
- float PacketLossRate() const { return packetLossRate; }
- private:
- /// Reads all the new bytes available in the socket.
- /// @return The number of bytes successfully read.
- virtual SocketReadResult ReadSocket(size_t &bytesRead); // [worker thread]
- /// Parses bytes with have previously been read from the socket to actual application-level messages.
- void ExtractMessages(const char *data, size_t numBytes); // [worker thread]
- /// Reads all available bytes from a datagram socket. This function will read in multiple datagrams
- /// as long as there are available ones to process.
- /// @param bytesRead [out] Returns the total number of bytes containes in the datagrams that were read.
- SocketReadResult UDPReadSocket(size_t &bytesRead); // [worker thread]
- void UpdateRTOCounterOnPacketAck(float rtt); // [worker thread]
- void UpdateRTOCounterOnPacketLoss(); // [worker thread]
- // Closing down the connection:
- void SendDisconnectMessage(bool isInternal); // [main thread]
- void HandleDisconnectMessage(); // [worker thread]
- void SendDisconnectAckMessage(); // [worker thread]
- void HandleDisconnectAckMessage(); // [worker thread]
- // Acknowledging reliable datagrams:
- void PerformPacketAckSends(); // [worker thread]
- void SendPacketAckMessage(); // [worker thread]
- void HandlePacketAckMessage(const char *data, size_t numBytes); // [worker thread]
-
- bool HandleMessage(packet_id_t packetID, message_id_t messageID, const char *data, size_t numBytes); // [worker thread]
- /// Refreshes Packet Loss related statistics.
- void ComputePacketLoss(); // [worker thread]
- /// Marks that we have received a datagram with the given ID.
- void AddReceivedPacketIDStats(packet_id_t packetID); // [worker thread]
- /// @return True if we have received a packet with the given packetID already.
- bool HaveReceivedPacketID(packet_id_t packetID) const; // [worker thread]
- /// Copies the given message to an internal queue to wait to be processed by the worker thread that owns this connection.
- void QueueInboundDatagram(const char *data, size_t numBytes); // [thread-safe].
- /// Handles all the previously queued datagrams this connection has received.
- void ProcessQueuedDatagrams(); // [worker thread]
- /// Specifies the PacketID of the last received datagram with InOrder flag set.
- packet_id_t lastReceivedInOrderPacketID;
- /// Specifies the PacketID of the last sent datagram with InOrder flag set.
- packet_id_t lastSentInOrderPacketID;
- /// A running index to identify packet datagrams as they are send out to the stream.
- packet_id_t datagramPacketIDCounter;
- /// Specifies in milliseconds the currently recommended datagram timeout value for any packet that is sent out at the present time.
- float retransmissionTimeout;
- /// The flow control operates on fixed time window intervals called 'frames'. This variable remembers
- /// when the previous frame ended, and the currently elapsed frame starts.
- tick_t lastFrameTime;
- int numAcksLastFrame;
- int numLossesLastFrame;
- /// The flow control algorithm:
- float datagramSendRate; ///< The number of datagrams/second to send.
- float lowestDatagramSendRateOnPacketLoss;
- int slowModeDelay; ///< Go into slow increase mode for some time on receiving loss
- // These variables correspond to RFC2988, http://tools.ietf.org/html/rfc2988 , section 2.
- bool rttCleared; ///< If true, smoothedRTT and rttVariation do not contain meaningful values, but "are clear".
- float smoothedRTT;
- float rttVariation;
- // The following are used for statistics purposes:
- float packetLossRate; ///< The currently estimated datagram packet loss rate, [0, 1].
- float packetLossCount; ///< The current packet loss in absolute packets/sec.
- /// Info struct used to track acks of reliable packets.
- struct PacketAckTrack
- {
- PacketAckTrack()
- :sendCount(0)
- {
- }
- /// The timestamp of when a packet with this ID was last sent out.
- tick_t sentTick;
- /// The timestamp of when this packet will time out and can be resent (at the earliest. It will get queued and be resent later)
- tick_t timeoutTick;
- /// The packet ID of the packet that was sent out.
- packet_id_t packetID;
- /// The packet send rate we had when this packet was sent out.
- float datagramSendRate;
- /// The number of times this packet has been sent. 1 denotes no resends. 2 - this packet's been resent once, and so on.
- int sendCount;
- /// If true, the packet with this ID was an inOrder packet.
- bool inOrder;
- /// if inOrder==true, this tells the packetID of the previous in-order packet that was transmitted.
- packet_id_t previousInOrderPacketID;
- Array<NetworkMessage*> messages;
- static int Hash(const PacketAckTrack &item, int maxElemsMask) { return item.packetID & maxElemsMask; }
- static int Hash(int key, int maxElemsMask) { return key & maxElemsMask; }
- };
- void ProcessPacketTimeouts(); // [worker thread]
- void HandleFlowControl(); // [worker thread]
- void DoUpdateConnection(); // [worker thread]
- PacketSendResult SendOutPacket(); // [worker thread]
- void SendOutPackets(); // [worker thread]
- unsigned long TimeUntilCanSendPacket() const; // [worker thread]
- void PerformDisconnection(); // [main thread]
- /// Returns OK if it is acceptable by the flow control timer to send out a new datagram.
- bool CanSendOutNewDatagram() const; // [worker thread]
- /// Called whenever we have sent a new datagram to recompute the datagram send throttle timer.
- void NewDatagramSent(); // [worker thread]
- /// Used to perform flow control on outbound UDP messages.
- mutable tick_t lastDatagramSendTime; ///\todo. No mutable. Rename to nextDatagramSendTime.
- /// Connection control update timer.
- PolledTimer udpUpdateTimer;
- PolledTimer statsUpdateTimer;
- typedef std::map<packet_id_t, PacketAckTrack> PacketAckTrackMap;
- /// Contains the messages we have sent out that we are waiting for the other party to Ack.
- // PacketAckTrackMap outboundPacketAckTrack;
- typedef WaitFreeQueue<PacketAckTrack> PacketAckTrackQueue;
- PacketAckTrackQueue outboundPacketAckTrack;
- // typedef OrderedHashTable<PacketAckTrack, PacketAckTrack> PacketAckTrackTable;
- // PacketAckTrackTable outboundPacketAckTrack;
- static int BiasedBinarySearchFindPacketIndex(UDPMessageConnection::PacketAckTrackQueue &queue, packet_id_t packetID);
- WaitFreeQueue<Datagram> queuedInboundDatagrams;
- void FreeOutboundPacketAckTrack(packet_id_t packetID); // [worker thread]
- // Contains a list of all messages we've received that we need to Ack at some point.
- PacketAckTrackMap inboundPacketAckTrack;
- /// Contains the reliable message numbers of all reliable messages we've received.
- /// Used to detect and discard duplicate messages we've received.
- std::set<unsigned long> receivedReliableMessages;
- SequentialIntegerSet receivedPacketIDs;
- /// Specifies the packet ID of the most recent datagram we sent. Used currently only
- /// for statistics purposes.
- packet_id_t previousReceivedPacketID;
- // The following are temporary data structures used by various internal routines for processing.
- // They are created here as members to avoid having to create objects on the stack at each call to
- // time-sensitive functions.
- std::vector<NetworkMessage *> datagramSerializedMessages; // MessageConnection::UDPSendOutPacket()
- std::vector<NetworkMessage *> skippedMessages; // MessageConnection::UDPSendOutPacket()
- std::vector<char> assembledData; // MessageConnection::DatagramExtractMessages
- /// Returns the average number of inbound packet loss, packets/sec.
- float GetPacketLossCount() const { return packetLossCount; }
- /// Returns the percentage of inbound packets that are being lost, [0, 1].
- float GetPacketLossRate() const { return packetLossRate; }
- void DumpConnectionStatus() const;
- friend class NetworkServer;
- };
- } // ~kNet
|