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_INTERNET_GAMING_H
21 #define WL_NETWORK_INTERNET_GAMING_H
22 
23 #include <memory>
24 
25 #include "chat/chat.h"
26 #include "network/netclient.h"
27 #include "network/network.h"
28 
29 /// A simple network client struct
30 struct InternetClient {
31 	std::string name;
32 	std::string build_id;
33 	std::string game;
34 	std::string type;
35 };
36 
37 /// A simple network game struct
38 struct InternetGame {
39 	std::string name;
40 	std::string build_id;
41 	std::string connectable;
42 };
43 
44 /**
45  * The InternetGaming struct.
46  */
47 struct InternetGaming : public ChatProvider {
48 
49 	/// The only instance of InternetGaming -> the constructor is private by purpose!
50 	static InternetGaming& ref();
51 
52 	void reset();
53 
54 	// Login and logout
55 
56 	void initialize_connection();
57 
58 	/**
59 	 * Try to login on the metaserver.
60 	 * @param nick The preferred username. Another username might be chosen by the metaserver if
61 	 *             the requested one is already in use.
62 	 * @param authenticator If \c registered is \c true, this is the password. Otherwise, it is some
63 	 * unique
64 	 *             id the server can use to identify the user.
65 	 * @param metaserver The hostname of the metaserver.
66 	 * @param port The port number of the metaserver.
67 	 * @return Whether the login was successful.
68 	 */
69 	bool login(const std::string& nick,
70 	           const std::string& authenticator,
71 	           bool registered,
72 	           const std::string& metaserver,
73 	           uint32_t port);
74 	bool relogin();
75 	void logout(const std::string& msgcode = "CONNECTION_CLOSED");
76 
77 	/**
78 	 * Connects to the metaserver and checks the password without logging in.
79 	 *
80 	 * Note that the user might be logged in with another username and as unregistered
81 	 * if the user account is already in use by another client.
82 	 * @warning Resets the current connection.
83 	 * @param nick The username.
84 	 * @param pwd The password.
85 	 * @param metaserver The hostname of the metaserver.
86 	 * @param port The port number of the metaserver.
87 	 * @return Whether the password was valid.
88 	 */
89 	bool check_password(const std::string& nick,
90 	                    const std::string& pwd,
91 	                    const std::string& metaserver,
92 	                    uint32_t port);
93 
94 	/// \returns whether the client is logged in
logged_inInternetGaming95 	bool logged_in() {
96 		return (state_ == LOBBY) || (state_ == CONNECTING) || (state_ == IN_GAME);
97 	}
errorInternetGaming98 	bool error() {
99 		return (state_ == COMMUNICATION_ERROR);
100 	}
set_errorInternetGaming101 	void set_error() {
102 		state_ = COMMUNICATION_ERROR;
103 		gameupdate_ = true;
104 		clientupdate_ = true;
105 	}
106 
107 	void handle_metaserver_communication(bool relogin_on_error = true);
108 
109 	// Game specific functions
110 	/**
111 	 * Returns a pair containing up to two NetAddress'es of the game host to connect to.
112 	 * Contains two addresses when the host supports IPv4 and IPv6, one address when the host
113 	 * only supports one of the protocols, no addresses when no join-request was sent to
114 	 * the metaserver. "No address" means a default constructed address.
115 	 * Also returns the IPs of the relay server when trying to host a game.
116 	 * Use NetAddress::is_valid() to check whether a NetAddress has been default constructed.
117 	 * @return The addresses.
118 	 */
119 	const std::pair<NetAddress, NetAddress>& ips();
120 
121 	/**
122 	 * Blocks for some time until either the ips() method is able to return the IPs of the relay
123 	 * or an error occurred or the timeout is met.
124 	 * @return \c True iff ips() can return something.
125 	 */
126 	bool wait_for_ips();
127 
128 	/**
129 	 * Returns the password required to connect to the relay server as host.
130 	 */
131 	const std::string relay_password();
132 
133 	void join_game(const std::string& gamename);
134 	void open_game();
135 	void set_game_playing();
136 	void set_game_done();
137 
138 	// Informative functions for lobby
139 	bool update_for_games();
140 	const std::vector<InternetGame>* games();
141 	bool update_for_clients();
142 	const std::vector<InternetClient>* clients();
143 
144 	/// sets the name of the local server as shown in the games list
set_local_servernameInternetGaming145 	void set_local_servername(const std::string& name) {
146 		gamename_ = name;
147 	}
148 
149 	/// \returns the name of the local server
get_local_servernameInternetGaming150 	std::string& get_local_servername() {
151 		return gamename_;
152 	}
153 
154 	/// \returns the name of the local client
get_local_clientnameInternetGaming155 	std::string& get_local_clientname() {
156 		return clientname_;
157 	}
158 
159 	/// \returns the rights of the local client
get_local_clientrightsInternetGaming160 	std::string& get_local_clientrights() {
161 		return clientrights_;
162 	}
163 
164 	/// ChatProvider: sends a message via the metaserver.
165 	void send(const std::string&) override;
166 
167 	/// ChatProvider: adds the message to the message list and calls parent.
receiveInternetGaming168 	void receive(const ChatMessage& msg) {
169 		messages_.push_back(msg);
170 		Notifications::publish(msg);
171 	}
172 
173 	/// ChatProvider: returns the list of chatmessages.
get_messagesInternetGaming174 	const std::vector<ChatMessage>& get_messages() const override {
175 		return messages_;
176 	}
177 
178 	/// Silence the internet lobby chat if we are in game as we do not see the messages anyways
sound_offInternetGaming179 	bool sound_off() override {
180 		return state_ == IN_GAME;
181 	}
182 
183 	/// writes the ingame_system_chat_ messages to \arg msg and resets it afterwards
get_ingame_system_messagesInternetGaming184 	void get_ingame_system_messages(std::vector<ChatMessage>& msg) {
185 		msg = ingame_system_chat_;
186 		ingame_system_chat_.clear();
187 	}
188 
has_been_setInternetGaming189 	bool has_been_set() const override {
190 		return true;
191 	}
192 
193 	void format_and_add_chat(const std::string& from,
194 	                         const std::string& to,
195 	                         bool system,
196 	                         const std::string& msg);
197 
198 	bool valid_username(std::string);
199 
200 private:
201 	InternetGaming();
202 
203 	/**
204 	 * Temporarily creates a second connection to the metaserver.
205 	 * If the primary connection is an IPv6 connection, we also try
206 	 * an IPv4 connection to tell the metaserver our IP.
207 	 * This way, when we host a game later on, the metaserver
208 	 * knows how to reach us for both protocol versions.
209 	 * The established connection does a login, then the connection is
210 	 * immediately closed.
211 	 *
212 	 * If the primary connection already is IPv4, this method does nothing.
213 	 * Since we first try to connect with IPv6, another try is futile.
214 	 */
215 	void create_second_connection();
216 
217 	void handle_packet(RecvPacket& packet, bool relogin_on_error = true);
218 	void handle_failed_read();
219 
220 	// conversion functions
221 	bool str2bool(std::string);
222 	std::string bool2str(bool);
223 
224 	/**
225 	 * Does the real work of the login.
226 	 * \param relogin Whether this is a relogin. Only difference is that
227 	 *                on first login a greeting is shown.
228 	 */
229 	bool do_login(bool relogin = false);
230 
231 	/// The connection to the metaserver
232 	std::unique_ptr<NetClient> net;
233 
234 	/// Current state of this class
235 	enum { OFFLINE, CONNECTING, LOBBY, IN_GAME, COMMUNICATION_ERROR } state_;
236 
237 	/// data saved for possible relogin
238 	std::string authenticator_;
239 	bool reg_;
240 
241 	/// Password for connecting as host to a game on the relay server
242 	std::string relay_password_;
243 
244 	std::string meta_;
245 	uint16_t port_;
246 
247 	/// local clients name and rights
248 	std::string clientname_;
249 	std::string clientrights_;
250 
251 	/// information of the clients game
252 	std::string gamename_;
253 	/// The IPv4/v6 addresses of the game host we are / will be connected to.
254 	/// See InternetGaming::ips().
255 	std::pair<NetAddress, NetAddress> gameips_;
256 
257 	/// Metaserver information
258 	bool clientupdateonmetaserver_;
259 	bool gameupdateonmetaserver_;
260 	bool clientupdate_;
261 	bool gameupdate_;
262 	std::vector<InternetClient> clientlist_;
263 	std::vector<InternetGame> gamelist_;
264 	int32_t time_offset_;
265 
266 	/// ChatProvider: chat messages
267 	std::vector<ChatMessage> messages_;
268 	std::vector<ChatMessage> ingame_system_chat_;
269 
270 	/// An important response of the metaserver, the client is waiting for.
271 	std::string waitcmd_;
272 	int32_t waittimeout_;
273 
274 	/// Connection tracking specific variables
275 	time_t lastbrokensocket_[2];  /// last times when socket last broke in s.
276 	time_t lastping_;
277 };
278 
279 #endif  // end of include guard: WL_NETWORK_INTERNET_GAMING_H
280