1 /*
2  * Copyright (C) 2004-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #ifndef WL_NETWORK_NETWORK_H
21 #define WL_NETWORK_NETWORK_H
22 
23 #include <functional>
24 
25 #include <boost/asio.hpp>
26 #include <boost/lexical_cast.hpp>
27 
28 #include "base/wexception.h"
29 #include "io/streamread.h"
30 #include "io/streamwrite.h"
31 #include "logic/cmd_queue.h"
32 #include "network/network_protocol.h"
33 
34 constexpr size_t kNetworkBufferSize = 512;
35 
36 /**
37  * Simple structure to hold the IP address and port of a server.
38  * This structure must not contain a hostname but only IP addresses.
39  */
40 struct NetAddress {
41 	/**
42 	 * Tries to resolve the given hostname to an IPv4 address.
43 	 * \param[out] addr A NetAddress structure to write the result to,
44 	 *                  if resolution succeeds.
45 	 * \param hostname The name of the host.
46 	 * \param port The port on the host.
47 	 * \return \c True if the resolution succeeded, \c false otherwise.
48 	 */
49 	static bool resolve_to_v4(NetAddress* addr, const std::string& hostname, uint16_t port);
50 
51 	/**
52 	 * Tries to resolve the given hostname to an IPv6 address.
53 	 * \param[out] addr A NetAddress structure to write the result to,
54 	 *                  if resolution succeeds.
55 	 * \param hostname The name of the host.
56 	 * \param port The port on the host.
57 	 * \return \c True if the resolution succeeded, \c false otherwise.
58 	 */
59 	static bool resolve_to_v6(NetAddress* addr, const std::string& hostname, uint16_t port);
60 
61 	/**
62 	 * Parses the given string to an IP address.
63 	 * \param[out] addr A NetAddress structure to write the result to,
64 	 *                  if parsing succeeds.
65 	 * \param ip An IP address as string.
66 	 * \param port The port on the host.
67 	 * \return \c True if the parsing succeeded, \c false otherwise.
68 	 */
69 	static bool parse_ip(NetAddress* addr, const std::string& ip, uint16_t port);
70 
71 	/**
72 	 * Returns whether the stored IP is in IPv6 format.
73 	 * @return \c true if the stored IP is in IPv6 format, \c false otherwise.
74 	 *   If it isn't an IPv6 address, it is an IPv4 address.
75 	 */
76 	bool is_ipv6() const;
77 
78 	/**
79 	 * Returns whether valid IP address and port are stored.
80 	 * @return \c true if valid, \c false otherwise.
81 	 */
82 	bool is_valid() const;
83 
84 	boost::asio::ip::address ip;
85 	uint16_t port;
86 };
87 
88 using SyncReportCallback = std::function<void()>;
89 
90 /**
91  * This non-gamelogic command is used by \ref GameHost and \ref GameClient
92  * to schedule taking a synchronization hash.
93  */
94 struct CmdNetCheckSync : public Widelands::Command {
95 	CmdNetCheckSync(uint32_t dt, SyncReportCallback);
96 
97 	void execute(Widelands::Game&) override;
98 
idCmdNetCheckSync99 	Widelands::QueueCommandTypes id() const override {
100 		return Widelands::QueueCommandTypes::kNetCheckSync;
101 	}
102 
103 private:
104 	SyncReportCallback callback_;
105 };
106 
107 /**
108  * Keeping track of network time: This class answers the question of how
109  * far the local simulation time should proceed, given the history of network
110  * time messages forwarded to the \ref receive() method.
111  *
112  * In general, the time progresses as fast as given by the speed, but we
113  * introduce some elasticity to catch up with the network time if necessary,
114  * and we never advance simulation past the received network time.
115  */
116 class NetworkTime {
117 public:
118 	NetworkTime();
119 
120 	void reset(int32_t ntime);
121 	void fastforward();
122 
123 	void think(uint32_t speed);
124 	int32_t time() const;
125 	int32_t networktime() const;
126 	void receive(int32_t ntime);
127 
128 private:
129 	int32_t networktime_;
130 	int32_t time_;
131 
132 	uint32_t lastframe_;
133 
134 	/// This is an attempt to measure how far behind the network time we are.
135 	uint32_t latency_;
136 };
137 
138 /**
139  * Buffered StreamWrite object for assembling a packet that will be
140  * sent over the network.
141  */
142 struct SendPacket : public StreamWrite {
143 	SendPacket();
144 
145 	void reset();
146 
147 	void data(void const* data, size_t size) override;
148 
149 	size_t get_size() const;
150 
151 	uint8_t* get_data() const;
152 
153 private:
154 	// First two bytes are overwritten on call to get_data()
155 	mutable std::vector<uint8_t> buffer;
156 };
157 
158 /**
159  * One packet, as received from the network.
160  */
161 struct RecvPacket : public StreamRead {
162 public:
163 	size_t data(void* data, size_t bufsize) override;
164 	bool end_of_file() const override;
165 
166 private:
167 	friend class BufferedConnection;
168 	std::vector<uint8_t> buffer;
169 	size_t index_ = 0U;
170 };
171 
172 struct FilePart {
173 	char part[NETFILEPARTSIZE];
174 };
175 
176 struct NetTransferFile {
NetTransferFileNetTransferFile177 	NetTransferFile() : bytes(0), filename(""), md5sum("") {
178 	}
179 	~NetTransferFile() = default;
180 
181 	uint32_t bytes;
182 	std::string filename;
183 	std::string md5sum;
184 	std::vector<FilePart> parts;
185 };
186 
187 /**
188  * This exception is used internally during protocol handling to indicate
189  * that the connection should be terminated with a reasonable error message.
190  *
191  * If the network handler catches a different exception from std::exception,
192  * it assumes that it is due to malformed data sent by the server.
193  */
194 struct DisconnectException : public std::exception {
195 	explicit DisconnectException(const char* fmt, ...) PRINTF_FORMAT(2, 3);
196 
197 	const char* what() const noexcept override;
198 
199 private:
200 	std::string what_;
201 };
202 
203 /**
204  * This exception is used internally during protocol handling to indicate that the connection
205  * should be terminated because an unexpected message got received that is disallowed by the
206  * protocol.
207  */
208 struct ProtocolException : public std::exception {
ProtocolExceptionProtocolException209 	explicit ProtocolException(uint8_t code)
210 	   : what_(boost::lexical_cast<std::string>(static_cast<unsigned int>(code))) {
211 	}
212 
213 	/// \returns the command number of the received message
whatProtocolException214 	const char* what() const noexcept override {
215 		return what_.c_str();
216 	}
217 
218 private:
219 	const std::string what_;
220 };
221 
222 /**
223  * The priorities for sending data over the network when using a BufferedConnection.
224  * Data with low priority values is send first even when data with high priority values
225  * have been passed to a BufferedConnection first
226  */
227 // The values assigned to the entries are arbitrary, only their order is important
228 // No "enum class" on purpose since this has to be interpreted as ints (I need a known ordering)
229 enum NetPriority : uint8_t { kPing = 10, kNormal = 50, kFiletransfer = 100 };
230 
231 #endif  // end of include guard: WL_NETWORK_NETWORK_H
232