1 /*
2  * common/AckManager.hpp
3  *
4  * This file is part of Leges Motus, a networked, 2D shooter set in zero gravity.
5  *
6  * Copyright 2009-2010 Andrew Ayer, Nathan Partlan, Jeffrey Pfau
7  *
8  * Leges Motus is free and open source software.  You may redistribute it and/or
9  * modify it under the terms of version 2, or (at your option) version 3, of the
10  * GNU General Public License (GPL), as published by the Free Software Foundation.
11  *
12  * Leges Motus is distributed in the hope that it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14  * PARTICULAR PURPOSE.  See the full text of the GNU General Public License for
15  * further detail.
16  *
17  * For a full copy of the GNU General Public License, please see the COPYING file
18  * in the root of the source code tree.  You may also retrieve a copy from
19  * <http://www.gnu.org/licenses/gpl-2.0.txt>, or request a copy by writing to the
20  * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307  USA
22  *
23  */
24 
25 #ifndef LM_COMMON_ACKMANAGER_HPP
26 #define LM_COMMON_ACKMANAGER_HPP
27 
28 #include <string>
29 #include <list>
30 #include <map>
31 #include <set>
32 #include <stdint.h>
33 #include "IPAddress.hpp"
34 #include "PacketHeader.hpp"
35 
36 namespace LM {
37 	class PacketWriter;
38 	class CommonNetwork;
39 
40 	class AckManager {
41 	private:
42 		// Parameters controlling ACKs
43 		enum {
44 			ACK_TIME = 500,
45 			RETRIES = 10
46 		};
47 
48 		// This class represents a packet which has been sent (possibly to multiple recipients), and is awaiting ACKs
49 		// Note that when the packet is sent to multiple recipients, all recipients receive the same packet data, but
50 		// each recipient is sent a different packet header. That's why the packet header is stored in the recipients map.
51 		class SentPacket {
52 		private:
53 			uint64_t				send_time;	// When was it sent?
54 			std::map<IPAddress, PacketHeader>	recipients;	// Who was it sent to? (and with what header?)
55 			std::string				packet_data;	// What it was
56 			int					tries_left;	// How many more times to try sending it
57 
58 			// Use this constructor to construct a broadcast packet.
59 			// Then call add_recipient() to add the peers to which it was sent.
60 			explicit SentPacket(const std::string& packet_data);
61 
62 			// Use this function to construct a unicast packet
63 			// It's just shorthand for SentPacket(data) followed by a call to add_recipient(peer_addr, header)
64 			SentPacket(const IPAddress& peer_addr, const PacketHeader& header, const std::string& data);
65 
66 			// Add a recipient
67 			void			add_recipient(const IPAddress&, const PacketHeader&);
68 
69 			// Call when an ACK is received for this packet for the given recipient
70 			// It will remove the recipient from this SentPacket
71 			void			ack(const IPAddress& peer);
72 
73 			uint64_t		time_since_send() const;	// How long since packet was sent?
74 			uint64_t		time_until_resend() const;	// How long until we should try resending?
75 
76 			void			reset_send_time();		// Call when the packet has been resent
77 
78 			// When has_recipients() returns false, this SentPacket should be removed
79 			// from the AckManager because all its recipients have received the packet OK
has_recipients() const80 			bool			has_recipients() const { return !recipients.empty(); }
81 
82 			friend class AckManager;
83 		};
84 		friend class SentPacket;
85 
86 		typedef std::list<SentPacket> Queue;
87 		typedef std::map<std::pair<IPAddress, uint64_t>, Queue::iterator> Map;
88 
89 		// Packets are added to this queue in the order that they are sent
90 		Queue								m_packets;
91 		// The map allows quick lookup of a packet by IP address and sequence number
92 		Map								m_packets_by_id;
93 
94 	public:
95 		void		clear();
96 		void		clear_peer(const IPAddress& peer); // Remove all packets for this peer from the ACK manager
97 
98 		typedef Queue::iterator PacketHandle;
99 
100 		// add_packet adds a unicast packet to the AckManager
101 		void		add_packet(const IPAddress& peer_addr, const PacketHeader& header, const std::string& data);
102 
103 		// Add_broadcast_packet adds a broadcast packet to the AckManager
104 		// It returns an opaque PacketHandle object.
105 		// Add each recipient of the broadcast packet by calling add_broadcast_recipient with the PacketHandle object.
106 		PacketHandle	add_broadcast_packet(const std::string& data);
107 		void		add_broadcast_recipient(PacketHandle, const IPAddress& peer_addr, const PacketHeader& header);
108 
109 		// Call ack() when an ACK is received from the given peer for the given sequence number
110 		void		ack(const IPAddress& peer_addr, uint64_t sequence_no);
111 
112 		// after time_until_resend() milliseconds elapses, call resend() to resend the packets
113 		uint64_t	time_until_resend() const;
114 		void		resend(CommonNetwork& network);
115 
116 		// if has_packets() returns false, there's no need to periodically call resend()
has_packets() const117 		bool		has_packets() const { return !m_packets.empty(); }
118 	};
119 }
120 
121 #endif
122