Merge lp:~widelands-dev/widelands/refac-netcode into lp:widelands

Proposed by Notabilis
Status: Merged
Merged at revision: 8353
Proposed branch: lp:~widelands-dev/widelands/refac-netcode
Merge into: lp:widelands
Diff against target: 2825 lines (+833/-488)
18 files modified
src/network/CMakeLists.txt (+4/-0)
src/network/gameclient.cc (+112/-126)
src/network/gameclient.h (+10/-10)
src/network/gamehost.cc (+167/-180)
src/network/gamehost.h (+11/-10)
src/network/internet_gaming.cc (+46/-61)
src/network/internet_gaming.h (+4/-8)
src/network/netclient.cc (+79/-0)
src/network/netclient.h (+91/-0)
src/network/nethost.cc (+117/-0)
src/network/nethost.h (+121/-0)
src/network/network.cc (+28/-36)
src/network/network.h (+14/-15)
src/network/network_lan_promotion.h (+2/-0)
src/network/network_protocol.h (+5/-5)
src/ui_fsmenu/internet_lobby.cc (+9/-28)
src/ui_fsmenu/netsetup_lan.h (+2/-0)
src/wlapplication.cc (+11/-9)
To merge this branch: bzr merge lp:~widelands-dev/widelands/refac-netcode
Reviewer Review Type Date Requested Status
GunChleoc Approve
SirVer Approve
Review via email: mp+323798@code.launchpad.net

Description of the change

Hint: You don't need to know anything about networking to review this.

Moving some code around to hide most SDLNet specific calls inside two classes. This branch should not change anything on the functionality but is a preparation for a future replacement of SDLNet with boost.asio.

Renamed the classes NetHost/NetClient to GameHost/GameClient and introduced new classes NetHost/NetClient with the "real" network calls (the SDLNet function calls). Also changed some related code segments in the hope of improving code quality.

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2161. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/230495286.
Appveyor build 1996. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_refac_netcode-1996.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2164. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/230634393.
Appveyor build 1999. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_refac_netcode-1999.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Added some ideas for small improvements in the comments.

Revision history for this message
Notabilis (notabilis27) wrote :

Thanks for the review! I included nearly all of them in the commit, except for you "Game or Net"-comment which was already correct.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Yes, I wasn't sure about that one.

Will download and do a bit of testing.

Revision history for this message
SirVer (sirver) wrote :

Reviewed the code. lgtm, I left a few nits in the code in the last commit. Grep for NOCOM please.

review: Approve
Revision history for this message
Notabilis (notabilis27) wrote :

Thanks, is done.
I used the *Impl structs to hide that we are using SDLNet, but admittedly it doesn't really matter.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Testing done.

@bunnybot merge

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/network/CMakeLists.txt'
2--- src/network/CMakeLists.txt 2017-02-28 12:59:39 +0000
3+++ src/network/CMakeLists.txt 2017-05-11 07:00:56 +0000
4@@ -6,6 +6,10 @@
5 internet_gaming_messages.cc
6 internet_gaming_messages.h
7 internet_gaming_protocol.h
8+ gameclient.cc
9+ gameclient.h
10+ gamehost.cc
11+ gamehost.h
12 netclient.cc
13 netclient.h
14 nethost.cc
15
16=== renamed file 'src/network/netclient.cc' => 'src/network/gameclient.cc'
17--- src/network/netclient.cc 2017-02-10 14:12:36 +0000
18+++ src/network/gameclient.cc 2017-05-11 07:00:56 +0000
19@@ -17,7 +17,7 @@
20 *
21 */
22
23-#include "network/netclient.h"
24+#include "network/gameclient.h"
25
26 #include <memory>
27
28@@ -53,19 +53,12 @@
29 #include "wui/interactive_player.h"
30 #include "wui/interactive_spectator.h"
31
32-struct NetClientImpl {
33+struct GameClientImpl {
34 GameSettings settings;
35
36 std::string localplayername;
37
38- /// The socket that connects us to the host
39- TCPsocket sock;
40-
41- /// Socket set used for selection
42- SDLNet_SocketSet sockset;
43-
44- /// Deserializer acts as a buffer for packets (reassembly/splitting up)
45- Deserializer deserializer;
46+ std::unique_ptr<NetClient> net;
47
48 /// Currently active modal panel. Receives an end_modal on disconnect
49 UI::Panel* modal;
50@@ -96,18 +89,16 @@
51 std::vector<ChatMessage> chatmessages;
52 };
53
54-NetClient::NetClient(IPaddress* const svaddr, const std::string& playername, bool internet)
55- : d(new NetClientImpl), internet_(internet) {
56- d->sock = SDLNet_TCP_Open(svaddr);
57- if (d->sock == nullptr)
58+GameClient::GameClient(const std::string& host, const uint16_t port, const std::string& playername, bool internet)
59+ : d(new GameClientImpl), internet_(internet) {
60+ d->net = NetClient::connect(host, port);
61+ if (!d->net || !d->net->is_connected()) {
62 throw WLWarning(_("Could not establish connection to host"),
63 _("Widelands could not establish a connection to the given "
64 "address.\n"
65 "Either no Widelands server was running at the supposed port or\n"
66 "the server shut down as you tried to connect."));
67-
68- d->sockset = SDLNet_AllocSocketSet(1);
69- SDLNet_TCP_AddSocket(d->sockset, d->sock);
70+ }
71
72 d->settings.playernum = UserSettings::not_connected();
73 d->settings.usernum = -2;
74@@ -122,22 +113,21 @@
75 d->settings.win_condition_script = d->settings.win_condition_scripts.front();
76 }
77
78-NetClient::~NetClient() {
79- if (d->sock != nullptr)
80+GameClient::~GameClient() {
81+ assert(d->net != nullptr);
82+ if (d->net->is_connected())
83 disconnect("CLIENT_LEFT_GAME", "", true, false);
84
85- SDLNet_FreeSocketSet(d->sockset);
86-
87 delete d;
88 }
89
90-void NetClient::run() {
91+void GameClient::run() {
92 SendPacket s;
93 s.unsigned_8(NETCMD_HELLO);
94 s.unsigned_8(NETWORK_PROTOCOL_VERSION);
95 s.string(d->localplayername);
96 s.string(build_id());
97- s.send(d->sock);
98+ d->net->send(s);
99
100 d->settings.multiplayer = true;
101
102@@ -221,7 +211,7 @@
103 }
104 }
105
106-void NetClient::think() {
107+void GameClient::think() {
108 handle_network();
109
110 if (d->game) {
111@@ -242,7 +232,7 @@
112 }
113 }
114
115-void NetClient::send_player_command(Widelands::PlayerCommand& pc) {
116+void GameClient::send_player_command(Widelands::PlayerCommand& pc) {
117 assert(d->game);
118 if (pc.sender() != d->settings.playernum + 1) {
119 delete &pc;
120@@ -255,7 +245,7 @@
121 s.unsigned_8(NETCMD_PLAYERCOMMAND);
122 s.signed_32(d->game->get_gametime());
123 pc.serialize(s);
124- s.send(d->sock);
125+ d->net->send(s);
126
127 d->lasttimestamp = d->game->get_gametime();
128 d->lasttimestamp_realtime = SDL_GetTicks();
129@@ -263,15 +253,15 @@
130 delete &pc;
131 }
132
133-int32_t NetClient::get_frametime() {
134+int32_t GameClient::get_frametime() {
135 return d->time.time() - d->game->get_gametime();
136 }
137
138-GameController::GameType NetClient::get_game_type() {
139+GameController::GameType GameClient::get_game_type() {
140 return GameController::GameType::NETCLIENT;
141 }
142
143-void NetClient::report_result(uint8_t player_nr,
144+void GameClient::report_result(uint8_t player_nr,
145 Widelands::PlayerEndResult result,
146 const std::string& info) {
147 // Send to game
148@@ -285,54 +275,54 @@
149 d->game->player_manager()->add_player_end_status(pes);
150 }
151
152-const GameSettings& NetClient::settings() {
153+const GameSettings& GameClient::settings() {
154 return d->settings;
155 }
156
157-void NetClient::set_scenario(bool) {
158-}
159-
160-bool NetClient::can_change_map() {
161- return false;
162-}
163-
164-bool NetClient::can_change_player_state(uint8_t const) {
165- return false;
166-}
167-
168-bool NetClient::can_change_player_tribe(uint8_t number) {
169+void GameClient::set_scenario(bool) {
170+}
171+
172+bool GameClient::can_change_map() {
173+ return false;
174+}
175+
176+bool GameClient::can_change_player_state(uint8_t const) {
177+ return false;
178+}
179+
180+bool GameClient::can_change_player_tribe(uint8_t number) {
181 return can_change_player_team(number);
182 }
183
184-bool NetClient::can_change_player_team(uint8_t number) {
185+bool GameClient::can_change_player_team(uint8_t number) {
186 return (number == d->settings.playernum) && !d->settings.scenario && !d->settings.savegame;
187 }
188
189-bool NetClient::can_change_player_init(uint8_t) {
190- return false;
191-}
192-
193-bool NetClient::can_launch() {
194- return false;
195-}
196-
197-void NetClient::set_player_state(uint8_t, PlayerSettings::State) {
198- // client is not allowed to do this
199-}
200-
201-void NetClient::set_player_ai(uint8_t, const std::string&, bool const /* random_ai */) {
202- // client is not allowed to do this
203-}
204-
205-void NetClient::next_player_state(uint8_t) {
206- // client is not allowed to do this
207-}
208-
209-void NetClient::set_map(const std::string&, const std::string&, uint32_t, bool) {
210- // client is not allowed to do this
211-}
212-
213-void NetClient::set_player_tribe(uint8_t number,
214+bool GameClient::can_change_player_init(uint8_t) {
215+ return false;
216+}
217+
218+bool GameClient::can_launch() {
219+ return false;
220+}
221+
222+void GameClient::set_player_state(uint8_t, PlayerSettings::State) {
223+ // client is not allowed to do this
224+}
225+
226+void GameClient::set_player_ai(uint8_t, const std::string&, bool const /* random_ai */) {
227+ // client is not allowed to do this
228+}
229+
230+void GameClient::next_player_state(uint8_t) {
231+ // client is not allowed to do this
232+}
233+
234+void GameClient::set_map(const std::string&, const std::string&, uint32_t, bool) {
235+ // client is not allowed to do this
236+}
237+
238+void GameClient::set_player_tribe(uint8_t number,
239 const std::string& tribe,
240 bool const random_tribe) {
241 if ((number != d->settings.playernum))
242@@ -343,10 +333,10 @@
243 s.unsigned_8(number);
244 s.string(tribe);
245 s.unsigned_8(random_tribe ? 1 : 0);
246- s.send(d->sock);
247+ d->net->send(s);
248 }
249
250-void NetClient::set_player_team(uint8_t number, Widelands::TeamNumber team) {
251+void GameClient::set_player_team(uint8_t number, Widelands::TeamNumber team) {
252 if ((number != d->settings.playernum))
253 return;
254
255@@ -354,14 +344,14 @@
256 s.unsigned_8(NETCMD_SETTING_CHANGETEAM);
257 s.unsigned_8(number);
258 s.unsigned_8(team);
259- s.send(d->sock);
260+ d->net->send(s);
261 }
262
263-void NetClient::set_player_closeable(uint8_t, bool) {
264+void GameClient::set_player_closeable(uint8_t, bool) {
265 // client is not allowed to do this
266 }
267
268-void NetClient::set_player_shared(uint8_t number, uint8_t player) {
269+void GameClient::set_player_shared(uint8_t number, uint8_t player) {
270 if ((number != d->settings.playernum))
271 return;
272
273@@ -369,10 +359,10 @@
274 s.unsigned_8(NETCMD_SETTING_CHANGESHARED);
275 s.unsigned_8(number);
276 s.unsigned_8(player);
277- s.send(d->sock);
278+ d->net->send(s);
279 }
280
281-void NetClient::set_player_init(uint8_t number, uint8_t) {
282+void GameClient::set_player_init(uint8_t number, uint8_t) {
283 if ((number != d->settings.playernum))
284 return;
285
286@@ -380,29 +370,29 @@
287 SendPacket s;
288 s.unsigned_8(NETCMD_SETTING_CHANGEINIT);
289 s.unsigned_8(number);
290- s.send(d->sock);
291+ d->net->send(s);
292 }
293
294-void NetClient::set_player_name(uint8_t, const std::string&) {
295+void GameClient::set_player_name(uint8_t, const std::string&) {
296 // until now the name is set before joining - if you allow a change in
297 // launchgame-menu, here properly should be a set_name function
298 }
299
300-void NetClient::set_player(uint8_t, const PlayerSettings&) {
301+void GameClient::set_player(uint8_t, const PlayerSettings&) {
302 // do nothing here - the request for a positionchange is send in
303 // set_player_number(uint8_t) to the host.
304 }
305
306-std::string NetClient::get_win_condition_script() {
307+std::string GameClient::get_win_condition_script() {
308 return d->settings.win_condition_script;
309 }
310
311-void NetClient::set_win_condition_script(const std::string&) {
312+void GameClient::set_win_condition_script(const std::string&) {
313 // Clients are not allowed to change this
314 NEVER_HERE();
315 }
316
317-void NetClient::set_player_number(uint8_t const number) {
318+void GameClient::set_player_number(uint8_t const number) {
319 // If the playernumber we want to switch to is our own, there is no need
320 // for sending a request to the host.
321 if (number == d->settings.playernum)
322@@ -417,18 +407,18 @@
323 SendPacket s;
324 s.unsigned_8(NETCMD_SETTING_CHANGEPOSITION);
325 s.unsigned_8(number);
326- s.send(d->sock);
327+ d->net->send(s);
328 }
329
330-uint32_t NetClient::real_speed() {
331+uint32_t GameClient::real_speed() {
332 return d->realspeed;
333 }
334
335-uint32_t NetClient::desired_speed() {
336+uint32_t GameClient::desired_speed() {
337 return d->desiredspeed;
338 }
339
340-void NetClient::set_desired_speed(uint32_t speed) {
341+void GameClient::set_desired_speed(uint32_t speed) {
342 if (speed > std::numeric_limits<uint16_t>::max())
343 speed = std::numeric_limits<uint16_t>::max();
344
345@@ -438,19 +428,19 @@
346 SendPacket s;
347 s.unsigned_8(NETCMD_SETSPEED);
348 s.unsigned_16(d->desiredspeed);
349- s.send(d->sock);
350+ d->net->send(s);
351 }
352 }
353
354 // Network games cannot be paused
355-bool NetClient::is_paused() {
356+bool GameClient::is_paused() {
357 return false;
358 }
359
360-void NetClient::set_paused(bool /* paused */) {
361+void GameClient::set_paused(bool /* paused */) {
362 }
363
364-void NetClient::receive_one_player(uint8_t const number, StreamRead& packet) {
365+void GameClient::receive_one_player(uint8_t const number, StreamRead& packet) {
366 if (number >= d->settings.players.size())
367 throw DisconnectException("PLAYER_UPDATE_FOR_N_E_P");
368
369@@ -466,7 +456,7 @@
370 player.shared_in = packet.unsigned_8();
371 }
372
373-void NetClient::receive_one_user(uint32_t const number, StreamRead& packet) {
374+void GameClient::receive_one_user(uint32_t const number, StreamRead& packet) {
375 if (number > d->settings.users.size())
376 throw DisconnectException("USER_UPDATE_FOR_N_E_U");
377
378@@ -485,18 +475,18 @@
379 }
380 }
381
382-void NetClient::send(const std::string& msg) {
383+void GameClient::send(const std::string& msg) {
384 SendPacket s;
385 s.unsigned_8(NETCMD_CHAT);
386 s.string(msg);
387- s.send(d->sock);
388+ d->net->send(s);
389 }
390
391-const std::vector<ChatMessage>& NetClient::get_messages() const {
392+const std::vector<ChatMessage>& GameClient::get_messages() const {
393 return d->chatmessages;
394 }
395
396-void NetClient::send_time() {
397+void GameClient::send_time() {
398 assert(d->game);
399
400 log("[Client]: sending timestamp: %i\n", d->game->get_gametime());
401@@ -504,19 +494,20 @@
402 SendPacket s;
403 s.unsigned_8(NETCMD_TIME);
404 s.signed_32(d->game->get_gametime());
405- s.send(d->sock);
406+ d->net->send(s);
407
408 d->lasttimestamp = d->game->get_gametime();
409 d->lasttimestamp_realtime = SDL_GetTicks();
410 }
411
412-void NetClient::syncreport() {
413- if (d->sock) {
414+void GameClient::syncreport() {
415+ assert(d->net != nullptr);
416+ if (d->net->is_connected()) {
417 SendPacket s;
418 s.unsigned_8(NETCMD_SYNCREPORT);
419 s.signed_32(d->game->get_gametime());
420 s.data(d->game->get_sync_hash().data, 16);
421- s.send(d->sock);
422+ d->net->send(s);
423 }
424 }
425
426@@ -525,7 +516,7 @@
427 *
428 * \note The caller must handle exceptions by closing the connection.
429 */
430-void NetClient::handle_packet(RecvPacket& packet) {
431+void GameClient::handle_packet(RecvPacket& packet) {
432 uint8_t cmd = packet.unsigned_8();
433
434 if (cmd == NETCMD_DISCONNECT) {
435@@ -555,7 +546,7 @@
436 case NETCMD_PING: {
437 SendPacket s;
438 s.unsigned_8(NETCMD_PONG);
439- s.send(d->sock);
440+ d->net->send(s);
441
442 log("[Client] Pong!\n");
443 break;
444@@ -611,7 +602,7 @@
445 // Yes we need the file!
446 SendPacket s;
447 s.unsigned_8(NETCMD_NEW_FILE_AVAILABLE);
448- s.send(d->sock);
449+ d->net->send(s);
450
451 if (file_)
452 delete file_;
453@@ -645,7 +636,7 @@
454 s.unsigned_8(NETCMD_FILE_PART);
455 s.unsigned_32(part);
456 s.string(file_->md5sum);
457- s.send(d->sock);
458+ d->net->send(s);
459
460 FilePart fp;
461
462@@ -688,12 +679,12 @@
463 // Something went wrong! We have to rerequest the file.
464 s.reset();
465 s.unsigned_8(NETCMD_NEW_FILE_AVAILABLE);
466- s.send(d->sock);
467+ d->net->send(s);
468 // Notify the players
469 s.reset();
470 s.unsigned_8(NETCMD_CHAT);
471 s.string(_("/me 's file failed md5 checksumming."));
472- s.send(d->sock);
473+ d->net->send(s);
474 g_fs->fs_unlink(file_->filename);
475 }
476 // Check file for validity
477@@ -722,7 +713,7 @@
478 s.unsigned_8(NETCMD_CHAT);
479 s.string(_("/me checked the received file. Although md5 check summing succeeded, "
480 "I can not handle the file."));
481- s.send(d->sock);
482+ d->net->send(s);
483 }
484 }
485 break;
486@@ -867,25 +858,21 @@
487 /**
488 * Handle all incoming network traffic.
489 */
490-void NetClient::handle_network() {
491+void GameClient::handle_network() {
492 // if this is an internet game, handle the metaserver network
493 if (internet_)
494 InternetGaming::ref().handle_metaserver_communication();
495 try {
496- while (d->sock != nullptr && SDLNet_CheckSockets(d->sockset, 0) > 0) {
497- // Perform only one read operation, then process all packets
498- // from this read. This ensures that we process DISCONNECT
499- // packets that are followed immediately by connection close.
500- if (!d->deserializer.read(d->sock)) {
501- disconnect("CONNECTION_LOST", "", false);
502- return;
503- }
504-
505- // Process all the packets from the last read
506- while (d->sock && d->deserializer.avail()) {
507- RecvPacket packet(d->deserializer);
508- handle_packet(packet);
509- }
510+ assert(d->net != nullptr);
511+ // Check if the connection is still open
512+ if (!d->net->is_connected()) {
513+ disconnect("CONNECTION_LOST", "", false);
514+ return;
515+ }
516+ // Process all available packets
517+ RecvPacket packet;
518+ while (d->net->try_receive(&packet)) {
519+ handle_packet(packet);
520 }
521 } catch (const DisconnectException& e) {
522 disconnect(e.what());
523@@ -896,13 +883,14 @@
524 }
525 }
526
527-void NetClient::disconnect(const std::string& reason,
528+void GameClient::disconnect(const std::string& reason,
529 const std::string& arg,
530 bool const sendreason,
531 bool const showmsg) {
532 log("[Client]: disconnect(%s, %s)\n", reason.c_str(), arg.c_str());
533
534- if (d->sock) {
535+ assert(d->net != nullptr);
536+ if (d->net->is_connected()) {
537 if (sendreason) {
538 SendPacket s;
539 s.unsigned_8(NETCMD_DISCONNECT);
540@@ -911,12 +899,10 @@
541 if (!arg.empty()) {
542 s.string(arg);
543 }
544- s.send(d->sock);
545+ d->net->send(s);
546 }
547
548- SDLNet_TCP_DelSocket(d->sockset, d->sock);
549- SDLNet_TCP_Close(d->sock);
550- d->sock = nullptr;
551+ d->net->close();
552 }
553
554 bool const trysave = showmsg && d->game;
555
556=== renamed file 'src/network/netclient.h' => 'src/network/gameclient.h'
557--- src/network/netclient.h 2017-02-10 14:12:36 +0000
558+++ src/network/gameclient.h 2017-05-11 07:00:56 +0000
559@@ -17,30 +17,30 @@
560 *
561 */
562
563-#ifndef WL_NETWORK_NETCLIENT_H
564-#define WL_NETWORK_NETCLIENT_H
565+#ifndef WL_NETWORK_GAMECLIENT_H
566+#define WL_NETWORK_GAMECLIENT_H
567
568 #include "chat/chat.h"
569 #include "logic/game_controller.h"
570 #include "logic/game_settings.h"
571-#include "network/network.h"
572+#include "network/netclient.h"
573
574-struct NetClientImpl;
575+struct GameClientImpl;
576
577 // TODO(unknown): Use composition instead of inheritance
578 /**
579- * NetClient manages the lifetime of a network game in which this computer
580+ * GameClient manages the lifetime of a network game in which this computer
581 * participates as a client.
582 *
583 * This includes running the game setup screen and the actual game after
584 * launch, as well as dealing with the actual network protocol.
585 */
586-struct NetClient : public GameController,
587+struct GameClient : public GameController,
588 public GameSettingsProvider,
589 private SyncCallback,
590 public ChatProvider {
591- NetClient(IPaddress*, const std::string& playername, bool internet = false);
592- virtual ~NetClient();
593+ GameClient(const std::string& host, const uint16_t port, const std::string& playername, bool internet = false);
594+ virtual ~GameClient();
595
596 void run();
597
598@@ -119,8 +119,8 @@
599 bool showmsg = true);
600
601 NetTransferFile* file_;
602- NetClientImpl* d;
603+ GameClientImpl* d;
604 bool internet_;
605 };
606
607-#endif // end of include guard: WL_NETWORK_NETCLIENT_H
608+#endif // end of include guard: WL_NETWORK_GAMECLIENT_H
609
610=== renamed file 'src/network/nethost.cc' => 'src/network/gamehost.cc'
611--- src/network/nethost.cc 2017-02-28 08:20:01 +0000
612+++ src/network/gamehost.cc 2017-05-11 07:00:56 +0000
613@@ -17,7 +17,7 @@
614 *
615 */
616
617-#include "network/nethost.h"
618+#include "network/gamehost.h"
619
620 #include <algorithm>
621 #include <memory>
622@@ -33,6 +33,7 @@
623 #include "ai/computer_player.h"
624 #include "base/i18n.h"
625 #include "base/md5.h"
626+#include "base/warning.h"
627 #include "base/wexception.h"
628 #include "build_info.h"
629 #include "chat/chat.h"
630@@ -64,7 +65,7 @@
631 #include "wui/interactive_spectator.h"
632
633 struct HostGameSettingsProvider : public GameSettingsProvider {
634- HostGameSettingsProvider(NetHost* const init_host) : host_(init_host), current_wincondition_(0) {
635+ HostGameSettingsProvider(GameHost* const init_host) : host_(init_host), current_wincondition_(0) {
636 }
637 ~HostGameSettingsProvider() {
638 }
639@@ -273,13 +274,13 @@
640 }
641
642 private:
643- NetHost* host_;
644+ GameHost* host_;
645 int16_t current_wincondition_;
646 std::vector<std::string> wincondition_scripts_;
647 };
648
649 struct HostChatProvider : public ChatProvider {
650- HostChatProvider(NetHost* const init_host) : h(init_host), kickClient(0) {
651+ HostChatProvider(GameHost* const init_host) : h(init_host), kickClient(0) {
652 }
653
654 void send(const std::string& msg) override {
655@@ -455,7 +456,7 @@
656 }
657
658 private:
659- NetHost* h;
660+ GameHost* h;
661 std::vector<ChatMessage> messages;
662 std::string kickUser;
663 uint32_t kickClient;
664@@ -463,8 +464,7 @@
665 };
666
667 struct Client {
668- TCPsocket sock;
669- Deserializer deserializer;
670+ NetHost::ConnectionId sock_id;
671 uint8_t playernum;
672 int16_t usernum;
673 std::string build_id;
674@@ -479,7 +479,7 @@
675 time_t lastdelta;
676 };
677
678-struct NetHostImpl {
679+struct GameHostImpl {
680 GameSettings settings;
681 std::string localplayername;
682 uint32_t localdesiredspeed;
683@@ -488,8 +488,7 @@
684 NetworkPlayerSettingsBackend npsb;
685
686 LanGamePromoter* promoter;
687- TCPsocket svsock;
688- SDLNet_SocketSet sockset;
689+ std::unique_ptr<NetHost> net;
690
691 /// List of connected clients. Note that clients are not in the same
692 /// order as players. In fact, a client must not be assigned to a player.
693@@ -530,14 +529,13 @@
694 Md5Checksum syncreport;
695 bool syncreport_arrived;
696
697- NetHostImpl(NetHost* const h)
698+ GameHostImpl(GameHost* const h)
699 : localdesiredspeed(0),
700 chat(h),
701 hp(h),
702 npsb(&hp),
703 promoter(nullptr),
704- svsock(nullptr),
705- sockset(nullptr),
706+ net(),
707 game(nullptr),
708 pseudo_networktime(0),
709 last_heartbeat(0),
710@@ -552,8 +550,8 @@
711 }
712 };
713
714-NetHost::NetHost(const std::string& playername, bool internet)
715- : d(new NetHostImpl(this)), internet_(internet), forced_pause_(false) {
716+GameHost::GameHost(const std::string& playername, bool internet)
717+ : d(new GameHostImpl(this)), internet_(internet), forced_pause_(false) {
718 log("[Host]: starting up.\n");
719
720 if (internet) {
721@@ -563,11 +561,13 @@
722 d->localplayername = playername;
723
724 // create a listening socket
725- IPaddress myaddr;
726- SDLNet_ResolveHost(&myaddr, nullptr, WIDELANDS_PORT);
727- d->svsock = SDLNet_TCP_Open(&myaddr);
728-
729- d->sockset = SDLNet_AllocSocketSet(16);
730+ d->net = NetHost::listen(WIDELANDS_PORT);
731+ if (d->net == nullptr) {
732+ // This might happen when the widelands socket is already in use
733+ throw WLWarning(_("Failed to start the server!"),
734+ _("Widelands could not start a server.\n"
735+ "Probably some other process is already running a server on our port."));
736+ }
737 d->promoter = new LanGamePromoter();
738 d->game = nullptr;
739 d->pseudo_networktime = 0;
740@@ -589,7 +589,7 @@
741 file_ = nullptr; // Initialize as 0 pointer - unfortunately needed in struct.
742 }
743
744-NetHost::~NetHost() {
745+GameHost::~GameHost() {
746 clear_computer_players();
747
748 while (!d->clients.empty()) {
749@@ -597,37 +597,33 @@
750 reaper();
751 }
752
753- SDLNet_FreeSocketSet(d->sockset);
754-
755 // close all open sockets
756- if (d->svsock != nullptr)
757- SDLNet_TCP_Close(d->svsock);
758-
759+ d->net.reset();
760 delete d->promoter;
761 delete d;
762 delete file_;
763 }
764
765-const std::string& NetHost::get_local_playername() const {
766+const std::string& GameHost::get_local_playername() const {
767 return d->localplayername;
768 }
769
770-int16_t NetHost::get_local_playerposition() {
771+int16_t GameHost::get_local_playerposition() {
772 return d->settings.users.at(0).position;
773 }
774
775-void NetHost::clear_computer_players() {
776+void GameHost::clear_computer_players() {
777 for (uint32_t i = 0; i < d->computerplayers.size(); ++i)
778 delete d->computerplayers.at(i);
779 d->computerplayers.clear();
780 }
781
782-void NetHost::init_computer_player(Widelands::PlayerNumber p) {
783+void GameHost::init_computer_player(Widelands::PlayerNumber p) {
784 d->computerplayers.push_back(ComputerPlayer::get_implementation(d->game->get_player(p)->get_ai())
785 ->instantiate(*d->game, p));
786 }
787
788-void NetHost::init_computer_players() {
789+void GameHost::init_computer_players() {
790 const Widelands::PlayerNumber nr_players = d->game->map().get_nrplayers();
791 iterate_players_existing_novar(p, nr_players, *d->game) {
792 if (p == d->settings.playernum + 1)
793@@ -643,7 +639,7 @@
794 }
795 }
796
797-void NetHost::run() {
798+void GameHost::run() {
799 // Fill the list of possible system messages
800 NetworkGamingMessages::fill_map();
801 FullscreenMenuLaunchMPG lm(&d->hp, this);
802@@ -721,8 +717,9 @@
803
804 d->committed_networktime = d->pseudo_networktime;
805
806- for (uint32_t i = 0; i < d->clients.size(); ++i)
807- d->clients.at(i).time = d->committed_networktime - 1;
808+ for (Client& client : d->clients) {
809+ client.time = d->committed_networktime - 1;
810+ }
811
812 // The call to check_hung_clients ensures that the game leaves the
813 // wait mode when there are no clients
814@@ -757,7 +754,7 @@
815 d->game = nullptr;
816 }
817
818-void NetHost::think() {
819+void GameHost::think() {
820 handle_network();
821
822 if (d->game) {
823@@ -789,12 +786,13 @@
824 }
825 }
826
827- for (uint32_t i = 0; i < d->computerplayers.size(); ++i)
828- d->computerplayers.at(i)->think();
829+ for (ComputerPlayer *cp : d->computerplayers) {
830+ cp->think();
831+ }
832 }
833 }
834
835-void NetHost::send_player_command(Widelands::PlayerCommand& pc) {
836+void GameHost::send_player_command(Widelands::PlayerCommand& pc) {
837 pc.set_duetime(d->committed_networktime + 1);
838
839 SendPacket s;
840@@ -814,7 +812,7 @@
841 * If it is a personal message it will only be send to the recipient and to
842 * the sender (to show that the message was actually sent).
843 */
844-void NetHost::send(ChatMessage msg) {
845+void GameHost::send(ChatMessage msg) {
846 if (msg.msg.empty())
847 return;
848
849@@ -850,7 +848,7 @@
850 s.string(msg.msg);
851 s.unsigned_8(1);
852 s.string(msg.recipient);
853- s.send(d->clients.at(clientnum).sock);
854+ d->net->send(d->clients.at(clientnum).sock_id, s);
855 log(
856 "[Host]: personal chat: from %s to %s\n", msg.sender.c_str(), msg.recipient.c_str());
857 } else {
858@@ -896,7 +894,7 @@
859 if (d->clients.at(j).usernum == static_cast<int16_t>(i))
860 break;
861 if (j < d->clients.size())
862- s.send(d->clients.at(j).sock);
863+ d->net->send(d->clients.at(j).sock_id, s);
864 else
865 // Better no wexception it would break the whole game
866 log("WARNING: user was found but no client is connected to it!\n");
867@@ -913,7 +911,7 @@
868 * - -1 if no client was found
869 * - -2 if the host is the client (has no client number)
870 */
871-int32_t NetHost::check_client(std::string name) {
872+int32_t GameHost::check_client(std::string name) {
873 // Check if the client is the host him-/herself
874 if (d->localplayername == name) {
875 return -2;
876@@ -943,13 +941,13 @@
877 * If the host sends a chat message with formation /kick <name> <reason>
878 * This function will handle this command and try to kick the user.
879 */
880-void NetHost::kick_user(uint32_t client, std::string reason) {
881+void GameHost::kick_user(uint32_t client, std::string reason) {
882 disconnect_client(client, "KICKED", true, reason);
883 }
884
885 /// Split up a user entered string in "cmd", "arg1" and "arg2"
886 /// \note the cmd must begin with "/"
887-void NetHost::split_command_array(const std::string& cmdarray,
888+void GameHost::split_command_array(const std::string& cmdarray,
889 std::string& cmd,
890 std::string& arg1,
891 std::string& arg2) {
892@@ -976,7 +974,7 @@
893 arg2 = "";
894 }
895
896-void NetHost::send_system_message_code(const std::string& code,
897+void GameHost::send_system_message_code(const std::string& code,
898 const std::string& a,
899 const std::string& b,
900 const std::string& c) {
901@@ -998,19 +996,19 @@
902 d->chat.receive(msg);
903 }
904
905-int32_t NetHost::get_frametime() {
906+int32_t GameHost::get_frametime() {
907 return d->time.time() - d->game->get_gametime();
908 }
909
910-GameController::GameType NetHost::get_game_type() {
911+GameController::GameType GameHost::get_game_type() {
912 return GameController::GameType::NETHOST;
913 }
914
915-const GameSettings& NetHost::settings() {
916+const GameSettings& GameHost::settings() {
917 return d->settings;
918 }
919
920-bool NetHost::can_launch() {
921+bool GameHost::can_launch() {
922 if (d->settings.mapname.empty())
923 return false;
924 if (d->settings.players.size() < 1)
925@@ -1027,16 +1025,16 @@
926 // all players must be connected to a controller (human/ai) or be closed.
927 // but not all should be closed!
928 bool one_not_closed = false;
929- for (size_t i = 0; i < d->settings.players.size(); ++i) {
930- if (d->settings.players.at(i).state != PlayerSettings::stateClosed)
931+ for (PlayerSettings& setting : d->settings.players) {
932+ if (setting.state != PlayerSettings::stateClosed)
933 one_not_closed = true;
934- if (d->settings.players.at(i).state == PlayerSettings::stateOpen)
935+ if (setting.state == PlayerSettings::stateOpen)
936 return false;
937 }
938 return one_not_closed;
939 }
940
941-void NetHost::set_map(const std::string& mapname,
942+void GameHost::set_map(const std::string& mapname,
943 const std::string& mapfilename,
944 uint32_t const maxplayers,
945 bool const savegame) {
946@@ -1144,7 +1142,7 @@
947 broadcast(s);
948 }
949
950-void NetHost::set_player_state(uint8_t const number,
951+void GameHost::set_player_state(uint8_t const number,
952 PlayerSettings::State const state,
953 bool const host) {
954 if (number >= d->settings.players.size())
955@@ -1202,7 +1200,7 @@
956 broadcast(s);
957 }
958
959-void NetHost::set_player_tribe(uint8_t const number,
960+void GameHost::set_player_tribe(uint8_t const number,
961 const std::string& tribe,
962 bool const random_tribe) {
963 if (number >= d->settings.players.size())
964@@ -1240,7 +1238,7 @@
965 log("Player %u attempted to change to tribe %s; not a valid tribe\n", number, tribe.c_str());
966 }
967
968-void NetHost::set_player_init(uint8_t const number, uint8_t const index) {
969+void GameHost::set_player_init(uint8_t const number, uint8_t const index) {
970 if (number >= d->settings.players.size())
971 return;
972
973@@ -1271,7 +1269,7 @@
974 NEVER_HERE();
975 }
976
977-void NetHost::set_player_ai(uint8_t number, const std::string& name, bool const random_ai) {
978+void GameHost::set_player_ai(uint8_t number, const std::string& name, bool const random_ai) {
979 if (number >= d->settings.players.size())
980 return;
981
982@@ -1287,7 +1285,7 @@
983 broadcast(s);
984 }
985
986-void NetHost::set_player_name(uint8_t const number, const std::string& name) {
987+void GameHost::set_player_name(uint8_t const number, const std::string& name) {
988 if (number >= d->settings.players.size())
989 return;
990
991@@ -1306,7 +1304,7 @@
992 broadcast(s);
993 }
994
995-void NetHost::set_player_closeable(uint8_t const number, bool closeable) {
996+void GameHost::set_player_closeable(uint8_t const number, bool closeable) {
997 if (number >= d->settings.players.size())
998 return;
999
1000@@ -1321,7 +1319,7 @@
1001 // uses it.
1002 }
1003
1004-void NetHost::set_player_shared(uint8_t number, uint8_t shared) {
1005+void GameHost::set_player_shared(uint8_t number, uint8_t shared) {
1006 if (number >= d->settings.players.size())
1007 return;
1008
1009@@ -1345,7 +1343,7 @@
1010 broadcast(s);
1011 }
1012
1013-void NetHost::set_player(uint8_t const number, const PlayerSettings& ps) {
1014+void GameHost::set_player(uint8_t const number, const PlayerSettings& ps) {
1015 if (number >= d->settings.players.size())
1016 return;
1017
1018@@ -1360,11 +1358,12 @@
1019 broadcast(s);
1020 }
1021
1022-void NetHost::set_player_number(uint8_t const number) {
1023+void GameHost::set_player_number(uint8_t const number) {
1024 switch_to_player(0, number);
1025 }
1026
1027-void NetHost::set_win_condition_script(const std::string& wc) {
1028+
1029+void GameHost::set_win_condition_script(const std::string& wc) {
1030 d->settings.win_condition_script = wc;
1031
1032 // Broadcast changes
1033@@ -1374,7 +1373,7 @@
1034 broadcast(s);
1035 }
1036
1037-void NetHost::switch_to_player(uint32_t user, uint8_t number) {
1038+void GameHost::switch_to_player(uint32_t user, uint8_t number) {
1039 if (number < d->settings.players.size() &&
1040 (d->settings.players.at(number).state != PlayerSettings::stateOpen &&
1041 d->settings.players.at(number).state != PlayerSettings::stateHuman))
1042@@ -1405,14 +1404,16 @@
1043 set_player_name(number, op.name + " " + name + " ");
1044 }
1045 d->settings.users.at(user).position = number;
1046- if (user == 0) // host
1047+ if (user == 0) { // host
1048 d->settings.playernum = number;
1049- else
1050- for (uint32_t j = 0; j < d->clients.size(); ++j)
1051- if (d->clients.at(j).usernum == static_cast<int16_t>(user)) {
1052- d->clients.at(j).playernum = number;
1053+ } else {
1054+ for (Client& client : d->clients) {
1055+ if (client.usernum == static_cast<int16_t>(user)) {
1056+ client.playernum = number;
1057 break;
1058 }
1059+ }
1060+ }
1061
1062 // Broadcast the user changes to everybody
1063 SendPacket s;
1064@@ -1422,7 +1423,7 @@
1065 broadcast(s);
1066 }
1067
1068-void NetHost::set_player_team(uint8_t number, Widelands::TeamNumber team) {
1069+void GameHost::set_player_team(uint8_t number, Widelands::TeamNumber team) {
1070 if (number >= d->settings.players.size())
1071 return;
1072 d->settings.players.at(number).team = team;
1073@@ -1435,26 +1436,26 @@
1074 broadcast(s);
1075 }
1076
1077-void NetHost::set_multiplayer_game_settings() {
1078+void GameHost::set_multiplayer_game_settings() {
1079 d->settings.scenario = false;
1080 d->settings.multiplayer = true;
1081 }
1082
1083-void NetHost::set_scenario(bool is_scenario) {
1084+void GameHost::set_scenario(bool is_scenario) {
1085 d->settings.scenario = is_scenario;
1086 }
1087
1088-uint32_t NetHost::real_speed() {
1089+uint32_t GameHost::real_speed() {
1090 if (d->waiting)
1091 return 0;
1092 return d->networkspeed;
1093 }
1094
1095-uint32_t NetHost::desired_speed() {
1096+uint32_t GameHost::desired_speed() {
1097 return d->localdesiredspeed;
1098 }
1099
1100-void NetHost::set_desired_speed(uint32_t const speed) {
1101+void GameHost::set_desired_speed(uint32_t const speed) {
1102 if (speed != d->localdesiredspeed) {
1103 d->localdesiredspeed = speed;
1104 update_network_speed();
1105@@ -1462,30 +1463,31 @@
1106 }
1107
1108 // Network games cannot be paused
1109-bool NetHost::is_paused() {
1110+bool GameHost::is_paused() {
1111 return false;
1112 }
1113
1114-void NetHost::set_paused(bool /* paused */) {
1115+void GameHost::set_paused(bool /* paused */) {
1116 }
1117
1118 // Send the packet to all properly connected clients
1119-void NetHost::broadcast(SendPacket& packet) {
1120+void GameHost::broadcast(SendPacket& packet) {
1121 for (const Client& client : d->clients) {
1122 if (client.playernum != UserSettings::not_connected()) {
1123- packet.send(client.sock);
1124+ assert(client.sock_id > 0);
1125+ d->net->send(client.sock_id, packet);
1126 }
1127 }
1128 }
1129
1130-void NetHost::write_setting_map(SendPacket& packet) {
1131+void GameHost::write_setting_map(SendPacket& packet) {
1132 packet.string(d->settings.mapname);
1133 packet.string(d->settings.mapfilename);
1134 packet.unsigned_8(d->settings.savegame ? 1 : 0);
1135 packet.unsigned_8(d->settings.scenario ? 1 : 0);
1136 }
1137
1138-void NetHost::write_setting_player(SendPacket& packet, uint8_t const number) {
1139+void GameHost::write_setting_player(SendPacket& packet, uint8_t const number) {
1140 PlayerSettings& player = d->settings.players.at(number);
1141 packet.unsigned_8(static_cast<uint8_t>(player.state));
1142 packet.string(player.name);
1143@@ -1498,19 +1500,19 @@
1144 packet.unsigned_8(player.shared_in);
1145 }
1146
1147-void NetHost::write_setting_all_players(SendPacket& packet) {
1148+void GameHost::write_setting_all_players(SendPacket& packet) {
1149 packet.unsigned_8(d->settings.players.size());
1150 for (uint8_t i = 0; i < d->settings.players.size(); ++i)
1151 write_setting_player(packet, i);
1152 }
1153
1154-void NetHost::write_setting_user(SendPacket& packet, uint32_t const number) {
1155+void GameHost::write_setting_user(SendPacket& packet, uint32_t const number) {
1156 packet.string(d->settings.users.at(number).name);
1157 packet.signed_32(d->settings.users.at(number).position);
1158 packet.unsigned_8(d->settings.users.at(number).ready ? 1 : 0);
1159 }
1160
1161-void NetHost::write_setting_all_users(SendPacket& packet) {
1162+void GameHost::write_setting_all_users(SendPacket& packet) {
1163 packet.unsigned_8(d->settings.users.size());
1164 for (uint32_t i = 0; i < d->settings.users.size(); ++i)
1165 write_setting_user(packet, i);
1166@@ -1521,7 +1523,7 @@
1167 *
1168 * \returns true if the data was written, else false
1169 */
1170-bool NetHost::write_map_transfer_info(SendPacket& s, std::string mapfilename) {
1171+bool GameHost::write_map_transfer_info(SendPacket& s, std::string mapfilename) {
1172 // TODO(unknown): not yet able to handle directory type maps / savegames
1173 if (g_fs->is_directory(mapfilename)) {
1174 log("Map/Save is a directory! No way for making it available a.t.m.!\n");
1175@@ -1544,7 +1546,7 @@
1176 *
1177 * \return a name for the given player.
1178 */
1179-std::string NetHost::get_computer_player_name(uint8_t const playernum) {
1180+std::string GameHost::get_computer_player_name(uint8_t const playernum) {
1181 std::string name;
1182 uint32_t suffix = playernum;
1183 do {
1184@@ -1559,7 +1561,7 @@
1185 * If \p ignoreplayer < UserSettings::highest_playernum(), the user with this
1186 * number will be ignored.
1187 */
1188-bool NetHost::has_user_name(const std::string& name, uint8_t ignoreplayer) {
1189+bool GameHost::has_user_name(const std::string& name, uint8_t ignoreplayer) {
1190 for (uint32_t i = 0; i < d->settings.users.size(); ++i)
1191 if (i != ignoreplayer && d->settings.users.at(i).name == name)
1192 return true;
1193@@ -1576,13 +1578,13 @@
1194 }
1195
1196 /// Respond to a client's Hello message.
1197-void NetHost::welcome_client(uint32_t const number, std::string& playername) {
1198+void GameHost::welcome_client(uint32_t const number, std::string& playername) {
1199 assert(number < d->clients.size());
1200
1201 Client& client = d->clients.at(number);
1202
1203 assert(client.playernum == UserSettings::not_connected());
1204- assert(client.sock);
1205+ assert(client.sock_id > 0);
1206
1207 // The client gets its own initial data set.
1208 client.playernum = UserSettings::none();
1209@@ -1624,52 +1626,51 @@
1210 s.unsigned_8(NETCMD_HELLO);
1211 s.unsigned_8(NETWORK_PROTOCOL_VERSION);
1212 s.unsigned_32(client.usernum);
1213- s.send(client.sock);
1214-
1215+ d->net->send(client.sock_id, s);
1216 // even if the network protocol is the same, the data might be different.
1217 if (client.build_id != build_id())
1218 send_system_message_code("DIFFERENT_WL_VERSION", effective_name, client.build_id, build_id());
1219-
1220 // Send information about currently selected map / savegame
1221 s.reset();
1222+
1223 s.unsigned_8(NETCMD_SETTING_MAP);
1224 write_setting_map(s);
1225- s.send(client.sock);
1226+ d->net->send(client.sock_id, s);
1227
1228 // If possible, offer the map / savegame as transfer
1229 if (file_) {
1230 s.reset();
1231 if (write_map_transfer_info(s, file_->filename))
1232- s.send(client.sock);
1233+ d->net->send(client.sock_id, s);
1234 }
1235
1236 // Send the tribe information to the new client.
1237 s.reset();
1238 s.unsigned_8(NETCMD_SETTING_TRIBES);
1239 s.unsigned_8(d->settings.tribes.size());
1240- for (uint8_t i = 0; i < d->settings.tribes.size(); ++i) {
1241- s.string(d->settings.tribes[i].name);
1242- size_t const nr_initializations = d->settings.tribes[i].initializations.size();
1243+ for (const TribeBasicInfo& tribe : d->settings.tribes) {
1244+ s.string(tribe.name);
1245+ size_t const nr_initializations = tribe.initializations.size();
1246 s.unsigned_8(nr_initializations);
1247- for (uint8_t j = 0; j < nr_initializations; ++j)
1248- s.string(d->settings.tribes[i].initializations[j].script);
1249+ for (const TribeBasicInfo::Initialization& init : tribe.initializations)
1250+ s.string(init.script);
1251 }
1252- s.send(client.sock);
1253+ d->net->send(client.sock_id, s);
1254
1255 s.reset();
1256 s.unsigned_8(NETCMD_SETTING_ALLPLAYERS);
1257 write_setting_all_players(s);
1258- s.send(client.sock);
1259+ d->net->send(client.sock_id, s);
1260
1261 s.reset();
1262 s.unsigned_8(NETCMD_SETTING_ALLUSERS);
1263 write_setting_all_users(s);
1264- s.send(client.sock);
1265+ d->net->send(client.sock_id, s);
1266
1267 s.reset();
1268 s.unsigned_8(NETCMD_WIN_CONDITION);
1269 s.string(d->settings.win_condition_script);
1270- s.send(client.sock);
1271+ d->net->send(client.sock_id, s);
1272
1273 // Broadcast new information about the player to everybody
1274 s.reset();
1275@@ -1688,7 +1689,7 @@
1276 send_system_message_code("CLIENT_HAS_JOINED_GAME", effective_name);
1277 }
1278
1279-void NetHost::committed_network_time(int32_t const time) {
1280+void GameHost::committed_network_time(int32_t const time) {
1281 assert(time - d->committed_networktime > 0);
1282
1283 d->committed_networktime = time;
1284@@ -1699,7 +1700,7 @@
1285 request_sync_reports();
1286 }
1287
1288-void NetHost::receive_client_time(uint32_t const number, int32_t const time) {
1289+void GameHost::receive_client_time(uint32_t const number, int32_t const time) {
1290 assert(number < d->clients.size());
1291
1292 Client& client = d->clients.at(number);
1293@@ -1723,7 +1724,7 @@
1294 }
1295 }
1296
1297-void NetHost::check_hung_clients() {
1298+void GameHost::check_hung_clients() {
1299 assert(d->game != nullptr);
1300
1301 int nrdelayed = 0;
1302@@ -1788,7 +1789,7 @@
1303 }
1304 }
1305
1306-void NetHost::broadcast_real_speed(uint32_t const speed) {
1307+void GameHost::broadcast_real_speed(uint32_t const speed) {
1308 assert(speed <= std::numeric_limits<uint16_t>::max());
1309
1310 SendPacket s;
1311@@ -1802,7 +1803,7 @@
1312 * given the desired speed of all clients.
1313 *
1314 * This function is supposed to be the only code that ever changes
1315- * \ref NetHostImpl::networkspeed.
1316+ * \ref GameHostImpl::networkspeed.
1317 *
1318 * The current implementation picks the median, or the average of
1319 * lower and upper median.
1320@@ -1816,7 +1817,7 @@
1321 * network games, as sudden pauses would be distracting to other players. A
1322 * hard interruption of the game can be achieved with the forced pause.
1323 */
1324-void NetHost::update_network_speed() {
1325+void GameHost::update_network_speed() {
1326 uint32_t const oldnetworkspeed = d->networkspeed;
1327
1328 // First check if a pause was forced by the host
1329@@ -1828,9 +1829,9 @@
1330 std::vector<uint32_t> speeds;
1331
1332 speeds.push_back(d->localdesiredspeed);
1333- for (uint32_t i = 0; i < d->clients.size(); ++i) {
1334- if (d->clients.at(i).playernum <= UserSettings::highest_playernum())
1335- speeds.push_back(d->clients.at(i).desiredspeed);
1336+ for (const Client& client : d->clients) {
1337+ if (client.playernum <= UserSettings::highest_playernum())
1338+ speeds.push_back(client.desiredspeed);
1339 }
1340 assert(!speeds.empty());
1341
1342@@ -1859,15 +1860,16 @@
1343 /**
1344 * Request sync reports from all clients at the next possible time.
1345 */
1346-void NetHost::request_sync_reports() {
1347+void GameHost::request_sync_reports() {
1348 assert(!d->syncreport_pending);
1349
1350 d->syncreport_pending = true;
1351 d->syncreport_arrived = false;
1352 d->syncreport_time = d->committed_networktime + 1;
1353
1354- for (uint32_t i = 0; i < d->clients.size(); ++i)
1355- d->clients.at(i).syncreport_arrived = false;
1356+ for (Client& client : d->clients) {
1357+ client.syncreport_arrived = false;
1358+ }
1359
1360 log("[Host]: Requesting sync reports for time %i\n", d->syncreport_time);
1361
1362@@ -1884,15 +1886,15 @@
1363 /**
1364 * Check whether all sync reports have arrived, and if so, compare.
1365 */
1366-void NetHost::check_sync_reports() {
1367+void GameHost::check_sync_reports() {
1368 assert(d->syncreport_pending);
1369
1370 if (!d->syncreport_arrived)
1371 return;
1372
1373- for (uint32_t i = 0; i < d->clients.size(); ++i) {
1374- if (d->clients.at(i).playernum != UserSettings::not_connected() &&
1375- !d->clients.at(i).syncreport_arrived)
1376+ for (const Client& client : d->clients) {
1377+ if (client.playernum != UserSettings::not_connected() &&
1378+ !client.syncreport_arrived)
1379 return;
1380 }
1381
1382@@ -1925,7 +1927,7 @@
1383 }
1384 }
1385
1386-void NetHost::syncreport() {
1387+void GameHost::syncreport() {
1388 assert(d->game->get_gametime() == static_cast<uint32_t>(d->syncreport_time));
1389
1390 d->syncreport = d->game->get_sync_hash();
1391@@ -1934,21 +1936,16 @@
1392 check_sync_reports();
1393 }
1394
1395-void NetHost::handle_network() {
1396- TCPsocket sock;
1397+void GameHost::handle_network() {
1398
1399 if (d->promoter != nullptr)
1400 d->promoter->run();
1401
1402+
1403 // Check for new connections.
1404- while (d->svsock != nullptr && (sock = SDLNet_TCP_Accept(d->svsock)) != nullptr) {
1405- log("[Host]: Received a connection request\n");
1406-
1407- SDLNet_TCP_AddSocket(d->sockset, sock);
1408-
1409- Client peer;
1410-
1411- peer.sock = sock;
1412+ Client peer;
1413+ assert(d->net != nullptr);
1414+ while (d->net->try_accept(&peer.sock_id)) {
1415 peer.playernum = UserSettings::not_connected();
1416 peer.syncreport_arrived = false;
1417 peer.desiredspeed = 1000;
1418@@ -1965,36 +1962,29 @@
1419 // that we should show in game as well.
1420 std::vector<ChatMessage> msgs;
1421 InternetGaming::ref().get_ingame_system_messages(msgs);
1422- for (uint8_t i = 0; i < msgs.size(); ++i)
1423- send(msgs.at(i));
1424+ for (const ChatMessage& msg : msgs)
1425+ send(msg);
1426+ }
1427+
1428+ for (size_t i = 0; i < d->clients.size(); ++i) {
1429+ if (!d->net->is_connected(d->clients.at(i).sock_id))
1430+ disconnect_client(i, "CONNECTION_LOST", false);
1431 }
1432
1433 // Check if we hear anything from our clients
1434- while (SDLNet_CheckSockets(d->sockset, 0) > 0) {
1435- for (size_t i = 0; i < d->clients.size(); ++i) {
1436- try {
1437- Client& client = d->clients.at(i);
1438-
1439- while (client.sock && SDLNet_SocketReady(client.sock)) {
1440- if (!client.deserializer.read(client.sock)) {
1441- disconnect_client(i, "CONNECTION_LOST", false);
1442- break;
1443- }
1444-
1445- // Handle all available packets immediately after each read, so
1446- // that we do not miss any commands (especially DISCONNECT...).
1447- while (client.sock && client.deserializer.avail()) {
1448- RecvPacket r(client.deserializer);
1449- handle_packet(i, r);
1450- }
1451- }
1452- } catch (const DisconnectException& e) {
1453- disconnect_client(i, e.what());
1454- } catch (const ProtocolException& e) {
1455- disconnect_client(i, "PROTOCOL_EXCEPTION", true, e.what());
1456- } catch (const std::exception& e) {
1457- disconnect_client(i, "MALFORMED_COMMANDS", true, e.what());
1458+ RecvPacket packet;
1459+ for (size_t i = 0; i < d->clients.size(); ++i) {
1460+ try {
1461+ while (d->net->try_receive(d->clients.at(i).sock_id, &packet)) {
1462+ handle_packet(i, packet);
1463 }
1464+ // Thrown by handle_packet()
1465+ } catch (const DisconnectException& e) {
1466+ disconnect_client(i, e.what());
1467+ } catch (const ProtocolException& e) {
1468+ disconnect_client(i, "PROTOCOL_EXCEPTION", true, e.what());
1469+ } catch (const std::exception& e) {
1470+ disconnect_client(i, "MALFORMED_COMMANDS", true, e.what());
1471 }
1472 }
1473
1474@@ -2019,7 +2009,7 @@
1475 * \param i the client number
1476 * \param r the received packet
1477 */
1478-void NetHost::handle_packet(uint32_t const i, RecvPacket& r) {
1479+void GameHost::handle_packet(uint32_t const i, RecvPacket& r) {
1480 Client& client = d->clients.at(i);
1481 uint8_t const cmd = r.unsigned_8();
1482
1483@@ -2041,13 +2031,12 @@
1484 // Send PING back
1485 SendPacket s;
1486 s.unsigned_8(NETCMD_METASERVER_PING);
1487- s.send(client.sock);
1488+ d->net->send(client.sock_id, s);
1489
1490 // Remove metaserver from list of clients
1491 client.playernum = UserSettings::not_connected();
1492- SDLNet_TCP_DelSocket(d->sockset, client.sock);
1493- SDLNet_TCP_Close(client.sock);
1494- client.sock = nullptr;
1495+ d->net->close(client.sock_id);
1496+ client.sock_id = 0;
1497 return;
1498 }
1499
1500@@ -2207,7 +2196,7 @@
1501 throw DisconnectException("REQUEST_OF_N_E_FILE");
1502 send_system_message_code(
1503 "STARTED_SENDING_FILE", file_->filename, d->settings.users.at(client.usernum).name);
1504- send_file_part(client.sock, 0);
1505+ send_file_part(client.sock_id, 0);
1506 // Remember client as "currently receiving file"
1507 d->settings.users[client.usernum].ready = false;
1508 SendPacket s;
1509@@ -2246,7 +2235,7 @@
1510 send_system_message_code("SENDING_FILE_PART",
1511 (boost::format("%i/%i") % part % (file_->parts.size() + 1)).str(),
1512 file_->filename, d->settings.users.at(client.usernum).name);
1513- send_file_part(client.sock, part);
1514+ send_file_part(client.sock_id, part);
1515 break;
1516 }
1517
1518@@ -2255,7 +2244,7 @@
1519 }
1520 }
1521
1522-void NetHost::send_file_part(TCPsocket csock, uint32_t part) {
1523+void GameHost::send_file_part(NetHost::ConnectionId csock_id, uint32_t part) {
1524 assert(part < file_->parts.size());
1525
1526 uint32_t left = file_->bytes - NETFILEPARTSIZE * part;
1527@@ -2267,14 +2256,14 @@
1528 s.unsigned_32(part);
1529 s.unsigned_32(size);
1530 s.data(file_->parts[part].part, size);
1531- s.send(csock);
1532+ d->net->send(csock_id, s);
1533 }
1534
1535-void NetHost::disconnect_player_controller(uint8_t const number, const std::string& name) {
1536+void GameHost::disconnect_player_controller(uint8_t const number, const std::string& name) {
1537 log("[Host]: disconnect_player_controller(%u, %s)\n", number, name.c_str());
1538
1539- for (uint32_t i = 0; i < d->settings.users.size(); ++i) {
1540- if (d->settings.users.at(i).position == number) {
1541+ for (const UserSettings& setting : d->settings.users) {
1542+ if (setting.position == number) {
1543 if (!d->game) {
1544 // Remove player name
1545 PlayerSettings& p = d->settings.players.at(number);
1546@@ -2294,7 +2283,7 @@
1547 init_computer_player(number + 1);
1548 }
1549
1550-void NetHost::disconnect_client(uint32_t const number,
1551+void GameHost::disconnect_client(uint32_t const number,
1552 const std::string& reason,
1553 bool const sendreason,
1554 const std::string& arg) {
1555@@ -2330,7 +2319,7 @@
1556
1557 log("[Host]: disconnect_client(%u, %s, %s)\n", number, reason.c_str(), arg.c_str());
1558
1559- if (client.sock) {
1560+ if (client.sock_id > 0) {
1561 if (sendreason) {
1562 SendPacket s;
1563 s.unsigned_8(NETCMD_DISCONNECT);
1564@@ -2338,12 +2327,11 @@
1565 s.string(reason);
1566 if (!arg.empty())
1567 s.string(arg);
1568- s.send(client.sock);
1569+ d->net->send(client.sock_id, s);
1570 }
1571
1572- SDLNet_TCP_DelSocket(d->sockset, client.sock);
1573- SDLNet_TCP_Close(client.sock);
1574- client.sock = nullptr;
1575+ d->net->close(client.sock_id);
1576+ client.sock_id = 0;
1577 }
1578
1579 if (d->game) {
1580@@ -2358,16 +2346,16 @@
1581 * Calls this when you're certain that nobody is holding any client indices or
1582 * iterators, since this function will invalidate them.
1583 */
1584-void NetHost::reaper() {
1585+void GameHost::reaper() {
1586 uint32_t index = 0;
1587 while (index < d->clients.size())
1588- if (d->clients.at(index).sock)
1589+ if (d->clients.at(index).sock_id > 0)
1590 ++index;
1591 else
1592 d->clients.erase(d->clients.begin() + index);
1593 }
1594
1595-void NetHost::report_result(uint8_t p_nr,
1596+void GameHost::report_result(uint8_t p_nr,
1597 Widelands::PlayerEndResult result,
1598 const std::string& info) {
1599 // Send to game
1600@@ -2382,8 +2370,7 @@
1601
1602 // there might be more than one client that control this Widelands player
1603 // and maybe even none -> computer player
1604- for (uint16_t i = 0; i < d->settings.users.size(); ++i) {
1605- UserSettings& user = d->settings.users.at(i);
1606+ for (UserSettings& user : d->settings.users) {
1607 if (user.position == p_nr - 1) {
1608 user.result = result;
1609 user.win_condition_string = info;
1610@@ -2393,6 +2380,6 @@
1611 }
1612 }
1613
1614- log("NetHost::report_result(%d, %u, %s)\n", player->player_number(),
1615+ log("GameHost::report_result(%d, %u, %s)\n", player->player_number(),
1616 static_cast<uint8_t>(result), info.c_str());
1617 }
1618
1619=== renamed file 'src/network/nethost.h' => 'src/network/gamehost.h'
1620--- src/network/nethost.h 2017-02-10 14:12:36 +0000
1621+++ src/network/gamehost.h 2017-05-11 07:00:56 +0000
1622@@ -17,28 +17,29 @@
1623 *
1624 */
1625
1626-#ifndef WL_NETWORK_NETHOST_H
1627-#define WL_NETWORK_NETHOST_H
1628+#ifndef WL_NETWORK_GAMEHOST_H
1629+#define WL_NETWORK_GAMEHOST_H
1630
1631 #include "logic/game_controller.h"
1632 #include "logic/game_settings.h"
1633 #include "logic/widelands.h"
1634+#include "network/nethost.h"
1635 #include "network/network.h"
1636
1637 struct ChatMessage;
1638-struct NetHostImpl;
1639+struct GameHostImpl;
1640 struct Client;
1641
1642 /**
1643- * NetHost manages the lifetime of a network game in which this computer
1644+ * GameHost manages the lifetime of a network game in which this computer
1645 * acts as the host.
1646 *
1647 * This includes running the game setup screen and the actual game after
1648 * launch, as well as dealing with the actual network protocol.
1649 */
1650-struct NetHost : public GameController, private SyncCallback {
1651- NetHost(const std::string& playername, bool internet = false);
1652- virtual ~NetHost();
1653+struct GameHost : public GameController, private SyncCallback {
1654+ GameHost(const std::string& playername, bool internet = false);
1655+ virtual ~GameHost();
1656
1657 void run();
1658 const std::string& get_local_playername() const;
1659@@ -125,7 +126,7 @@
1660
1661 void handle_packet(uint32_t i, RecvPacket&);
1662 void handle_network();
1663- void send_file_part(TCPsocket, uint32_t);
1664+ void send_file_part(NetHost::ConnectionId client_sock_id, uint32_t part);
1665
1666 void check_hung_clients();
1667 void broadcast_real_speed(uint32_t speed);
1668@@ -153,9 +154,9 @@
1669 void reaper();
1670
1671 NetTransferFile* file_;
1672- NetHostImpl* d;
1673+ GameHostImpl* d;
1674 bool internet_;
1675 bool forced_pause_;
1676 };
1677
1678-#endif // end of include guard: WL_NETWORK_NETHOST_H
1679+#endif // end of include guard: WL_NETWORK_GAMEHOST_H
1680
1681=== modified file 'src/network/internet_gaming.cc'
1682--- src/network/internet_gaming.cc 2017-02-10 15:37:44 +0000
1683+++ src/network/internet_gaming.cc 2017-05-11 07:00:56 +0000
1684@@ -34,8 +34,7 @@
1685 /// will ensure
1686 /// that only one instance is running at time.
1687 InternetGaming::InternetGaming()
1688- : sock_(nullptr),
1689- sockset_(nullptr),
1690+ : net(nullptr),
1691 state_(OFFLINE),
1692 reg_(false),
1693 port_(INTERNET_GAMING_PORT),
1694@@ -58,8 +57,7 @@
1695
1696 /// resets all stored variables without the chat messages for a clean new login (not relogin)
1697 void InternetGaming::reset() {
1698- sock_ = nullptr;
1699- sockset_ = nullptr;
1700+ net.reset();
1701 state_ = OFFLINE;
1702 pwd_ = "";
1703 reg_ = false;
1704@@ -97,27 +95,13 @@
1705 void InternetGaming::initialize_connection() {
1706 // First of all try to connect to the metaserver
1707 log("InternetGaming: Connecting to the metaserver.\n");
1708- IPaddress peer;
1709- if (hostent* const he = gethostbyname(meta_.c_str())) {
1710- peer.host = (reinterpret_cast<in_addr*>(he->h_addr_list[0]))->s_addr;
1711- DIAG_OFF("-Wold-style-cast")
1712- peer.port = htons(port_);
1713- DIAG_ON("-Wold-style-cast")
1714- } else
1715- throw WLWarning(
1716- _("Connection problem"), "%s", _("Widelands could not connect to the metaserver."));
1717-
1718- SDLNet_ResolveHost(&peer, meta_.c_str(), port_);
1719- sock_ = SDLNet_TCP_Open(&peer);
1720- if (sock_ == nullptr)
1721+ net = NetClient::connect(meta_, port_);
1722+ if (!net || !net->is_connected())
1723 throw WLWarning(_("Could not establish connection to host"),
1724 _("Widelands could not establish a connection to the given address.\n"
1725 "Either there was no metaserver running at the supposed port or\n"
1726 "your network setup is broken."));
1727
1728- sockset_ = SDLNet_AllocSocketSet(1);
1729- SDLNet_TCP_AddSocket(sockset_, sock_);
1730-
1731 // Of course not 100% true, but we just care about an answer at all, so we reset this tracker
1732 lastping_ = time(nullptr);
1733 }
1734@@ -148,7 +132,7 @@
1735 s.string(bool2str(reg));
1736 if (reg)
1737 s.string(pwd);
1738- s.send(sock_);
1739+ net->send(s);
1740
1741 // Now let's see, whether the metaserver is answering
1742 uint32_t const secs = time(nullptr);
1743@@ -191,7 +175,7 @@
1744 s.string(bool2str(reg_));
1745 if (reg_)
1746 s.string(pwd_);
1747- s.send(sock_);
1748+ net->send(s);
1749
1750 // Now let's see, whether the metaserver is answering
1751 uint32_t const secs = time(nullptr);
1752@@ -235,7 +219,7 @@
1753 SendPacket s;
1754 s.string(IGPCMD_DISCONNECT);
1755 s.string(msgcode);
1756- s.send(sock_);
1757+ net->send(s);
1758
1759 const std::string& msg = InternetGamingMessages::get_message(msgcode);
1760 log("InternetGaming: logout(%s)\n", msg.c_str());
1761@@ -278,20 +262,16 @@
1762 if (error())
1763 return;
1764 try {
1765- while (sock_ != nullptr && SDLNet_CheckSockets(sockset_, 0) > 0) {
1766- // Perform only one read operation, then process all packets
1767- // from this read. This ensures that we process DISCONNECT
1768- // packets that are followed immediately by connection close.
1769- if (!deserializer_.read(sock_)) {
1770- handle_failed_read();
1771- return;
1772- }
1773-
1774- // Process all the packets from the last read
1775- while (sock_ && deserializer_.avail()) {
1776- RecvPacket packet(deserializer_);
1777- handle_packet(packet);
1778- }
1779+ assert(net != nullptr);
1780+ // Check if the connection is still open
1781+ if (!net->is_connected()) {
1782+ handle_failed_read();
1783+ return;
1784+ }
1785+ // Process all available packets
1786+ RecvPacket packet;
1787+ while (net->try_receive(&packet)) {
1788+ handle_packet(packet);
1789 }
1790 } catch (const std::exception& e) {
1791 logout((boost::format(_("Something went wrong: %s")) % e.what()).str());
1792@@ -303,7 +283,7 @@
1793 if (clientupdateonmetaserver_) {
1794 SendPacket s;
1795 s.string(IGPCMD_CLIENTS);
1796- s.send(sock_);
1797+ net->send(s);
1798
1799 clientupdateonmetaserver_ = false;
1800 }
1801@@ -311,7 +291,7 @@
1802 if (gameupdateonmetaserver_) {
1803 SendPacket s;
1804 s.string(IGPCMD_GAMES);
1805- s.send(sock_);
1806+ net->send(s);
1807
1808 gameupdateonmetaserver_ = false;
1809 }
1810@@ -434,7 +414,7 @@
1811 // Client received a PING and should immediately PONG as requested
1812 SendPacket s;
1813 s.string(IGPCMD_PONG);
1814- s.send(sock_);
1815+ net->send(s);
1816
1817 lastping_ = time(nullptr);
1818 }
1819@@ -475,12 +455,13 @@
1820 gamelist_.push_back(*ing);
1821
1822 bool found = false;
1823- for (std::vector<InternetGame>::size_type j = 0; j < old.size(); ++j)
1824- if (old[j].name == ing->name) {
1825+ for (InternetGame& old_game : old) {
1826+ if (old_game.name == ing->name) {
1827 found = true;
1828- old[j].name = "";
1829+ old_game.name = "";
1830 break;
1831 }
1832+ }
1833 if (!found)
1834 format_and_add_chat(
1835 "", "", true,
1836@@ -490,11 +471,13 @@
1837 ing = nullptr;
1838 }
1839
1840- for (std::vector<InternetGame>::size_type i = 0; i < old.size(); ++i)
1841- if (old[i].name.size())
1842+ for (InternetGame& old_game : old) {
1843+ if (old_game.name.size()) {
1844 format_and_add_chat(
1845 "", "", true,
1846- (boost::format(_("The game %s has been closed")) % old[i].name).str());
1847+ (boost::format(_("The game %s has been closed")) % old_game.name).str());
1848+ }
1849+ }
1850
1851 gameupdate_ = true;
1852 }
1853@@ -522,12 +505,13 @@
1854
1855 bool found =
1856 old.empty(); // do not show all clients, if this instance is the actual change
1857- for (std::vector<InternetClient>::size_type j = 0; j < old.size(); ++j)
1858- if (old[j].name == inc->name) {
1859+ for (InternetClient& client : old) {
1860+ if (client.name == inc->name) {
1861 found = true;
1862- old[j].name = "";
1863+ client.name = "";
1864 break;
1865 }
1866+ }
1867 if (!found)
1868 format_and_add_chat(
1869 "", "", true, (boost::format(_("%s joined the lobby")) % inc->name).str());
1870@@ -536,11 +520,12 @@
1871 inc = nullptr;
1872 }
1873
1874- for (std::vector<InternetClient>::size_type i = 0; i < old.size(); ++i)
1875- if (old[i].name.size())
1876+ for (InternetClient& client : old) {
1877+ if (client.name.size()) {
1878 format_and_add_chat(
1879- "", "", true, (boost::format(_("%s left the lobby")) % old[i].name).str());
1880-
1881+ "", "", true, (boost::format(_("%s left the lobby")) % client.name).str());
1882+ }
1883+ }
1884 clientupdate_ = true;
1885 }
1886
1887@@ -618,7 +603,7 @@
1888 SendPacket s;
1889 s.string(IGPCMD_GAME_CONNECT);
1890 s.string(gamename);
1891- s.send(sock_);
1892+ net->send(s);
1893 gamename_ = gamename;
1894 log("InternetGaming: Client tries to join a game with the name %s\n", gamename_.c_str());
1895 state_ = IN_GAME;
1896@@ -637,7 +622,7 @@
1897 s.string(IGPCMD_GAME_OPEN);
1898 s.string(gamename_);
1899 s.string("1024"); // Used to be maxclients, no longer used.
1900- s.send(sock_);
1901+ net->send(s);
1902 log("InternetGaming: Client opened a game with the name %s.\n", gamename_.c_str());
1903 state_ = IN_GAME;
1904
1905@@ -653,7 +638,7 @@
1906
1907 SendPacket s;
1908 s.string(IGPCMD_GAME_START);
1909- s.send(sock_);
1910+ net->send(s);
1911 log("InternetGaming: Client announced the start of the game %s.\n", gamename_.c_str());
1912
1913 // From now on we wait for a reply from the metaserver
1914@@ -670,7 +655,7 @@
1915
1916 SendPacket s;
1917 s.string(IGPCMD_GAME_DISCONNECT);
1918- s.send(sock_);
1919+ net->send(s);
1920
1921 gameip_ = "";
1922 state_ = LOBBY;
1923@@ -767,14 +752,14 @@
1924 }
1925 // send the request to change the motd
1926 m.string(arg);
1927- m.send(sock_);
1928+ net->send(s);
1929 return;
1930 } else if (cmd == "announcement") {
1931 // send the request to change the motd
1932 SendPacket m;
1933 m.string(IGPCMD_ANNOUNCEMENT);
1934 m.string(arg);
1935- m.send(sock_);
1936+ net->send(s);
1937 return;
1938 } else
1939 // let everything else pass
1940@@ -786,7 +771,7 @@
1941 s.string("");
1942 }
1943
1944- s.send(sock_);
1945+ net->send(s);
1946 }
1947
1948 /**
1949@@ -827,7 +812,7 @@
1950
1951 receive(c);
1952 if (system && (state_ == IN_GAME)) {
1953- // Save system chat messages seperately as well, so the nethost can import and show them in
1954+ // Save system chat messages separately as well, so the nethost can import and show them in
1955 // game;
1956 c.msg = "METASERVER: " + msg;
1957 ingame_system_chat_.push_back(c);
1958
1959=== modified file 'src/network/internet_gaming.h'
1960--- src/network/internet_gaming.h 2017-01-25 18:55:59 +0000
1961+++ src/network/internet_gaming.h 2017-05-11 07:00:56 +0000
1962@@ -20,6 +20,7 @@
1963 #ifndef WL_NETWORK_INTERNET_GAMING_H
1964 #define WL_NETWORK_INTERNET_GAMING_H
1965
1966+#include <memory>
1967 #include <string>
1968 #include <vector>
1969
1970@@ -31,6 +32,7 @@
1971 #include "build_info.h"
1972 #include "chat/chat.h"
1973 #include "network/internet_gaming_protocol.h"
1974+#include "network/netclient.h"
1975 #include "network/network.h"
1976 #include "network/network_lan_promotion.h"
1977
1978@@ -158,14 +160,8 @@
1979
1980 void format_and_add_chat(std::string from, std::string to, bool system, std::string msg);
1981
1982- /// The socket that connects us to the host
1983- TCPsocket sock_;
1984-
1985- /// Socket set used for selection
1986- SDLNet_SocketSet sockset_;
1987-
1988- /// Deserializer acts as a buffer for packets (reassembly/splitting up)
1989- Deserializer deserializer_;
1990+ /// The connection to the metaserver
1991+ std::unique_ptr<NetClient> net;
1992
1993 /// Current state of this class
1994 enum { OFFLINE, CONNECTING, LOBBY, IN_GAME, COMMUNICATION_ERROR } state_;
1995
1996=== added file 'src/network/netclient.cc'
1997--- src/network/netclient.cc 1970-01-01 00:00:00 +0000
1998+++ src/network/netclient.cc 2017-05-11 07:00:56 +0000
1999@@ -0,0 +1,79 @@
2000+#include "network/netclient.h"
2001+
2002+#include <memory>
2003+
2004+#include "base/log.h"
2005+
2006+std::unique_ptr<NetClient> NetClient::connect(const std::string& ip_address, const uint16_t port) {
2007+ std::unique_ptr<NetClient> ptr(new NetClient(ip_address, port));
2008+ if (ptr->is_connected()) {
2009+ return ptr;
2010+ } else {
2011+ ptr.reset();
2012+ return ptr;
2013+ }
2014+}
2015+
2016+NetClient::~NetClient() {
2017+ if (is_connected())
2018+ close();
2019+ if (sockset_ != nullptr)
2020+ SDLNet_FreeSocketSet(sockset_);
2021+}
2022+
2023+bool NetClient::is_connected() const {
2024+ return sock_ != nullptr;
2025+}
2026+
2027+void NetClient::close() {
2028+ if (!is_connected())
2029+ return;
2030+ SDLNet_TCP_DelSocket(sockset_, sock_);
2031+ SDLNet_TCP_Close(sock_);
2032+ sock_ = nullptr;
2033+}
2034+
2035+bool NetClient::try_receive(RecvPacket *packet) {
2036+ if (!is_connected())
2037+ return false;
2038+
2039+ uint8_t buffer[512];
2040+ while (SDLNet_CheckSockets(sockset_, 0) > 0) {
2041+
2042+ const int32_t bytes = SDLNet_TCP_Recv(sock_, buffer, sizeof(buffer));
2043+ if (bytes <= 0) {
2044+ // Error while receiving
2045+ close();
2046+ return false;
2047+ }
2048+
2049+ deserializer_.read_data(buffer, bytes);
2050+ }
2051+ // Get one packet from the deserializer
2052+ return deserializer_.write_packet(packet);
2053+}
2054+
2055+void NetClient::send(const SendPacket& packet) {
2056+ if (is_connected()) {
2057+ SDLNet_TCP_Send(sock_, packet.get_data(), packet.get_size());
2058+ }
2059+}
2060+
2061+NetClient::NetClient(const std::string& ip_address, const uint16_t port)
2062+ : sock_(nullptr), sockset_(nullptr), deserializer_() {
2063+
2064+ IPaddress addr;
2065+ if (SDLNet_ResolveHost(&addr, ip_address.c_str(), port) != 0) {
2066+ log("[Client]: Failed to resolve host address %s:%u.\n", ip_address.c_str(), port);
2067+ return;
2068+ }
2069+ log("[Client]: Trying to connect to %s:%u ... ", ip_address.c_str(), port);
2070+ sock_ = SDLNet_TCP_Open(&addr);
2071+ if (is_connected()) {
2072+ log("success\n");
2073+ sockset_ = SDLNet_AllocSocketSet(1);
2074+ SDLNet_TCP_AddSocket(sockset_, sock_);
2075+ } else {
2076+ log("failed\n");
2077+ }
2078+}
2079
2080=== added file 'src/network/netclient.h'
2081--- src/network/netclient.h 1970-01-01 00:00:00 +0000
2082+++ src/network/netclient.h 2017-05-11 07:00:56 +0000
2083@@ -0,0 +1,91 @@
2084+/*
2085+ * Copyright (C) 2008-2017 by the Widelands Development Team
2086+ *
2087+ * This program is free software; you can redistribute it and/or
2088+ * modify it under the terms of the GNU General Public License
2089+ * as published by the Free Software Foundation; either version 2
2090+ * of the License, or (at your option) any later version.
2091+ *
2092+ * This program is distributed in the hope that it will be useful,
2093+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2094+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2095+ * GNU General Public License for more details.
2096+ *
2097+ * You should have received a copy of the GNU General Public License
2098+ * along with this program; if not, write to the Free Software
2099+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2100+ *
2101+ */
2102+
2103+#ifndef WL_NETWORK_NETCLIENT_H
2104+#define WL_NETWORK_NETCLIENT_H
2105+
2106+#include <memory>
2107+
2108+#include <SDL_net.h>
2109+
2110+#include "network/network.h"
2111+
2112+/**
2113+ * NetClient manages the network connection for a network game in which this computer
2114+ * participates as a client.
2115+ */
2116+class NetClient {
2117+ public:
2118+ /**
2119+ * Tries to establish a connection to the given host.
2120+ * @param ip_address A hostname or an IPv4 address as string.
2121+ * @param port The port to connect to.
2122+ * @return A pointer to a connected \c NetClient object or a nullptr if the connection failed.
2123+ */
2124+ static std::unique_ptr<NetClient> connect(const std::string& ip_address,
2125+ const uint16_t port);
2126+
2127+ /**
2128+ * Closes the connection.
2129+ * If you want to send a goodbye-message to the host, do so before freeing the object.
2130+ */
2131+ ~NetClient();
2132+
2133+ /**
2134+ * Returns whether the client is connected.
2135+ * @return \c true if the connection is open, \c false otherwise.
2136+ */
2137+ bool is_connected() const;
2138+
2139+ /**
2140+ * Closes the connection.
2141+ * If you want to send a goodbye-message to the host, do so before calling this.
2142+ */
2143+ void close();
2144+
2145+ /**
2146+ * Tries to receive a packet.
2147+ * @param packet A packet that should be overwritten with the received data.
2148+ * @return \c true if a packet is available, \c false otherwise.
2149+ * The given packet is only modified when \c true is returned.
2150+ * Calling this on a closed connection will return false.
2151+ */
2152+ bool try_receive(RecvPacket *packet);
2153+
2154+ /**
2155+ * Sends a packet.
2156+ * Calling this on a closed connection will silently fail.
2157+ * @param packet The packet to send.
2158+ */
2159+ void send(const SendPacket& packet);
2160+
2161+ private:
2162+ NetClient(const std::string& ip_address, const uint16_t port);
2163+
2164+ /// The socket that connects us to the host
2165+ TCPsocket sock_;
2166+
2167+ /// Socket set used for selection
2168+ SDLNet_SocketSet sockset_;
2169+
2170+ /// Deserializer acts as a buffer for packets (reassembly/splitting up)
2171+ Deserializer deserializer_;
2172+};
2173+
2174+#endif // end of include guard: WL_NETWORK_NETCLIENT_H
2175
2176=== added file 'src/network/nethost.cc'
2177--- src/network/nethost.cc 1970-01-01 00:00:00 +0000
2178+++ src/network/nethost.cc 2017-05-11 07:00:56 +0000
2179@@ -0,0 +1,117 @@
2180+#include "network/nethost.h"
2181+
2182+#include <memory>
2183+
2184+#include "base/log.h"
2185+
2186+NetHost::Client::Client(TCPsocket sock)
2187+ : socket(sock), deserializer() {
2188+}
2189+
2190+std::unique_ptr<NetHost> NetHost::listen(const uint16_t port) {
2191+ std::unique_ptr<NetHost> ptr(new NetHost(port));
2192+ if (ptr->is_listening()) {
2193+ return ptr;
2194+ } else {
2195+ ptr.reset();
2196+ return ptr;
2197+ }
2198+}
2199+
2200+NetHost::~NetHost() {
2201+ stop_listening();
2202+ while (!clients_.empty()) {
2203+ close(clients_.begin()->first);
2204+ }
2205+ SDLNet_FreeSocketSet(sockset_);
2206+}
2207+
2208+
2209+bool NetHost::is_listening() const {
2210+ return svrsock_ != nullptr;
2211+}
2212+
2213+bool NetHost::is_connected(const ConnectionId id) const {
2214+ return clients_.count(id) > 0;
2215+}
2216+
2217+void NetHost::stop_listening() {
2218+ if (!is_listening())
2219+ return;
2220+ SDLNet_TCP_DelSocket(sockset_, svrsock_);
2221+ SDLNet_TCP_Close(svrsock_);
2222+ svrsock_ = nullptr;
2223+}
2224+
2225+void NetHost::close(const ConnectionId id) {
2226+ auto iter_client = clients_.find(id);
2227+ if (iter_client == clients_.end()) {
2228+ // Not connected anyway
2229+ return;
2230+ }
2231+ SDLNet_TCP_DelSocket(sockset_, iter_client->second.socket);
2232+ SDLNet_TCP_Close(iter_client->second.socket);
2233+ clients_.erase(iter_client);
2234+}
2235+
2236+bool NetHost::try_accept(ConnectionId *new_id) {
2237+ if (!is_listening())
2238+ return false;
2239+
2240+ TCPsocket sock = SDLNet_TCP_Accept(svrsock_);
2241+ // No client wants to connect
2242+ if (sock == nullptr)
2243+ return false;
2244+ SDLNet_TCP_AddSocket(sockset_, sock);
2245+ ConnectionId id = next_id_++;
2246+ assert(id > 0);
2247+ assert(clients_.count(id) == 0);
2248+ clients_.insert(std::make_pair(id, Client(sock)));
2249+ assert(clients_.count(id) == 1);
2250+ *new_id = id;
2251+ return true;
2252+}
2253+
2254+bool NetHost::try_receive(const ConnectionId id, RecvPacket *packet) {
2255+
2256+ // Always read all available data into buffers
2257+ uint8_t buffer[512];
2258+ while (SDLNet_CheckSockets(sockset_, 0) > 0) {
2259+ for (auto& e : clients_) {
2260+ if (SDLNet_SocketReady(e.second.socket)) {
2261+ const int32_t bytes = SDLNet_TCP_Recv(e.second.socket, buffer, sizeof(buffer));
2262+ if (bytes <= 0) {
2263+ // Error while receiving
2264+ close(e.first);
2265+ // We have to run the for-loop again since we modified the map
2266+ break;
2267+ }
2268+
2269+ e.second.deserializer.read_data(buffer, bytes);
2270+ }
2271+ }
2272+ }
2273+
2274+ // Now check whether there is data for the requested client
2275+ if (!is_connected(id))
2276+ return false;
2277+
2278+ // Get one packet from the deserializer
2279+ return clients_.at(id).deserializer.write_packet(packet);
2280+}
2281+
2282+void NetHost::send(const ConnectionId id, const SendPacket& packet) {
2283+ if (is_connected(id)) {
2284+ SDLNet_TCP_Send(clients_.at(id).socket, packet.get_data(), packet.get_size());
2285+ }
2286+}
2287+
2288+NetHost::NetHost(const uint16_t port)
2289+ : svrsock_(nullptr), sockset_(nullptr), next_id_(1) {
2290+
2291+ IPaddress myaddr;
2292+ SDLNet_ResolveHost(&myaddr, nullptr, port);
2293+ svrsock_ = SDLNet_TCP_Open(&myaddr);
2294+ // Maximal 16 sockets! This mean we can have at most 15 clients_ in our game (+ metaserver)
2295+ sockset_ = SDLNet_AllocSocketSet(16);
2296+}
2297
2298=== added file 'src/network/nethost.h'
2299--- src/network/nethost.h 1970-01-01 00:00:00 +0000
2300+++ src/network/nethost.h 2017-05-11 07:00:56 +0000
2301@@ -0,0 +1,121 @@
2302+/*
2303+ * Copyright (C) 2008-2017 by the Widelands Development Team
2304+ *
2305+ * This program is free software; you can redistribute it and/or
2306+ * modify it under the terms of the GNU General Public License
2307+ * as published by the Free Software Foundation; either version 2
2308+ * of the License, or (at your option) any later version.
2309+ *
2310+ * This program is distributed in the hope that it will be useful,
2311+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2312+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2313+ * GNU General Public License for more details.
2314+ *
2315+ * You should have received a copy of the GNU General Public License
2316+ * along with this program; if not, write to the Free Software
2317+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2318+ *
2319+ */
2320+
2321+#ifndef WL_NETWORK_NETHOST_H
2322+#define WL_NETWORK_NETHOST_H
2323+
2324+#include <map>
2325+#include <memory>
2326+
2327+#include <SDL_net.h>
2328+
2329+#include "network/network.h"
2330+
2331+/**
2332+ * NetHost manages the client connections of a network game in which this computer
2333+ * participates as a server.
2334+ */
2335+class NetHost {
2336+ public:
2337+
2338+ using ConnectionId = uint32_t;
2339+
2340+ /**
2341+ * Tries to listen on the given port.
2342+ * @param port The port to listen on.
2343+ * @return A pointer to a listening \c NetHost object or a nullptr if the connection failed.
2344+ */
2345+ static std::unique_ptr<NetHost> listen(const uint16_t port);
2346+
2347+ /**
2348+ * Closes the server.
2349+ */
2350+ ~NetHost();
2351+
2352+ /**
2353+ * Returns whether the server is started and is listening.
2354+ * @return \c true if the server is listening, \c false otherwise.
2355+ */
2356+ bool is_listening() const;
2357+
2358+ /**
2359+ * Returns whether the given client is connected.
2360+ * @param The id of the client to check.
2361+ * @return \c true if the connection is open, \c false otherwise.
2362+ */
2363+ bool is_connected(ConnectionId id) const;
2364+
2365+ /**
2366+ * Stops listening for connections.
2367+ */
2368+ void stop_listening();
2369+
2370+ /**
2371+ * Closes the connection to the given client.
2372+ * @param id The id of the client to close the connection to.
2373+ */
2374+ void close(ConnectionId id);
2375+
2376+ /**
2377+ * Tries to accept a new client.
2378+ * @param new_id The connection id of the new client will be stored here.
2379+ * @return \c true if a client has connected, \c false otherwise.
2380+ * The given id is only modified when \c true is returned.
2381+ * Calling this on a closed server will return false.
2382+ * The returned id is always greater than 0.
2383+ */
2384+ bool try_accept(ConnectionId *new_id);
2385+
2386+ /**
2387+ * Tries to receive a packet.
2388+ * @param id The connection id of the client that should be received.
2389+ * @param packet A packet that should be overwritten with the received data.
2390+ * @return \c true if a packet is available, \c false otherwise.
2391+ * The given packet is only modified when \c true is returned.
2392+ * Calling this on a closed connection will return false.
2393+ */
2394+ bool try_receive(ConnectionId id, RecvPacket *packet);
2395+
2396+ /**
2397+ * Sends a packet.
2398+ * Calling this on a closed connection will silently fail.
2399+ * @param id The connection id of the client that should be sent to.
2400+ * @param packet The packet to send.
2401+ */
2402+ void send(ConnectionId id, const SendPacket& packet);
2403+
2404+ private:
2405+
2406+ NetHost(const uint16_t port);
2407+
2408+ class Client {
2409+ public:
2410+ Client(TCPsocket sock);
2411+
2412+ TCPsocket socket;
2413+ Deserializer deserializer;
2414+ };
2415+
2416+ TCPsocket svrsock_;
2417+ SDLNet_SocketSet sockset_;
2418+ std::map<NetHost::ConnectionId, Client> clients_;
2419+ NetHost::ConnectionId next_id_;
2420+};
2421+
2422+#endif // end of include guard: WL_NETWORK_NETHOST_H
2423
2424=== modified file 'src/network/network.cc'
2425--- src/network/network.cc 2017-01-25 18:55:59 +0000
2426+++ src/network/network.cc 2017-05-11 07:00:56 +0000
2427@@ -117,11 +117,21 @@
2428 buffer.push_back(0); // this will finally be the length of the packet
2429 buffer.push_back(0);
2430 }
2431+
2432 for (size_t idx = 0; idx < size; ++idx)
2433 buffer.push_back(static_cast<const uint8_t*>(packet_data)[idx]);
2434 }
2435
2436-void SendPacket::send(TCPsocket sock) {
2437+void SendPacket::reset() {
2438+ buffer.clear();
2439+}
2440+
2441+size_t SendPacket::get_size() const {
2442+ return buffer.size();
2443+}
2444+
2445+uint8_t* SendPacket::get_data() const {
2446+
2447 uint32_t const length = buffer.size();
2448
2449 assert(length < 0x10000);
2450@@ -130,29 +140,11 @@
2451 buffer[0] = length >> 8;
2452 buffer[1] = length & 0xFF;
2453
2454- if (sock)
2455- SDLNet_TCP_Send(sock, &(buffer[0]), buffer.size());
2456-}
2457-
2458-void SendPacket::reset() {
2459- buffer.clear();
2460+ return &(buffer[0]);
2461 }
2462
2463 /*** class RecvPacket ***/
2464
2465-RecvPacket::RecvPacket(Deserializer& des) {
2466- uint16_t const size = des.queue_[0] << 8 | des.queue_[1];
2467-
2468- // The following should be caught by Deserializer::read and ::avail
2469- assert(des.queue_.size() >= static_cast<size_t>(size));
2470- assert(size >= 2);
2471-
2472- buffer.insert(buffer.end(), des.queue_.begin() + 2, des.queue_.begin() + size);
2473- index_ = 0;
2474-
2475- des.queue_.erase(des.queue_.begin(), des.queue_.begin() + size);
2476-}
2477-
2478 size_t RecvPacket::data(void* const packet_data, size_t const bufsize) {
2479 if (index_ + bufsize > buffer.size())
2480 throw wexception("Packet too short");
2481@@ -167,29 +159,29 @@
2482 return index_ < buffer.size();
2483 }
2484
2485-bool Deserializer::read(TCPsocket sock) {
2486- uint8_t buffer[512];
2487- const int32_t bytes = SDLNet_TCP_Recv(sock, buffer, sizeof(buffer));
2488- if (bytes <= 0)
2489- return false;
2490-
2491- queue_.insert(queue_.end(), &buffer[0], &buffer[bytes]);
2492-
2493- return queue_.size() < 2 || 2 <= (queue_[0] << 8 | queue_[1]);
2494+void Deserializer::read_data(const uint8_t *data, const int32_t len) {
2495+
2496+ queue_.insert(queue_.end(), &data[0], &data[len]);
2497 }
2498
2499-/**
2500- * Returns true if an entire packet is available
2501- */
2502-bool Deserializer::avail() const {
2503+bool Deserializer::write_packet(RecvPacket *packet) {
2504+ // No data at all
2505 if (queue_.size() < 2)
2506 return false;
2507
2508- const uint16_t size = queue_[0] << 8 | queue_[1];
2509- if (size < 2)
2510+ uint16_t const size = queue_[0] << 8 | queue_[1];
2511+ assert(size >= 2);
2512+
2513+ // Not enough data for a complete packet
2514+ if (queue_.size() < static_cast<size_t>(size))
2515 return false;
2516
2517- return queue_.size() >= static_cast<size_t>(size);
2518+ packet->buffer.clear();
2519+ packet->buffer.insert(packet->buffer.end(), queue_.begin() + 2, queue_.begin() + size);
2520+ packet->index_ = 0;
2521+
2522+ queue_.erase(queue_.begin(), queue_.begin() + size);
2523+ return true;
2524 }
2525
2526 DisconnectException::DisconnectException(const char* fmt, ...) {
2527
2528=== modified file 'src/network/network.h'
2529--- src/network/network.h 2017-01-25 18:55:59 +0000
2530+++ src/network/network.h 2017-05-11 07:00:56 +0000
2531@@ -43,7 +43,7 @@
2532 };
2533
2534 /**
2535- * This non-gamelogic command is used by \ref NetHost and \ref NetClient
2536+ * This non-gamelogic command is used by \ref GameHost and \ref GameClient
2537 * to schedule taking a synchronization hash.
2538 */
2539 struct CmdNetCheckSync : public Widelands::Command {
2540@@ -92,18 +92,22 @@
2541
2542 /**
2543 * Buffered StreamWrite object for assembling a packet that will be
2544- * sent via the \ref send() function.
2545+ * sent over the network.
2546 */
2547 struct SendPacket : public StreamWrite {
2548 SendPacket();
2549
2550- void send(TCPsocket);
2551 void reset();
2552
2553 void data(void const* data, size_t size) override;
2554
2555+ size_t get_size() const;
2556+
2557+ uint8_t* get_data() const;
2558+
2559 private:
2560- std::vector<uint8_t> buffer;
2561+ // First two bytes are overwritten on call to get_data()
2562+ mutable std::vector<uint8_t> buffer;
2563 };
2564
2565 /**
2566@@ -111,12 +115,11 @@
2567 */
2568 struct RecvPacket : public StreamRead {
2569 public:
2570- RecvPacket(Deserializer&);
2571-
2572 size_t data(void* data, size_t bufsize) override;
2573 bool end_of_file() const override;
2574
2575 private:
2576+ friend struct Deserializer;
2577 std::vector<uint8_t> buffer;
2578 size_t index_;
2579 };
2580@@ -135,21 +138,17 @@
2581 class Deserializer {
2582 public:
2583 /**
2584- * Read data from the given socket.
2585- * \return \c false if the socket was disconnected or another error
2586- * occurred.
2587- * \c true if some data could be read (this does not imply that \ref avail
2588- * will return \c true !)
2589+ * Adds the given data to the internal buffer.
2590 */
2591- bool read(TCPsocket sock);
2592+ void read_data(const uint8_t *data, const int32_t len);
2593
2594 /**
2595- * \return \c true if an entire packet has been received.
2596+ * \param packet The packet to fill with the received data.
2597+ * \return \c true if an entire packet has been received and written to the given packet.
2598 */
2599- bool avail() const;
2600+ bool write_packet(RecvPacket *packet);
2601
2602 private:
2603- friend struct RecvPacket;
2604 std::vector<uint8_t> queue_;
2605 };
2606
2607
2608=== modified file 'src/network/network_lan_promotion.h'
2609--- src/network/network_lan_promotion.h 2017-01-25 18:55:59 +0000
2610+++ src/network/network_lan_promotion.h 2017-05-11 07:00:56 +0000
2611@@ -34,6 +34,8 @@
2612 #define LAN_GAME_CLOSED 0
2613 #define LAN_GAME_OPEN 1
2614
2615+// TODO(Notabilis): Update file for IPv6
2616+
2617 struct NetGameInfo {
2618 char magic[6];
2619 uint8_t version;
2620
2621=== modified file 'src/network/network_protocol.h'
2622--- src/network/network_protocol.h 2017-01-25 18:55:59 +0000
2623+++ src/network/network_protocol.h 2017-05-11 07:00:56 +0000
2624@@ -165,7 +165,7 @@
2625 * During game setup, this command is sent by the host to inform clients
2626 * about the names of the tribes they may choose.
2627 *
2628- * \see NetClient::handle_network
2629+ * \see GameClient::handle_network
2630 */
2631 NETCMD_SETTING_TRIBES = 6,
2632
2633@@ -173,7 +173,7 @@
2634 * During game setup, this command contains complete information about all
2635 * player slots (independent of their state).
2636 *
2637- * \see NetClient::handle_network
2638+ * \see GameClient::handle_network
2639 */
2640 NETCMD_SETTING_ALLPLAYERS = 7,
2641
2642@@ -184,7 +184,7 @@
2643 * Payload in that case is:
2644 * \li unsigned_8: number of the player
2645 *
2646- * \see NetClient::handle_network
2647+ * \see GameClient::handle_network
2648 */
2649 NETCMD_SETTING_PLAYER = 8,
2650
2651@@ -192,7 +192,7 @@
2652 * During game setup, this command contains complete information about all
2653 * users.
2654 *
2655- * \see NetClient::handle_network
2656+ * \see GameClient::handle_network
2657 */
2658 NETCMD_SETTING_ALLUSERS = 9,
2659
2660@@ -200,7 +200,7 @@
2661 * During game setup, this command updates the information associated to
2662 * one user.
2663 *
2664- * \see NetClient::handle_network
2665+ * \see GameClient::handle_network
2666 */
2667 NETCMD_SETTING_USER = 10,
2668
2669
2670=== modified file 'src/ui_fsmenu/internet_lobby.cc'
2671--- src/ui_fsmenu/internet_lobby.cc 2017-02-27 13:45:46 +0000
2672+++ src/ui_fsmenu/internet_lobby.cc 2017-05-11 07:00:56 +0000
2673@@ -28,9 +28,9 @@
2674 #include "graphic/graphic.h"
2675 #include "graphic/text_constants.h"
2676 #include "network/constants.h"
2677+#include "network/gameclient.h"
2678+#include "network/gamehost.h"
2679 #include "network/internet_gaming.h"
2680-#include "network/netclient.h"
2681-#include "network/nethost.h"
2682 #include "profile/profile.h"
2683 #include "ui_basic/messagebox.h"
2684
2685@@ -206,9 +206,8 @@
2686 std::string localservername = edit_servername_.text();
2687
2688 if (games != nullptr) { // If no communication error occurred, fill the list.
2689- for (uint32_t i = 0; i < games->size(); ++i) {
2690+ for (const InternetGame& game : *games) {
2691 const Image* pic;
2692- const InternetGame& game = games->at(i);
2693 if (game.connectable) {
2694 if (game.build_id == build_id())
2695 pic = g_gr->images().get("images/ui_basic/continue.png");
2696@@ -255,8 +254,7 @@
2697 void FullscreenMenuInternetLobby::fill_client_list(const std::vector<InternetClient>* clients) {
2698 clientsonline_list_.clear();
2699 if (clients != nullptr) { // If no communication error occurred, fill the list.
2700- for (uint32_t i = 0; i < clients->size(); ++i) {
2701- const InternetClient& client(clients->at(i));
2702+ for (const InternetClient& client : *clients) {
2703 UI::Table<const InternetClient* const>::EntryRecord& er = clientsonline_list_.add(&client);
2704 er.set_string(1, client.name);
2705 er.set_string(2, client.build_id);
2706@@ -344,8 +342,8 @@
2707 // And disable 'hostgame' button if yes.
2708 const std::vector<InternetGame>* games = InternetGaming::ref().games();
2709 if (games != nullptr) {
2710- for (uint32_t i = 0; i < games->size(); ++i) {
2711- if (games->at(i).name == edit_servername_.text()) {
2712+ for (const InternetGame& game : *games) {
2713+ if (game.name == edit_servername_.text()) {
2714 hostgame_.set_enabled(false);
2715 }
2716 }
2717@@ -375,6 +373,7 @@
2718 }
2719 std::string ip = InternetGaming::ref().ip();
2720
2721+ // TODO(Notabilis): Change this for IPv6
2722 // convert IPv6 addresses returned by the metaserver to IPv4 addresses.
2723 // At the moment SDL_net does not support IPv6 anyways.
2724 if (!ip.compare(0, 7, "::ffff:")) {
2725@@ -382,25 +381,7 @@
2726 log("InternetGaming: cut IPv6 address: %s\n", ip.c_str());
2727 }
2728
2729- IPaddress peer;
2730- if (hostent* const he = gethostbyname(ip.c_str())) {
2731- peer.host = (reinterpret_cast<in_addr*>(he->h_addr_list[0]))->s_addr;
2732- DIAG_OFF("-Wold-style-cast")
2733- peer.port = htons(WIDELANDS_PORT);
2734- DIAG_ON("-Wold-style-cast")
2735- } else {
2736- // Actually the game is not done, but that way we are again listed as in the lobby
2737- InternetGaming::ref().set_game_done();
2738- // Show a popup warning message
2739- std::string warningheader(_("Connection problem"));
2740- std::string warning(_("Widelands was unable to connect to the host."));
2741- UI::WLMessageBox mmb(
2742- this, warningheader, warning, UI::WLMessageBox::MBoxType::kOk, UI::Align::kLeft);
2743- mmb.run<UI::Panel::Returncodes>();
2744- }
2745- SDLNet_ResolveHost(&peer, ip.c_str(), WIDELANDS_PORT);
2746-
2747- NetClient netgame(&peer, InternetGaming::ref().get_local_clientname(), true);
2748+ GameClient netgame(ip, WIDELANDS_PORT, InternetGaming::ref().get_local_clientname(), true);
2749 netgame.run();
2750 } else
2751 throw wexception("No server selected! That should not happen!");
2752@@ -423,6 +404,6 @@
2753 InternetGaming::ref().set_local_servername(servername_ui);
2754
2755 // Start the game
2756- NetHost netgame(InternetGaming::ref().get_local_clientname(), true);
2757+ GameHost netgame(InternetGaming::ref().get_local_clientname(), true);
2758 netgame.run();
2759 }
2760
2761=== modified file 'src/ui_fsmenu/netsetup_lan.h'
2762--- src/ui_fsmenu/netsetup_lan.h 2017-01-25 18:55:59 +0000
2763+++ src/ui_fsmenu/netsetup_lan.h 2017-05-11 07:00:56 +0000
2764@@ -34,6 +34,8 @@
2765 struct NetOpenGame;
2766 struct NetGameInfo;
2767
2768+// TODO(Notabilis): Update for IPv6
2769+
2770 class FullscreenMenuNetSetupLAN : public FullscreenMenuBase {
2771 public:
2772 FullscreenMenuNetSetupLAN();
2773
2774=== modified file 'src/wlapplication.cc'
2775--- src/wlapplication.cc 2017-04-20 10:54:30 +0000
2776+++ src/wlapplication.cc 2017-05-11 07:00:56 +0000
2777@@ -69,9 +69,9 @@
2778 #include "logic/single_player_game_controller.h"
2779 #include "logic/single_player_game_settings_provider.h"
2780 #include "map_io/map_loader.h"
2781+#include "network/gameclient.h"
2782+#include "network/gamehost.h"
2783 #include "network/internet_gaming.h"
2784-#include "network/netclient.h"
2785-#include "network/nethost.h"
2786 #include "profile/profile.h"
2787 #include "sound/sound_handler.h"
2788 #include "ui_basic/messagebox.h"
2789@@ -1164,27 +1164,29 @@
2790 FullscreenMenuNetSetupLAN ns;
2791 menu_result = ns.run<FullscreenMenuBase::MenuTarget>();
2792 std::string playername = ns.get_playername();
2793+ // TODO(Notabilis): This has to be updated for IPv6
2794 uint32_t addr;
2795 uint16_t port;
2796 bool const host_address = ns.get_host_address(addr, port);
2797
2798 switch (menu_result) {
2799 case FullscreenMenuBase::MenuTarget::kHostgame: {
2800- NetHost netgame(playername);
2801+ GameHost netgame(playername);
2802 netgame.run();
2803 break;
2804 }
2805 case FullscreenMenuBase::MenuTarget::kJoingame: {
2806- IPaddress peer;
2807-
2808 if (!host_address)
2809 throw WLWarning(
2810 "Invalid Address", "%s", "The address of the game server is invalid");
2811
2812- peer.host = addr;
2813- peer.port = port;
2814-
2815- NetClient netgame(&peer, playername);
2816+ // TODO(Notabilis): Make this prettier. I am aware that this is quite ugly but it should work
2817+ // for now and will be removed shortly when we switch to boost.asio
2818+ char ip_str[] = {"255.255.255.255"};
2819+ sprintf(ip_str, "%d.%d.%d.%d", (addr & 0x000000ff), (addr & 0x0000ff00) >> 8,
2820+ (addr & 0x00ff0000) >> 16, (addr & 0xff000000) >> 24);
2821+ port = (port >> 8) | ((port & 0xFF) << 8);
2822+ GameClient netgame(ip_str, port, playername);
2823 netgame.run();
2824 break;
2825 }

Subscribers

People subscribed via source and target branches

to status/vote changes: