OpenTTD Source  20241108-master-g80f628063a
network_client.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "../stdafx.h"
11 #include "network_gui.h"
12 #include "../saveload/saveload.h"
13 #include "../saveload/saveload_filter.h"
14 #include "../command_func.h"
15 #include "../console_func.h"
16 #include "../strings_func.h"
17 #include "../window_func.h"
18 #include "../company_func.h"
19 #include "../company_base.h"
20 #include "../company_gui.h"
21 #include "../company_cmd.h"
22 #include "../core/random_func.hpp"
23 #include "../timer/timer_game_tick.h"
24 #include "../timer/timer_game_calendar.h"
25 #include "../gfx_func.h"
26 #include "../error.h"
27 #include "../rev.h"
28 #include "network.h"
29 #include "network_base.h"
30 #include "network_client.h"
31 #include "network_gamelist.h"
32 #include "../core/backup_type.hpp"
33 #include "../thread.h"
34 #include "../social_integration.h"
35 
36 #include "table/strings.h"
37 
38 #include "../safeguards.h"
39 
40 /* This file handles all the client-commands */
41 
44  static const size_t CHUNK = 32 * 1024;
45 
46  std::vector<uint8_t *> blocks;
47  uint8_t *buf;
48  uint8_t *bufe;
49  uint8_t **block;
50  size_t written_bytes;
51  size_t read_bytes;
52 
54  PacketReader() : LoadFilter(nullptr), buf(nullptr), bufe(nullptr), block(nullptr), written_bytes(0), read_bytes(0)
55  {
56  }
57 
58  ~PacketReader() override
59  {
60  for (auto p : this->blocks) {
61  free(p);
62  }
63  }
64 
72  static inline ssize_t TransferOutMemCopy(PacketReader *destination, const char *source, size_t amount)
73  {
74  memcpy(destination->buf, source, amount);
75  destination->buf += amount;
76  destination->written_bytes += amount;
77  return amount;
78  }
79 
84  void AddPacket(Packet &p)
85  {
86  assert(this->read_bytes == 0);
87  p.TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this);
88 
89  /* Did everything fit in the current chunk, then we're done. */
90  if (p.RemainingBytesToTransfer() == 0) return;
91 
92  /* Allocate a new chunk and add the remaining data. */
93  this->blocks.push_back(this->buf = CallocT<uint8_t>(CHUNK));
94  this->bufe = this->buf + CHUNK;
95 
96  p.TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this);
97  }
98 
99  size_t Read(uint8_t *rbuf, size_t size) override
100  {
101  /* Limit the amount to read to whatever we still have. */
102  size_t ret_size = size = std::min(this->written_bytes - this->read_bytes, size);
103  this->read_bytes += ret_size;
104  const uint8_t *rbufe = rbuf + ret_size;
105 
106  while (rbuf != rbufe) {
107  if (this->buf == this->bufe) {
108  this->buf = *this->block++;
109  this->bufe = this->buf + CHUNK;
110  }
111 
112  size_t to_write = std::min(this->bufe - this->buf, rbufe - rbuf);
113  memcpy(rbuf, this->buf, to_write);
114  rbuf += to_write;
115  this->buf += to_write;
116  }
117 
118  return ret_size;
119  }
120 
121  void Reset() override
122  {
123  this->read_bytes = 0;
124 
125  this->block = this->blocks.data();
126  this->buf = *this->block++;
127  this->bufe = this->buf + CHUNK;
128  }
129 };
130 
131 
136 {
137  static FiosNumberedSaveName _netsave_ctr("netsave");
138  DoAutoOrNetsave(_netsave_ctr);
139 }
140 
141 
146 ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s, const std::string &connection_string) : NetworkGameSocketHandler(s), connection_string(connection_string), savegame(nullptr), status(STATUS_INACTIVE)
147 {
150 }
151 
154 {
157 
158  delete this->GetInfo();
159 }
160 
162 {
163  assert(status != NETWORK_RECV_STATUS_OKAY);
164  if (this->IsPendingDeletion()) return status;
165 
166  assert(this->sock != INVALID_SOCKET);
167 
168  if (!this->HasClientQuit()) {
169  Debug(net, 3, "Closed client connection {}", this->client_id);
170 
171  this->SendPackets(true);
172 
173  /* Wait a number of ticks so our leave message can reach the server.
174  * This is especially needed for Windows servers as they seem to get
175  * the "socket is closed" message before receiving our leave message,
176  * which would trigger the server to close the connection as well. */
178  }
179 
180  this->DeferDeletion();
181 
182  return status;
183 }
184 
190 {
191  if (this->IsPendingDeletion()) return;
192 
193  /* First, send a CLIENT_ERROR to the server, so it knows we are
194  * disconnected (and why!) */
195  NetworkErrorCode errorno;
196 
197  /* We just want to close the connection.. */
198  if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
200  this->CloseConnection(res);
201  _networking = false;
202 
204  return;
205  }
206 
207  switch (res) {
208  case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break;
209  case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
210  case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break;
211  default: errorno = NETWORK_ERROR_GENERAL; break;
212  }
213 
216  /* This means the server closed the connection. Emergency save is
217  * already created if this was appropriate during handling of the
218  * disconnect. */
219  this->CloseConnection(res);
220  } else {
221  /* This means we as client made a boo-boo. */
222  SendError(errorno);
223 
224  /* Close connection before we make an emergency save, as the save can
225  * take a bit of time; better that the server doesn't stall while we
226  * are doing the save, and already disconnects us. */
227  this->CloseConnection(res);
229  }
230 
232 
233  if (_game_mode != GM_MENU) _switch_mode = SM_MENU;
234  _networking = false;
235 }
236 
237 
244 {
245  if (my_client->CanSendReceive()) {
247  if (res != NETWORK_RECV_STATUS_OKAY) {
248  /* The client made an error of which we can not recover.
249  * Close the connection and drop back to the main menu. */
250  my_client->ClientError(res);
251  return false;
252  }
253  }
254  return _networking;
255 }
256 
259 {
261  if (my_client != nullptr) my_client->CheckConnection();
262 }
263 
269 {
270  _frame_counter++;
271 
273 
274  StateGameLoop();
275 
276  /* Check if we are in sync! */
277  if (_sync_frame != 0) {
278  if (_sync_frame == _frame_counter) {
279 #ifdef NETWORK_SEND_DOUBLE_SEED
280  if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
281 #else
282  if (_sync_seed_1 != _random.state[0]) {
283 #endif
284  ShowNetworkError(STR_NETWORK_ERROR_DESYNC);
285  Debug(desync, 1, "sync_err: {:08x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract);
286  Debug(net, 0, "Sync error detected");
288  return false;
289  }
290 
291  /* If this is the first time we have a sync-frame, we
292  * need to let the server know that we are ready and at the same
293  * frame as it is.. so we can start playing! */
294  if (_network_first_time) {
295  _network_first_time = false;
296  SendAck();
297  }
298 
299  _sync_frame = 0;
300  } else if (_sync_frame < _frame_counter) {
301  Debug(net, 1, "Missed frame for sync-test: {} / {}", _sync_frame, _frame_counter);
302  _sync_frame = 0;
303  }
304  }
305 
306  return true;
307 }
308 
309 
312 
314 static uint32_t last_ack_frame;
315 
320 
323 
324 /***********
325  * Sending functions
326  ************/
327 
330 {
331  Debug(net, 9, "Client::SendJoin()");
332 
333  Debug(net, 9, "Client::status = JOIN");
335  Debug(net, 9, "Client::join_status = AUTHORIZING");
336  _network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
338 
339  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_JOIN);
340  p->Send_string(GetNetworkRevisionString());
341  p->Send_uint32(_openttd_newgrf_version);
342  my_client->SendPacket(std::move(p));
343 
345 }
346 
347 NetworkRecvStatus ClientNetworkGameSocketHandler::SendIdentify()
348 {
349  Debug(net, 9, "Client::SendIdentify()");
350 
351  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_IDENTIFY);
352  p->Send_string(_settings_client.network.client_name); // Client name
353  p->Send_uint8(_network_join.company); // PlayAs
354  my_client->SendPacket(std::move(p));
356 }
357 
360 {
361  Debug(net, 9, "Client::SendNewGRFsOk()");
362 
363  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_NEWGRFS_CHECKED);
364  my_client->SendPacket(std::move(p));
366 }
367 
373 {
374  Debug(net, 9, "Client::SendAuthResponse()");
375 
376  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_AUTH_RESPONSE);
377  my_client->authentication_handler->SendResponse(*p);
378  my_client->SendPacket(std::move(p));
379 
381 }
382 
385 {
386  Debug(net, 9, "Client::SendGetMap()");
387 
388  Debug(net, 9, "Client::status = MAP_WAIT");
390 
391  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_GETMAP);
392  my_client->SendPacket(std::move(p));
394 }
395 
398 {
399  Debug(net, 9, "Client::SendMapOk()");
400 
401  Debug(net, 9, "Client::status = ACTIVE");
403 
404  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_MAP_OK);
405  my_client->SendPacket(std::move(p));
407 }
408 
411 {
412  Debug(net, 9, "Client::SendAck()");
413 
414  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_ACK);
415 
416  p->Send_uint32(_frame_counter);
417  p->Send_uint8 (my_client->token);
418  my_client->SendPacket(std::move(p));
420 }
421 
427 {
428  Debug(net, 9, "Client::SendCommand(): cmd={}", cp.cmd);
429 
430  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_COMMAND);
431  my_client->NetworkGameSocketHandler::SendCommand(*p, cp);
432 
433  my_client->SendPacket(std::move(p));
435 }
436 
438 NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data)
439 {
440  Debug(net, 9, "Client::SendChat(): action={}, type={}, dest={}", action, type, dest);
441 
442  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_CHAT);
443 
444  p->Send_uint8 (action);
445  p->Send_uint8 (type);
446  p->Send_uint32(dest);
447  p->Send_string(msg);
448  p->Send_uint64(data);
449 
450  my_client->SendPacket(std::move(p));
452 }
453 
456 {
457  Debug(net, 9, "Client::SendError(): errorno={}", errorno);
458 
459  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_ERROR);
460 
461  p->Send_uint8(errorno);
462  my_client->SendPacket(std::move(p));
464 }
465 
471 {
472  Debug(net, 9, "Client::SendSetName()");
473 
474  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_SET_NAME);
475 
476  p->Send_string(name);
477  my_client->SendPacket(std::move(p));
479 }
480 
485 {
486  Debug(net, 9, "Client::SendQuit()");
487 
488  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_QUIT);
489 
490  my_client->SendPacket(std::move(p));
492 }
493 
499 NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const std::string &pass, const std::string &command)
500 {
501  Debug(net, 9, "Client::SendRCon()");
502 
503  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_RCON);
504  p->Send_string(pass);
505  p->Send_string(command);
506  my_client->SendPacket(std::move(p));
508 }
509 
515 {
516  Debug(net, 9, "Client::SendMove(): company={}", company);
517 
518  auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_MOVE);
519  p->Send_uint8(company);
520  my_client->SendPacket(std::move(p));
522 }
523 
529 {
530  return my_client != nullptr && my_client->status == STATUS_ACTIVE;
531 }
532 
533 
534 /***********
535  * Receiving functions
536  ************/
537 
538 extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, std::shared_ptr<struct LoadFilter> lf);
539 
541 {
542  Debug(net, 9, "Client::Receive_SERVER_FULL()");
543 
544  /* We try to join a server which is full */
545  ShowErrorMessage(STR_NETWORK_ERROR_SERVER_FULL, INVALID_STRING_ID, WL_CRITICAL);
546 
548 }
549 
551 {
552  Debug(net, 9, "Client::Receive_SERVER_BANNED()");
553 
554  /* We try to join a server where we are banned */
555  ShowErrorMessage(STR_NETWORK_ERROR_SERVER_BANNED, INVALID_STRING_ID, WL_CRITICAL);
556 
558 }
559 
560 /* This packet contains info about the client (playas and name)
561  * as client we save this in NetworkClientInfo, linked via 'client_id'
562  * which is always an unique number on a server. */
564 {
565  NetworkClientInfo *ci;
567  CompanyID playas = (CompanyID)p.Recv_uint8();
568 
569  Debug(net, 9, "Client::Receive_SERVER_CLIENT_INFO(): client_id={}, playas={}", client_id, playas);
570 
571  std::string name = p.Recv_string(NETWORK_NAME_LENGTH);
572  std::string public_key = p.Recv_string(NETWORK_PUBLIC_KEY_LENGTH);
573 
576  /* The server validates the name when receiving it from clients, so when it is wrong
577  * here something went really wrong. In the best case the packet got malformed on its
578  * way too us, in the worst case the server is broken or compromised. */
580 
582  if (ci != nullptr) {
583  if (playas == ci->client_playas && name.compare(ci->client_name) != 0) {
584  /* Client name changed, display the change */
585  NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, name);
586  } else if (playas != ci->client_playas) {
587  /* The client changed from client-player..
588  * Do not display that for now */
589  }
590 
591  /* Make sure we're in the company the server tells us to be in,
592  * for the rare case that we get moved while joining. */
594 
595  ci->client_playas = playas;
596  ci->client_name = name;
597  ci->public_key = public_key;
598 
600 
602  }
603 
604  /* There are at most as many ClientInfo as ClientSocket objects in a
605  * server. Having more info than a server can have means something
606  * has gone wrong somewhere, i.e. the server has more info than it
607  * has actual clients. That means the server is feeding us an invalid
608  * state. So, bail out! This server is broken. */
610 
611  /* We don't have this client_id yet, find an empty client_id, and put the data there */
612  ci = new NetworkClientInfo(client_id);
613  ci->client_playas = playas;
614  if (client_id == _network_own_client_id) this->SetInfo(ci);
615 
616  ci->client_name = name;
617  ci->public_key = public_key;
618 
620 
622 }
623 
625 {
626  static const StringID network_error_strings[] = {
627  STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_GENERAL
628  STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_DESYNC
629  STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_SAVEGAME_FAILED
630  STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_CONNECTION_LOST
631  STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_ILLEGAL_PACKET
632  STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NEWGRF_MISMATCH
633  STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_AUTHORIZED
634  STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_EXPECTED
635  STR_NETWORK_ERROR_WRONG_REVISION, // NETWORK_ERROR_WRONG_REVISION
636  STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NAME_IN_USE
637  STR_NETWORK_ERROR_WRONG_PASSWORD, // NETWORK_ERROR_WRONG_PASSWORD
638  STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_COMPANY_MISMATCH
639  STR_NETWORK_ERROR_KICKED, // NETWORK_ERROR_KICKED
640  STR_NETWORK_ERROR_CHEATER, // NETWORK_ERROR_CHEATER
641  STR_NETWORK_ERROR_SERVER_FULL, // NETWORK_ERROR_FULL
642  STR_NETWORK_ERROR_TOO_MANY_COMMANDS, // NETWORK_ERROR_TOO_MANY_COMMANDS
643  STR_NETWORK_ERROR_TIMEOUT_PASSWORD, // NETWORK_ERROR_TIMEOUT_PASSWORD
644  STR_NETWORK_ERROR_TIMEOUT_COMPUTER, // NETWORK_ERROR_TIMEOUT_COMPUTER
645  STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP
646  STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN
647  STR_NETWORK_ERROR_INVALID_CLIENT_NAME, // NETWORK_ERROR_INVALID_CLIENT_NAME
648  STR_NETWORK_ERROR_NOT_ON_ALLOW_LIST, // NETWORK_ERROR_NOT_ON_ALLOW_LIST
649  STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NO_AUTHENTICATION_METHOD_AVAILABLE
650  };
651  static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
652 
654 
655  Debug(net, 9, "Client::Receive_SERVER_ERROR(): error={}", error);
656 
657  StringID err = STR_NETWORK_ERROR_LOSTCONNECTION;
658  if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error];
659  /* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */
660  if (error == NETWORK_ERROR_KICKED && p.CanReadFromPacket(1)) {
662  ShowErrorMessage(err, STR_NETWORK_ERROR_KICK_MESSAGE, WL_CRITICAL);
663  } else {
665  }
666 
667  /* Perform an emergency save if we had already entered the game */
669 
671 }
672 
674 {
676 
677  uint grf_count = p.Recv_uint8();
679 
680  Debug(net, 9, "Client::Receive_SERVER_CHECK_NEWGRFS(): grf_count={}", grf_count);
681 
682  /* Check all GRFs */
683  for (; grf_count > 0; grf_count--) {
684  GRFIdentifier c;
685  DeserializeGRFIdentifier(p, c);
686 
687  /* Check whether we know this GRF */
688  const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, &c.md5sum);
689  if (f == nullptr) {
690  /* We do not know this GRF, bail out of initialization */
691  Debug(grf, 0, "NewGRF {:08X} not found; checksum {}", BSWAP32(c.grfid), FormatArrayAsHex(c.md5sum));
693  }
694  }
695 
696  if (ret == NETWORK_RECV_STATUS_OKAY) {
697  /* Start receiving the map */
698  return SendNewGRFsOk();
699  }
700 
701  /* NewGRF mismatch, bail out */
702  ShowErrorMessage(STR_NETWORK_ERROR_NEWGRF_MISMATCH, INVALID_STRING_ID, WL_CRITICAL);
703  return ret;
704 }
705 
707  virtual void SendResponse() override { MyClient::SendAuthResponse(); }
708  virtual void AskUserForPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request) override
709  {
710  if (!_network_join.server_password.empty()) {
711  request->Reply(_network_join.server_password);
712  } else {
713  ShowNetworkNeedPassword(request);
714  }
715  }
716 };
717 
719 {
721  Debug(net, 9, "Client::status = AUTH_GAME");
722  this->status = STATUS_AUTH_GAME;
723 
724  Debug(net, 9, "Client::Receive_SERVER_AUTH_REQUEST()");
725 
726  if (this->authentication_handler == nullptr) {
727  this->authentication_handler = NetworkAuthenticationClientHandler::Create(std::make_shared<ClientGamePasswordRequestHandler>(),
729  }
730  switch (this->authentication_handler->ReceiveRequest(p)) {
732  return SendAuthResponse();
733 
736 
738  default:
740  }
741 }
742 
744 {
746 
747  Debug(net, 9, "Client::Receive_SERVER_ENABLE_ENCRYPTION()");
748 
749  if (!this->authentication_handler->ReceiveEnableEncryption(p)) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
750 
751  this->receive_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
752  this->send_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
753  this->authentication_handler = nullptr;
754 
755  Debug(net, 9, "Client::status = ENCRYPTED");
756  this->status = STATUS_ENCRYPTED;
757 
758  return this->SendIdentify();
759 }
760 
762 {
763  if (this->status < STATUS_ENCRYPTED || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
764  Debug(net, 9, "Client::status = AUTHORIZED");
765  this->status = STATUS_AUTHORIZED;
766 
768 
769  Debug(net, 9, "Client::Receive_SERVER_WELCOME(): client_id={}", _network_own_client_id);
770 
771  /* Start receiving the map */
772  return SendGetMap();
773 }
774 
776 {
777  /* We set the internal wait state when requesting the map. */
779 
780  Debug(net, 9, "Client::Receive_SERVER_WAIT()");
781 
782  /* But... only now we set the join status to waiting, instead of requesting. */
783  Debug(net, 9, "Client::join_status = WAITING");
784  _network_join_status = NETWORK_JOIN_STATUS_WAITING;
787 
789 }
790 
792 {
793  if (this->status < STATUS_AUTHORIZED || this->status >= STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
794  Debug(net, 9, "Client::status = MAP");
795  this->status = STATUS_MAP;
796 
797  if (this->savegame != nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
798 
799  this->savegame = std::make_shared<PacketReader>();
800 
802 
803  Debug(net, 9, "Client::Receive_SERVER_MAP_BEGIN(): frame_counter={}", _frame_counter);
804 
807 
808  Debug(net, 9, "Client::join_status = DOWNLOADING");
809  _network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
811 
813 }
814 
816 {
818  if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
819 
822 
823  Debug(net, 9, "Client::Receive_SERVER_MAP_SIZE(): bytes_total={}", _network_join_bytes_total);
824 
826 }
827 
829 {
831  if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
832 
833  /* We are still receiving data, put it to the file */
834  this->savegame->AddPacket(p);
835 
836  _network_join_bytes = (uint32_t)this->savegame->written_bytes;
838 
840 }
841 
843 {
845  if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
846 
847  Debug(net, 9, "Client::Receive_SERVER_MAP_DONE()");
848 
849  Debug(net, 9, "Client::join_status = PROCESSING");
850  _network_join_status = NETWORK_JOIN_STATUS_PROCESSING;
852 
853  this->savegame->Reset();
854 
855  /* The map is done downloading, load it */
857 
858  /* Set the abstract filetype. This is read during savegame load. */
860 
861  bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, this->savegame);
862  this->savegame = nullptr;
863 
864  /* Long savegame loads shouldn't affect the lag calculation! */
865  this->last_packet = std::chrono::steady_clock::now();
866 
867  if (!load_success) {
868  ShowErrorMessage(STR_NETWORK_ERROR_SAVEGAMEERROR, INVALID_STRING_ID, WL_CRITICAL);
870  }
871  /* If the savegame has successfully loaded, ALL windows have been removed,
872  * only toolbar/statusbar and gamefield are visible */
873 
874  /* Say we received the map and loaded it correctly! */
875  SendMapOk();
876 
877  /* As we skipped switch-mode, update the time we "switched". */
878  _game_session_stats.start_time = std::chrono::steady_clock::now();
879  _game_session_stats.savegame_size = std::nullopt;
880 
881  ShowClientList();
882 
883  /* New company/spectator (invalid company) or company we want to join is not active
884  * Switch local company to spectator and await the server's judgement */
887 
889  /* We have arrived and ready to start playing; send a command to make a new company;
890  * the server will give us a client-id and let us in */
891  Debug(net, 9, "Client::join_status = REGISTERING");
892  _network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
893  ShowJoinStatusWindow();
895  }
896  } else {
897  /* take control over an existing company */
899  }
900 
902 
904 }
905 
907 {
909 
912 #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
913  /* Test if the server supports this option
914  * and if we are at the frame the server is */
915 #ifdef NETWORK_SEND_DOUBLE_SEED
916  if (p.CanReadFromPacket(sizeof(uint32_t) + sizeof(uint32_t))) {
917 #else
918  if (p.CanReadFromPacket(sizeof(uint32_t))) {
919 #endif
922 #ifdef NETWORK_SEND_DOUBLE_SEED
923  _sync_seed_2 = p.Recv_uint32();
924 #endif
925  }
926 #endif
927  /* Receive the token. */
928  if (p.CanReadFromPacket(sizeof(uint8_t))) this->token = p.Recv_uint8();
929 
930  /* Let the server know that we received this frame correctly
931  * We do this only once per day, to save some bandwidth ;) */
934  Debug(net, 7, "Sent ACK at {}", _frame_counter);
935  SendAck();
936  }
937 
939 }
940 
942 {
944 
945  _sync_frame = p.Recv_uint32();
947 #ifdef NETWORK_SEND_DOUBLE_SEED
948  _sync_seed_2 = p.Recv_uint32();
949 #endif
950 
951  Debug(net, 9, "Client::Receive_SERVER_SYNC(): sync_frame={}, sync_seed_1={}", _sync_frame, _sync_seed_1);
952 
954 }
955 
957 {
959 
960  CommandPacket cp;
961  const char *err = this->ReceiveCommand(p, cp);
962  cp.frame = p.Recv_uint32();
963  cp.my_cmd = p.Recv_bool();
964 
965  Debug(net, 9, "Client::Receive_SERVER_COMMAND(): cmd={}, frame={}", cp.cmd, cp.frame);
966 
967  if (err != nullptr) {
968  IConsolePrint(CC_WARNING, "Dropping server connection due to {}.", err);
970  }
971 
972  this->incoming_queue.push_back(cp);
973 
975 }
976 
978 {
980 
981  std::string name;
982  const NetworkClientInfo *ci = nullptr, *ci_to;
983 
984  NetworkAction action = (NetworkAction)p.Recv_uint8();
986  bool self_send = p.Recv_bool();
987  std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
988  int64_t data = p.Recv_uint64();
989 
990  Debug(net, 9, "Client::Receive_SERVER_CHAT(): action={}, client_id={}, self_send={}", action, client_id, self_send);
991 
993  if (ci_to == nullptr) return NETWORK_RECV_STATUS_OKAY;
994 
995  /* Did we initiate the action locally? */
996  if (self_send) {
997  switch (action) {
998  case NETWORK_ACTION_CHAT_CLIENT:
999  /* For speaking to client we need the client-name */
1000  name = ci_to->client_name;
1002  break;
1003 
1004  /* For speaking to company, we need the company-name */
1005  case NETWORK_ACTION_CHAT_COMPANY: {
1006  StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
1007  SetDParam(0, ci_to->client_playas);
1008 
1009  name = GetString(str);
1011  break;
1012  }
1013 
1014  default: return NETWORK_RECV_STATUS_MALFORMED_PACKET;
1015  }
1016  } else {
1017  /* Display message from somebody else */
1018  name = ci_to->client_name;
1019  ci = ci_to;
1020  }
1021 
1022  if (ci != nullptr) {
1023  NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data);
1024  }
1025  return NETWORK_RECV_STATUS_OKAY;
1026 }
1027 
1029 {
1031 
1032  std::string source = p.Recv_string(NETWORK_CHAT_LENGTH);
1033  TextColour colour = (TextColour)p.Recv_uint16();
1034  std::string user = p.Recv_string(NETWORK_CHAT_LENGTH);
1035  std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
1036 
1037  Debug(net, 9, "Client::Receive_SERVER_EXTERNAL_CHAT(): source={}", source);
1038 
1040 
1041  NetworkTextMessage(NETWORK_ACTION_EXTERNAL_CHAT, colour, false, user, msg, 0, source);
1042 
1043  return NETWORK_RECV_STATUS_OKAY;
1044 }
1045 
1047 {
1049 
1051 
1052  Debug(net, 9, "Client::Receive_SERVER_ERROR_QUIT(): client_id={}", client_id);
1053 
1055  if (ci != nullptr) {
1056  NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "", GetNetworkErrorMsg((NetworkErrorCode)p.Recv_uint8()));
1057  delete ci;
1058  }
1059 
1061 
1062  return NETWORK_RECV_STATUS_OKAY;
1063 }
1064 
1066 {
1068 
1070 
1071  Debug(net, 9, "Client::Receive_SERVER_QUIT(): client_id={}", client_id);
1072 
1074  if (ci != nullptr) {
1075  NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "", STR_NETWORK_MESSAGE_CLIENT_LEAVING);
1076  delete ci;
1077  } else {
1078  Debug(net, 1, "Unknown client ({}) is leaving the game", client_id);
1079  }
1080 
1082 
1083  /* If we come here it means we could not locate the client.. strange :s */
1084  return NETWORK_RECV_STATUS_OKAY;
1085 }
1086 
1088 {
1090 
1092 
1093  Debug(net, 9, "Client::Receive_SERVER_JOIN(): client_id={}", client_id);
1094 
1096  if (ci != nullptr) {
1097  NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name);
1098  }
1099 
1101 
1102  return NETWORK_RECV_STATUS_OKAY;
1103 }
1104 
1106 {
1107  Debug(net, 9, "Client::Receive_SERVER_SHUTDOWN()");
1108 
1109  /* Only when we're trying to join we really
1110  * care about the server shutting down. */
1111  if (this->status >= STATUS_JOIN) {
1112  ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_SHUTDOWN, INVALID_STRING_ID, WL_CRITICAL);
1113  }
1114 
1116 
1118 }
1119 
1121 {
1122  Debug(net, 9, "Client::Receive_SERVER_NEWGAME()");
1123 
1124  /* Only when we're trying to join we really
1125  * care about the server shutting down. */
1126  if (this->status >= STATUS_JOIN) {
1127  /* To throttle the reconnects a bit, every clients waits its
1128  * Client ID modulo 16 + 1 (value 0 means no reconnect).
1129  * This way reconnects should be spread out a bit. */
1131  ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_REBOOT, INVALID_STRING_ID, WL_CRITICAL);
1132  }
1133 
1135 
1137 }
1138 
1140 {
1142 
1143  Debug(net, 9, "Client::Receive_SERVER_RCON()");
1144 
1145  TextColour colour_code = (TextColour)p.Recv_uint16();
1147 
1148  std::string rcon_out = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
1149 
1150  IConsolePrint(colour_code, rcon_out);
1151 
1152  return NETWORK_RECV_STATUS_OKAY;
1153 }
1154 
1156 {
1158 
1159  /* Nothing more in this packet... */
1161  CompanyID company_id = (CompanyID)p.Recv_uint8();
1162 
1163  Debug(net, 9, "Client::Receive_SERVER_MOVE(): client_id={}, comapny_id={}", client_id, company_id);
1164 
1165  if (client_id == 0) {
1166  /* definitely an invalid client id, debug message and do nothing. */
1167  Debug(net, 1, "Received invalid client index = 0");
1169  }
1170 
1172  /* Just make sure we do not try to use a client_index that does not exist */
1173  if (ci == nullptr) return NETWORK_RECV_STATUS_OKAY;
1174 
1175  /* if not valid player, force spectator, else check player exists */
1176  if (!Company::IsValidID(company_id)) company_id = COMPANY_SPECTATOR;
1177 
1179  SetLocalCompany(company_id);
1180  }
1181 
1182  return NETWORK_RECV_STATUS_OKAY;
1183 }
1184 
1186 {
1188 
1189  _network_server_max_companies = p.Recv_uint8();
1191 
1193 
1194  Debug(net, 9, "Client::Receive_SERVER_CONFIG_UPDATE(): max_companies={}", _network_server_max_companies);
1195 
1196  return NETWORK_RECV_STATUS_OKAY;
1197 }
1198 
1203 {
1204  /* Only once we're authorized we can expect a steady stream of packets. */
1205  if (this->status < STATUS_AUTHORIZED) return;
1206 
1207  /* 5 seconds are roughly twice the server's "you're slow" threshold (1 game day). */
1208  std::chrono::steady_clock::duration lag = std::chrono::steady_clock::now() - this->last_packet;
1209  if (lag < std::chrono::seconds(5)) return;
1210 
1211  /* 20 seconds are (way) more than 4 game days after which
1212  * the server will forcefully disconnect you. */
1213  if (lag > std::chrono::seconds(20)) {
1215  return;
1216  }
1217 
1218  /* Prevent showing the lag message every tick; just update it when needed. */
1219  static std::chrono::steady_clock::duration last_lag = {};
1220  if (std::chrono::duration_cast<std::chrono::seconds>(last_lag) == std::chrono::duration_cast<std::chrono::seconds>(lag)) return;
1221 
1222  last_lag = lag;
1223  SetDParam(0, std::chrono::duration_cast<std::chrono::seconds>(lag).count());
1224  ShowErrorMessage(STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION, STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION, WL_INFO);
1225 }
1226 
1227 
1230 {
1231  /* Set the frame-counter to 0 so nothing happens till we are ready */
1232  _frame_counter = 0;
1234  last_ack_frame = 0;
1235 
1236  Debug(net, 9, "Client::NetworkClient_Connected()");
1237 
1238  /* Request the game-info */
1240 }
1241 
1247 void NetworkClientSendRcon(const std::string &password, const std::string &command)
1248 {
1249  MyClient::SendRCon(password, command);
1250 }
1251 
1257 {
1258  MyClient::SendMove(company_id);
1259 }
1260 
1266 {
1267  Backup<CompanyID> cur_company(_current_company);
1268  /* If our company is changing owner, go to spectators */
1270 
1272  if (ci->client_playas != cid) continue;
1273  NetworkTextMessage(NETWORK_ACTION_COMPANY_SPECTATOR, CC_DEFAULT, false, ci->client_name);
1274  ci->client_playas = COMPANY_SPECTATOR;
1275  }
1276 
1277  cur_company.Restore();
1278 }
1279 
1287 bool NetworkIsValidClientName(const std::string_view client_name)
1288 {
1289  if (client_name.empty()) return false;
1290  if (client_name[0] == ' ') return false;
1291  return true;
1292 }
1293 
1309 bool NetworkValidateClientName(std::string &client_name)
1310 {
1311  StrTrimInPlace(client_name);
1312  if (NetworkIsValidClientName(client_name)) return true;
1313 
1314  ShowErrorMessage(STR_NETWORK_ERROR_BAD_PLAYER_NAME, INVALID_STRING_ID, WL_ERROR);
1315  return false;
1316 }
1317 
1326 {
1328 }
1329 
1334 void NetworkUpdateClientName(const std::string &client_name)
1335 {
1337  if (ci == nullptr) return;
1338 
1339  /* Don't change the name if it is the same as the old name */
1340  if (client_name.compare(ci->client_name) != 0) {
1341  if (!_network_server) {
1342  MyClient::SendSetName(client_name);
1343  } else {
1344  /* Copy to a temporary buffer so no #n gets added after our name in the settings when there are duplicate names. */
1345  std::string temporary_name = client_name;
1346  if (NetworkMakeClientNameUnique(temporary_name)) {
1347  NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, temporary_name);
1348  ci->client_name = temporary_name;
1350  }
1351  }
1352  }
1353 }
1354 
1363 void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data)
1364 {
1365  MyClient::SendChat(action, type, dest, msg, data);
1366 }
1367 
1374 {
1375  /* Only companies actually playing can speak to team. Eg spectators cannot */
1377 
1378  for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1379  if (ci->client_playas == cio->client_playas && ci != cio) return true;
1380  }
1381 
1382  return false;
1383 }
1384 
1390 {
1392 }
1393 
1399 {
1401 }
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
virtual void AskUserForPassword(std::shared_ptr< NetworkAuthenticationPasswordRequest > request) override
Callback to trigger asking the user for the password.
virtual void SendResponse() override
Callback to trigger sending the response for the password request.
Class for handling the client side of the game connection.
NetworkRecvStatus Receive_SERVER_QUIT(Packet &p) override
Notification that a client left the game: uint32_t ID of the client.
static ClientNetworkGameSocketHandler * my_client
This is us!
static NetworkRecvStatus SendQuit()
Tell the server we would like to quit.
NetworkRecvStatus Receive_SERVER_SYNC(Packet &p) override
Sends a sync-check to the client: uint32_t Frame counter.
NetworkRecvStatus Receive_SERVER_ENABLE_ENCRYPTION(Packet &p) override
Indication to the client that authentication is complete and encryption has to be used from here on f...
NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet &p) override
Sends the size of the map to the client.
static bool Receive()
Check whether we received/can send some data from/to the server and when that's the case handle it ap...
NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet &p) override
Sends that all data of the map are sent to the client:
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p) override
Send information about a client: uint32_t ID of the client (always unique on a server.
~ClientNetworkGameSocketHandler()
Clear whatever we assigned.
ServerStatus status
Status of the connection with the server.
NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet &p) override
Sends information about all used GRFs to the client: uint8_t Amount of GRFs (the following data is re...
static NetworkRecvStatus SendMove(CompanyID company)
Ask the server to move us.
NetworkRecvStatus Receive_SERVER_WAIT(Packet &p) override
Notification that another client is currently receiving the map: uint8_t Number of clients waiting in...
std::unique_ptr< class NetworkAuthenticationClientHandler > authentication_handler
The handler for the authentication.
std::shared_ptr< struct PacketReader > savegame
Packet reader for reading the savegame.
static bool IsConnected()
Check whether the client is actually connected (and in the game).
NetworkRecvStatus Receive_SERVER_EXTERNAL_CHAT(Packet &p) override
Sends a chat-packet for external source to the client: string Name of the source this message came fr...
uint8_t token
The token we need to send back to the server to prove we're the right client.
static NetworkRecvStatus SendSetName(const std::string &name)
Tell the server that we like to change the name of the client.
friend void NetworkExecuteLocalCommandQueue()
Execute all commands on the local command queue that ought to be executed this frame.
NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet &p) override
Inform all clients that one client made an error and thus has quit/been disconnected: uint32_t ID of ...
static NetworkRecvStatus SendNewGRFsOk()
Tell the server we got all the NewGRFs.
static NetworkRecvStatus SendMapOk()
Tell the server we received the complete map.
void CheckConnection()
Check the connection's state, i.e.
NetworkRecvStatus Receive_SERVER_RCON(Packet &p) override
Send the result of an issues RCon command back to the client: uint16_t Colour code.
NetworkRecvStatus Receive_SERVER_BANNED(Packet &p) override
Notification that the client trying to join is banned.
NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet &p) override
Update the clients knowledge of the max settings: uint8_t Maximum number of companies allowed.
void ClientError(NetworkRecvStatus res)
Handle an error coming from the client side.
NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p) override
The client is joined and ready to receive their map: uint32_t Own client ID.
static NetworkRecvStatus SendAck()
Send an acknowledgement from the server's ticks.
NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet &p) override
Sends that the server will begin with sending the map to the client: uint32_t Current frame.
NetworkRecvStatus Receive_SERVER_JOIN(Packet &p) override
A client joined (PACKET_CLIENT_MAP_OK), what usually directly follows is a PACKET_SERVER_CLIENT_INFO:...
@ STATUS_JOIN
We are trying to join a server.
@ STATUS_ENCRYPTED
The game authentication has completed and from here on the connection to the server is encrypted.
@ STATUS_MAP
The client is downloading the map.
@ STATUS_AUTH_GAME
Last action was requesting game (server) password.
@ STATUS_ACTIVE
The client is active within in the game.
@ STATUS_MAP_WAIT
The client is waiting as someone else is downloading the map.
@ STATUS_AUTHORIZED
The client is authorized at the server.
static NetworkRecvStatus SendAuthResponse()
Set the game password as requested.
static NetworkRecvStatus SendRCon(const std::string &password, const std::string &command)
Send a console command.
static bool GameLoop()
Actual game loop for the client.
static void Send()
Send the packets of this socket handler.
NetworkRecvStatus Receive_SERVER_CHAT(Packet &p) override
Sends a chat-packet to the client: uint8_t ID of the action (see NetworkAction).
NetworkRecvStatus Receive_SERVER_MOVE(Packet &p) override
Move a client from one company into another: uint32_t ID of the client.
static NetworkRecvStatus SendCommand(const CommandPacket &cp)
Send a command to the server.
NetworkRecvStatus Receive_SERVER_FRAME(Packet &p) override
Sends the current frame counter to the client: uint32_t Frame counter uint32_t Frame counter max (how...
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data)
Send a chat-packet over the network.
NetworkRecvStatus Receive_SERVER_COMMAND(Packet &p) override
Sends a DoCommand to the client: uint8_t ID of the company (0..MAX_COMPANIES-1).
NetworkRecvStatus Receive_SERVER_NEWGAME(Packet &p) override
Let the clients know that the server is loading a new map.
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override
Close the network connection due to the given status.
static NetworkRecvStatus SendGetMap()
Request the map from the server.
ClientNetworkGameSocketHandler(SOCKET s, const std::string &connection_string)
Create a new socket for the client side of the game connection.
NetworkRecvStatus Receive_SERVER_AUTH_REQUEST(Packet &p) override
Indication to the client that it needs to authenticate: uint8_t The NetworkAuthenticationMethod to us...
NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet &p) override
Sends the data of the map to the client: Contains a part of the map (until max size of packet).
NetworkRecvStatus Receive_SERVER_ERROR(Packet &p) override
The client made an error: uint8_t Error code caused (see NetworkErrorCode).
static NetworkRecvStatus SendError(NetworkErrorCode errorno)
Send an error-packet over the network.
NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet &p) override
Let the clients know that the server is closing.
static NetworkRecvStatus SendJoin()
Tell the server we would like to join.
NetworkRecvStatus Receive_SERVER_FULL(Packet &p) override
Notification that the server is full.
@ READY_FOR_RESPONSE
We do not have to wait for user input, and can immediately respond to the server.
@ AWAIT_USER_INPUT
We have requested some user input, but must wait on that.
@ INVALID
We have received an invalid request.
static std::unique_ptr< NetworkAuthenticationClientHandler > Create(std::shared_ptr< NetworkAuthenticationPasswordRequestHandler > password_handler, std::string &secret_key, std::string &public_key)
Create a NetworkAuthenticationClientHandler.
Callback interface for client implementations to provide the handling of the password requests.
Base socket handler for all TCP sockets.
Definition: tcp_game.h:141
NetworkRecvStatus ReceivePackets()
Do the actual receiving of packets.
Definition: tcp_game.cpp:134
ClientID client_id
Client identifier.
Definition: tcp_game.h:486
CommandQueue incoming_queue
The command-queue awaiting handling.
Definition: tcp_game.h:489
std::chrono::steady_clock::time_point last_packet
Time we received the last frame.
Definition: tcp_game.h:490
void SetInfo(NetworkClientInfo *info)
Sets the client info for this socket handler.
Definition: tcp_game.h:505
NetworkClientInfo * GetInfo() const
Gets the client info of this socket handler.
Definition: tcp_game.h:515
const char * ReceiveCommand(Packet &p, CommandPacket &cp)
Receives a command from the network.
NetworkRecvStatus CloseConnection(bool error=true) override
Functions to help ReceivePacket/SendPacket a bit A socket can make errors.
Definition: tcp_game.cpp:43
void MarkClosed()
Mark the connection as closed.
Definition: core.h:66
bool HasClientQuit() const
Whether the current client connected to the socket has quit.
Definition: core.h:74
std::unique_ptr< class NetworkEncryptionHandler > send_encryption_handler
The handler for encrypting sent packets.
Definition: core.h:50
std::unique_ptr< class NetworkEncryptionHandler > receive_encryption_handler
The handler for decrypting received packets.
Definition: core.h:49
SOCKET sock
The socket currently connected to.
Definition: tcp.h:38
virtual void SendPacket(std::unique_ptr< Packet > &&packet)
This function puts the packet in the send-queue and it is send as soon as possible.
Definition: tcp.cpp:68
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition: tcp.cpp:86
bool CanSendReceive()
Check whether this socket can send or receive something.
Definition: tcp.cpp:204
static void EventEnterMultiplayer(uint map_width, uint map_height)
Event: user entered a multiplayer game.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Date date
Current date in days (day counter).
static DateFract date_fract
Fractional part of the day.
TextColour GetDrawStringCompanyColour(CompanyID company)
Get the colour for DrawString-subroutines which matches the colour of the company.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
void SetLocalCompany(CompanyID new_company)
Sets the local company and updates the settings that are set on a per-company basis to reflect the co...
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
@ CCA_NEW
Create a new company.
Definition: company_type.h:68
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ INVALID_COMPANY
An invalid company.
Definition: company_type.h:30
@ COMPANY_SPECTATOR
The client is spectating.
Definition: company_type.h:35
@ COMPANY_NEW_COMPANY
The client wants a new company.
Definition: company_type.h:34
@ CRR_NONE
Dummy reason for actions that don't need one.
Definition: company_type.h:63
static const uint NETWORK_CHAT_LENGTH
The maximum length of a chat message, in bytes including '\0'.
Definition: config.h:62
static const uint NETWORK_NAME_LENGTH
The maximum length of the server name and map name, in bytes including '\0'.
Definition: config.h:53
static const uint NETWORK_PUBLIC_KEY_LENGTH
The maximum length of the hexadecimal encoded public keys, in bytes including '\0'.
Definition: config.h:102
static const uint NETWORK_RCONCOMMAND_LENGTH
The maximum length of a rconsole command, in bytes including '\0'.
Definition: config.h:60
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Definition: console.cpp:89
bool IsValidConsoleColour(TextColour c)
Check whether the given TextColour is valid for console usage.
static const TextColour CC_WARNING
Colour for warning lines.
Definition: console_type.h:25
static const TextColour CC_DEFAULT
Default colour of the console.
Definition: console_type.h:23
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
Definition: core.h:23
@ NETWORK_RECV_STATUS_DESYNC
A desync did occur.
Definition: core.h:25
@ NETWORK_RECV_STATUS_CLIENT_QUIT
The connection is lost gracefully. Other clients are already informed of this leaving client.
Definition: core.h:28
@ NETWORK_RECV_STATUS_SERVER_ERROR
The server told us we made an error.
Definition: core.h:30
@ NETWORK_RECV_STATUS_SAVEGAME
Something went wrong (down)loading the savegame.
Definition: core.h:27
@ NETWORK_RECV_STATUS_CLOSE_QUERY
Done querying the server.
Definition: core.h:33
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
Definition: core.h:24
@ NETWORK_RECV_STATUS_NEWGRF_MISMATCH
We did not have the required NewGRFs.
Definition: core.h:26
@ NETWORK_RECV_STATUS_SERVER_FULL
The server is full.
Definition: core.h:31
@ NETWORK_RECV_STATUS_MALFORMED_PACKET
We apparently send a malformed packet.
Definition: core.h:29
@ NETWORK_RECV_STATUS_SERVER_BANNED
The server has banned us.
Definition: core.h:32
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
void ClearErrorMessages()
Clear all errors from the queue.
Definition: error_gui.cpp:328
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
@ WL_ERROR
Errors (eg. saving/loading failed)
Definition: error.h:26
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition: error.h:27
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition: error.h:24
@ FT_SAVEGAME
old or new savegame
Definition: fileio_type.h:18
SaveLoadOperation
Operation performed on the file.
Definition: fileio_type.h:53
@ SLO_LOAD
File is being loaded.
Definition: fileio_type.h:55
DetailedFileType
Kinds of files in each AbstractFileType.
Definition: fileio_type.h:29
@ DFT_GAME_FILE
Save game or scenario file.
Definition: fileio_type.h:32
Subdirectory
The different kinds of subdirectories OpenTTD uses.
Definition: fileio_type.h:115
@ NO_DIRECTORY
A path without any base directory.
Definition: fileio_type.h:133
GameSessionStats _game_session_stats
Statistics about the current session.
Definition: gfx.cpp:51
SwitchMode _switch_mode
The next mainloop command.
Definition: gfx.cpp:49
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:260
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition: gfx_type.h:325
StringID GetNetworkErrorMsg(NetworkErrorCode err)
Retrieve the string id of an internal error number.
Definition: network.cpp:315
uint32_t _frame_counter_server
The frame_counter of the server, if in network-mode.
Definition: network.cpp:76
uint32_t _frame_counter
The current frame.
Definition: network.cpp:78
uint8_t _network_reconnect
Reconnect timeout.
Definition: network.cpp:72
bool _networking
are we in networking mode?
Definition: network.cpp:65
bool _network_server
network-server is active
Definition: network.cpp:66
uint32_t _sync_seed_1
Seed to compare during sync checks.
Definition: network.cpp:81
uint32_t _sync_frame
The frame to perform the sync check.
Definition: network.cpp:85
ClientID _network_own_client_id
Our client identifier.
Definition: network.cpp:70
bool _network_first_time
Whether we have finished joining or not.
Definition: network.cpp:86
uint32_t _frame_counter_max
To where we may go with our clients.
Definition: network.cpp:77
Basic functions/variables used all over the place.
Base core network types and some helper functions to access them.
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data)
Send a chat message.
void NetworkUpdateClientName(const std::string &client_name)
Send the server our name as callback from the setting.
NetworkJoinInfo _network_join
Information about the game to join to.
bool NetworkIsValidClientName(const std::string_view client_name)
Check whether the given client name is deemed valid for use in network games.
bool NetworkValidateOurClientName()
Convenience method for NetworkValidateClientName on _settings_client.network.client_name.
void ClientNetworkEmergencySave()
Create an emergency savegame when the network connection is lost.
static uint32_t last_ack_frame
Last frame we performed an ack.
bool NetworkMaxCompaniesReached()
Check if max_companies has been reached on the server (local check only).
uint NetworkMaxCompaniesAllowed()
Get the maximum number of companies that are allowed by the server.
void NetworkClient_Connected()
Is called after a client is connected to the server.
void NetworkClientsToSpectators(CompanyID cid)
Move the clients of a company to the spectators.
static uint8_t _network_server_max_companies
Maximum number of companies of the currently joined server.
bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio)
Tell whether the client has team members who they can chat to.
std::string _network_server_name
The current name of the server you are on.
void NetworkClientRequestMove(CompanyID company_id)
Notify the server of this client wanting to be moved to another company.
bool NetworkValidateClientName(std::string &client_name)
Trim the given client name in place, i.e.
void NetworkClientSendRcon(const std::string &password, const std::string &command)
Send a remote console command.
Client part of the network protocol.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
Handling of the list of games.
NetworkJoinStatus _network_join_status
The status of joining.
uint8_t _network_join_waiting
The number of clients waiting in front of us.
uint32_t _network_join_bytes_total
The total number of bytes to download.
uint32_t _network_join_bytes
The number of bytes we already downloaded.
GUIs related to networking.
bool NetworkMakeClientNameUnique(std::string &new_name)
Check whether a name is unique, and otherwise try to make it unique.
DestType
Destination of our chat messages.
Definition: network_type.h:79
NetworkAction
Actions that can be used for NetworkTextMessage.
Definition: network_type.h:90
ClientID
'Unique' identifier to be given to clients
Definition: network_type.h:49
@ CLIENT_ID_SERVER
Servers always have this ID.
Definition: network_type.h:51
NetworkErrorCode
The error codes we send around in the protocols.
Definition: network_type.h:110
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
@ FGCM_EXACT
Only find Grfs matching md5sum.
bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, std::shared_ptr< LoadFilter > lf=nullptr)
Load the specified savegame but on error do different things.
Definition: openttd.cpp:943
void StateGameLoop()
State controlling game loop.
Definition: openttd.cpp:1212
@ SM_MENU
Switch to game intro menu.
Definition: openttd.h:33
GameMode
Mode which defines the state of the game.
Definition: openttd.h:18
Randomizer _random
Random used in the game state calculations.
Definition: random_func.cpp:37
void DoAutoOrNetsave(FiosNumberedSaveName &counter)
Create an autosave or netsave.
Definition: saveload.cpp:3183
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
Definition: saveload.cpp:60
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: stdafx.h:334
#define lengthof(array)
Return the length of an fixed size array.
Definition: stdafx.h:280
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition: string.cpp:81
void StrTrimInPlace(std::string &str)
Trim the spaces from given string in place, i.e.
Definition: string.cpp:260
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:319
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:357
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Class to backup a specific variable and restore it later.
Definition: backup_type.hpp:21
void Restore()
Restore the variable.
NetworkSettings network
settings related to the network
GUISettings gui
settings related to the GUI
Everything we need to know about a command to be able to execute it.
uint32_t frame
the frame in which this packet is executed
bool my_cmd
did the command originate from "me"
Commands cmd
command being executed.
void SetMode(FiosType ft)
Set the mode and file type of the file to save or load based on the type of file entry at the file sy...
Definition: saveload.cpp:3252
A savegame name automatically numbered.
Definition: fios.h:130
Information about GRF, used in the game and (part of it) in savegames.
Basic data to distinguish a GRF.
Definition: newgrf_config.h:82
uint32_t grfid
GRF ID (defined by Action 0x08)
Definition: newgrf_config.h:83
MD5Hash md5sum
MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
Definition: newgrf_config.h:84
bool prefer_teamchat
choose the chat message target with <ENTER>, true=all clients, false=your team
std::chrono::steady_clock::time_point start_time
Time when the current game was started.
Definition: openttd.h:56
std::optional< size_t > savegame_size
Size of the last saved savegame in bytes, or std::nullopt if not saved yet.
Definition: openttd.h:58
Interface for filtering a savegame till it is loaded.
static uint SizeY()
Get the size of the map along the Y.
Definition: map_func.h:279
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition: map_func.h:270
Container for all information known about a client.
Definition: network_base.h:24
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition: network.cpp:118
CompanyID client_playas
As which company is this client playing (CompanyID)
Definition: network_base.h:28
std::string client_name
Name of the client.
Definition: network_base.h:26
std::string public_key
The public key of the client.
Definition: network_base.h:27
Information required to join a server.
std::string server_password
The password of the server to join.
CompanyID company
The company to join.
std::string client_secret_key
The secret key of the client for authorized key logins.
uint8_t max_companies
maximum amount of companies
std::string client_name
name of the player (as client)
std::string client_public_key
The public key of the client for authorized key logins.
Read some packets, and when do use that data as initial load filter.
size_t Read(uint8_t *rbuf, size_t size) override
Read a given number of bytes from the savegame.
PacketReader()
Initialise everything.
size_t read_bytes
The total number of read bytes.
size_t written_bytes
The total number of bytes we've written.
void AddPacket(Packet &p)
Add a packet to this buffer.
uint8_t * bufe
End of the buffer we write to/read from.
uint8_t ** block
The block we're reading from/writing to.
std::vector< uint8_t * > blocks
Buffer with blocks of allocated memory.
void Reset() override
Reset this filter to read from the beginning of the file.
static ssize_t TransferOutMemCopy(PacketReader *destination, const char *source, size_t amount)
Simple wrapper around fwrite to be able to pass it to Packet's TransferOut.
uint8_t * buf
Buffer we're going to write to/read from.
static const size_t CHUNK
32 KiB chunks of memory.
Internal entity of a packet.
Definition: packet.h:42
uint16_t Recv_uint16()
Read a 16 bits integer from the packet.
Definition: packet.cpp:332
ssize_t TransferOutWithLimit(F transfer_function, size_t limit, D destination, Args &&... args)
Transfer data from the packet to the given function.
Definition: packet.h:109
uint64_t Recv_uint64()
Read a 64 bits integer from the packet.
Definition: packet.cpp:364
bool Recv_bool()
Read a boolean from the packet.
Definition: packet.cpp:309
uint32_t Recv_uint32()
Read a 32 bits integer from the packet.
Definition: packet.cpp:347
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
Definition: packet.cpp:318
size_t RemainingBytesToTransfer() const
Get the amount of bytes that are still available for the Transfer functions.
Definition: packet.cpp:447
bool CanReadFromPacket(size_t bytes_to_read, bool close_connection=false)
Is it safe to read from the packet, i.e.
Definition: packet.cpp:219
std::string Recv_string(size_t length, StringValidationSettings settings=SVS_REPLACE_WITH_QUESTION_MARK)
Reads characters (bytes) from the packet until it finds a '\0', or reaches a maximum of length charac...
Definition: packet.cpp:425
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition: pool_type.hpp:369
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition: pool_type.hpp:309
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
uint32_t state[2]
The state of the randomizer.
Definition: random_func.hpp:29
@ PACKET_CLIENT_IDENTIFY
Client telling the server the client's name and requested company.
Definition: tcp_game.h:68
@ PACKET_CLIENT_GETMAP
Client requests the actual map.
Definition: tcp_game.h:79
@ PACKET_CLIENT_ERROR
A client reports an error to the server.
Definition: tcp_game.h:124
@ PACKET_CLIENT_JOIN
The client telling the server it wants to join.
Definition: tcp_game.h:37
@ PACKET_CLIENT_AUTH_RESPONSE
The client responds to the authentication request.
Definition: tcp_game.h:64
@ PACKET_CLIENT_NEWGRFS_CHECKED
Client acknowledges that it has all required NewGRFs.
Definition: tcp_game.h:72
@ PACKET_CLIENT_COMMAND
Client executed a command and sends it to the server.
Definition: tcp_game.h:101
@ PACKET_CLIENT_SET_NAME
A client changes its name.
Definition: tcp_game.h:118
@ PACKET_CLIENT_ACK
The client tells the server which frame it has executed.
Definition: tcp_game.h:97
@ PACKET_CLIENT_RCON
Client asks the server to execute some command.
Definition: tcp_game.h:110
@ PACKET_CLIENT_MAP_OK
Client tells the server that it received the whole map.
Definition: tcp_game.h:85
@ PACKET_CLIENT_QUIT
A client tells the server it is going to quit.
Definition: tcp_game.h:122
@ PACKET_CLIENT_MOVE
A client would like to be moved to another company.
Definition: tcp_game.h:114
@ PACKET_CLIENT_CHAT
Client said something that should be distributed.
Definition: tcp_game.h:105
void CSleep(int milliseconds)
Sleep on the current thread for a defined time.
Definition: thread.h:24
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition: window.cpp:3211
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
@ WN_NETWORK_STATUS_WINDOW_JOIN
Network join status.
Definition: window_type.h:39
@ WC_CLIENT_LIST
Client list; Window numbers:
Definition: window_type.h:484
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers:
Definition: window_type.h:491