OpenTTD Source 20241222-master-gc72542431a
network_server.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 "../strings_func.h"
12#include "core/network_game_info.h"
13#include "network_admin.h"
14#include "network_server.h"
15#include "network_udp.h"
16#include "network_base.h"
17#include "../console_func.h"
18#include "../company_base.h"
19#include "../command_func.h"
20#include "../saveload/saveload.h"
21#include "../saveload/saveload_filter.h"
22#include "../station_base.h"
23#include "../genworld.h"
24#include "../company_func.h"
25#include "../company_gui.h"
26#include "../company_cmd.h"
27#include "../roadveh.h"
28#include "../order_backup.h"
29#include "../core/pool_func.hpp"
30#include "../core/random_func.hpp"
31#include "../company_cmd.h"
32#include "../rev.h"
33#include "../timer/timer.h"
34#include "../timer/timer_game_calendar.h"
35#include "../timer/timer_game_economy.h"
36#include "../timer/timer_game_realtime.h"
37#include <mutex>
38#include <condition_variable>
39
40#include "../safeguards.h"
41
42
43/* This file handles all the server-commands */
44
48
50static_assert(MAX_CLIENT_SLOTS > MAX_CLIENTS);
52static_assert(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS);
53
56INSTANTIATE_POOL_METHODS(NetworkClientSocket)
57
60
64
65
69 std::unique_ptr<Packet> current;
70 size_t total_size;
71 std::deque<std::unique_ptr<Packet>> packets;
72 std::mutex mutex;
73 std::condition_variable exit_sig;
74
79 PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(nullptr), cs(cs), total_size(0)
80 {
81 }
82
85 {
86 std::unique_lock<std::mutex> lock(this->mutex);
87
88 if (this->cs != nullptr) this->exit_sig.wait(lock);
89
90 /* This must all wait until the Destroy function is called. */
91
92 this->packets.clear();
93 this->current = nullptr;
94 }
95
106 void Destroy()
107 {
108 std::unique_lock<std::mutex> lock(this->mutex);
109
110 this->cs = nullptr;
111
112 this->exit_sig.notify_all();
113 lock.unlock();
114
115 /* Make sure the saving is completely cancelled. Yes,
116 * we need to handle the save finish as well as the
117 * next connection might just be requesting a map. */
118 WaitTillSaved();
119 }
120
127 {
128 /* Unsafe check for the queue being empty or not. */
129 if (this->packets.empty()) return false;
130
131 std::lock_guard<std::mutex> lock(this->mutex);
132
133 while (!this->packets.empty()) {
134 bool last_packet = this->packets.front()->GetPacketType() == PACKET_SERVER_MAP_DONE;
135 this->cs->SendPacket(std::move(this->packets.front()));
136 this->packets.pop_front();
137
138 if (last_packet) return true;
139 }
140
141 return false;
142 }
143
144 void Write(uint8_t *buf, size_t size) override
145 {
146 std::lock_guard<std::mutex> lock(this->mutex);
147
148 /* We want to abort the saving when the socket is closed. */
149 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
150
151 if (this->current == nullptr) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
152
153 std::span<const uint8_t> to_write(buf, size);
154 while (!to_write.empty()) {
155 to_write = this->current->Send_bytes(to_write);
156
157 if (!this->current->CanWriteToPacket(1)) {
158 this->packets.push_back(std::move(this->current));
159 if (!to_write.empty()) this->current = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DATA, TCP_MTU);
160 }
161 }
162
163 this->total_size += size;
164 }
165
166 void Finish() override
167 {
168 std::lock_guard<std::mutex> lock(this->mutex);
169
170 /* We want to abort the saving when the socket is closed. */
171 if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
172
173 /* Make sure the last packet is flushed. */
174 if (this->current != nullptr) this->packets.push_back(std::move(this->current));
175
176 /* Add a packet stating that this is the end to the queue. */
177 this->packets.push_back(std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_DONE));
178
179 /* Fast-track the size to the client. */
180 auto p = std::make_unique<Packet>(this->cs, PACKET_SERVER_MAP_SIZE);
181 p->Send_uint32((uint32_t)this->total_size);
182 this->packets.push_front(std::move(p));
183 }
184};
185
186
192{
193 this->status = STATUS_INACTIVE;
196
197 Debug(net, 9, "client[{}] status = INACTIVE", this->client_id);
198
199 /* The Socket and Info pools need to be the same in size. After all,
200 * each Socket will be associated with at most one Info object. As
201 * such if the Socket was allocated the Info object can as well. */
203}
204
209{
210 delete this->GetInfo();
211
214
215 if (this->savegame != nullptr) {
216 this->savegame->Destroy();
217 this->savegame = nullptr;
218 }
219
221}
222
224{
225 /* Only allow receiving when we have some buffer free; this value
226 * can go negative, but eventually it will become positive again. */
227 if (this->receive_limit <= 0) return nullptr;
228
229 /* We can receive a packet, so try that and if needed account for
230 * the amount of received data. */
231 std::unique_ptr<Packet> p = this->NetworkTCPSocketHandler::ReceivePacket();
232 if (p != nullptr) this->receive_limit -= p->Size();
233 return p;
234}
235
237{
239 /*
240 * Sending a message just before leaving the game calls cs->SendPackets.
241 * This might invoke this function, which means that when we close the
242 * connection after cs->SendPackets we will close an already closed
243 * connection. This handles that case gracefully without having to make
244 * that code any more complex or more aware of the validity of the socket.
245 */
246 if (this->IsPendingDeletion() || this->sock == INVALID_SOCKET) return status;
247
249 /* We did not receive a leave message from this client... */
250 std::string client_name = this->GetClientName();
251
252 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
253
254 /* Inform other clients of this... strange leaving ;) */
256 if (new_cs->status >= STATUS_AUTHORIZED && this != new_cs) {
257 new_cs->SendErrorQuit(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
258 }
259 }
260 }
261
262 /* If we were transfering a map to this client, stop the savegame creation
263 * process and queue the next client to receive the map. */
264 if (this->status == STATUS_MAP) {
265 /* Ensure the saving of the game is stopped too. */
266 this->savegame->Destroy();
267 this->savegame = nullptr;
268
269 this->CheckNextClientToSendMap(this);
270 }
271
272 NetworkAdminClientError(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
273 Debug(net, 3, "[{}] Client #{} closed connection", ServerNetworkGameSocketHandler::GetName(), this->client_id);
274
275 /* We just lost one client :( */
276 if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
277 extern uint8_t _network_clients_connected;
279
280 this->SendPackets(true);
281
282 this->DeferDeletion();
283
284 return status;
285}
286
292{
293 extern uint8_t _network_clients_connected;
295
296 /* We can't go over the MAX_CLIENTS limit here. However, the
297 * pool must have place for all clients and ourself. */
300 return accept;
301}
302
305{
307 if (cs->writable) {
308 if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
309 /* This client is in the middle of a map-send, call the function for that */
310 cs->SendMap();
311 }
312 }
313 }
314}
315
316static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
317
318/***********
319 * Sending functions
320 ************/
321
327{
328 Debug(net, 9, "client[{}] SendClientInfo(): client_id={}", this->client_id, ci->client_id);
329
330 if (ci->client_id != INVALID_CLIENT_ID) {
331 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CLIENT_INFO);
332 p->Send_uint32(ci->client_id);
333 p->Send_uint8 (ci->client_playas);
334 p->Send_string(ci->client_name);
335 p->Send_string(ci->public_key);
336
337 this->SendPacket(std::move(p));
338 }
340}
341
344{
345 Debug(net, 9, "client[{}] SendGameInfo()", this->client_id);
346
347 auto p = std::make_unique<Packet>(this, PACKET_SERVER_GAME_INFO, TCP_MTU);
348 SerializeNetworkGameInfo(*p, GetCurrentNetworkServerGameInfo());
349
350 this->SendPacket(std::move(p));
351
353}
354
361{
362 Debug(net, 9, "client[{}] SendError(): error={}", this->client_id, error);
363
364 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR);
365
366 p->Send_uint8(error);
367 if (!reason.empty()) p->Send_string(reason);
368 this->SendPacket(std::move(p));
369
370 StringID strid = GetNetworkErrorMsg(error);
371
372 /* Only send when the current client was in game */
373 if (this->status >= STATUS_AUTHORIZED) {
374 std::string client_name = this->GetClientName();
375
376 Debug(net, 1, "'{}' made an error and has been disconnected: {}", client_name, GetString(strid));
377
378 if (error == NETWORK_ERROR_KICKED && !reason.empty()) {
379 NetworkTextMessage(NETWORK_ACTION_KICKED, CC_DEFAULT, false, client_name, reason, strid);
380 } else {
381 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", strid);
382 }
383
385 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
386 /* Some errors we filter to a more general error. Clients don't have to know the real
387 * reason a joining failed. */
388 if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) {
389 error = NETWORK_ERROR_ILLEGAL_PACKET;
390 }
391 new_cs->SendErrorQuit(this->client_id, error);
392 }
393 }
394
396 } else {
397 Debug(net, 1, "Client {} made an error and has been disconnected: {}", this->client_id, GetString(strid));
398 }
399
400 /* The client made a mistake, so drop the connection now! */
402}
403
406{
407 Debug(net, 9, "client[{}] SendNewGRFCheck()", this->client_id);
408
409 /* Invalid packet when status is anything but STATUS_IDENTIFY. */
411
412 Debug(net, 9, "client[{}] status = NEWGRFS_CHECK", this->client_id);
414
415 if (_grfconfig == nullptr) {
416 /* There are no NewGRFs, so they're welcome. */
417 return this->SendWelcome();
418 }
419
420 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
421 const GRFConfig *c;
422 uint grf_count = 0;
423
424 for (c = _grfconfig; c != nullptr; c = c->next) {
425 if (!HasBit(c->flags, GCF_STATIC)) grf_count++;
426 }
427
428 p->Send_uint8 (grf_count);
429 for (c = _grfconfig; c != nullptr; c = c->next) {
430 if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(*p, c->ident);
431 }
432
433 this->SendPacket(std::move(p));
435}
436
439{
440 Debug(net, 9, "client[{}] SendAuthRequest()", this->client_id);
441
442 /* Invalid packet when status is anything but STATUS_INACTIVE or STATUS_AUTH_GAME. */
444
445 Debug(net, 9, "client[{}] status = AUTH_GAME", this->client_id);
446 this->status = STATUS_AUTH_GAME;
447
448 /* Reset 'lag' counters */
450
451 if (this->authentication_handler == nullptr) {
453 }
454
455 auto p = std::make_unique<Packet>(this, PACKET_SERVER_AUTH_REQUEST);
456 this->authentication_handler->SendRequest(*p);
457
458 this->SendPacket(std::move(p));
460}
461
464{
465 Debug(net, 9, "client[{}] SendEnableEncryption()", this->client_id);
466
467 /* Invalid packet when status is anything but STATUS_AUTH_GAME. */
469
470 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ENABLE_ENCRYPTION);
471 this->authentication_handler->SendEnableEncryption(*p);
472 this->SendPacket(std::move(p));
474}
475
478{
479 Debug(net, 9, "client[{}] SendWelcome()", this->client_id);
480
481 /* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
483
484 Debug(net, 9, "client[{}] status = AUTHORIZED", this->client_id);
486
487 /* Reset 'lag' counters */
489
490 _network_game_info.clients_on++;
491
492 auto p = std::make_unique<Packet>(this, PACKET_SERVER_WELCOME);
493 p->Send_uint32(this->client_id);
494 this->SendPacket(std::move(p));
495
496 /* Transmit info about all the active clients */
498 if (new_cs != this && new_cs->status >= STATUS_AUTHORIZED) {
499 this->SendClientInfo(new_cs->GetInfo());
500 }
501 }
502 /* Also send the info of the server */
504}
505
508{
509 Debug(net, 9, "client[{}] SendWait()", this->client_id);
510
511 int waiting = 1; // current player getting the map counts as 1
512
513 /* Count how many clients are waiting in the queue, in front of you! */
515 if (new_cs->status != STATUS_MAP_WAIT) continue;
516 if (new_cs->GetInfo()->join_date < this->GetInfo()->join_date || (new_cs->GetInfo()->join_date == this->GetInfo()->join_date && new_cs->client_id < this->client_id)) waiting++;
517 }
518
519 auto p = std::make_unique<Packet>(this, PACKET_SERVER_WAIT);
520 p->Send_uint8(waiting);
521 this->SendPacket(std::move(p));
523}
524
525void ServerNetworkGameSocketHandler::CheckNextClientToSendMap(NetworkClientSocket *ignore_cs)
526{
527 Debug(net, 9, "client[{}] CheckNextClientToSendMap()", this->client_id);
528
529 /* Find the best candidate for joining, i.e. the first joiner. */
530 NetworkClientSocket *best = nullptr;
531 for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) {
532 if (ignore_cs == new_cs) continue;
533
534 if (new_cs->status == STATUS_MAP_WAIT) {
535 if (best == nullptr || best->GetInfo()->join_date > new_cs->GetInfo()->join_date || (best->GetInfo()->join_date == new_cs->GetInfo()->join_date && best->client_id > new_cs->client_id)) {
536 best = new_cs;
537 }
538 }
539 }
540
541 /* Is there someone else to join? */
542 if (best != nullptr) {
543 /* Let the first start joining. */
544 best->status = STATUS_AUTHORIZED;
545 best->SendMap();
546
547 /* And update the rest. */
548 for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) {
549 if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait();
550 }
551 }
552}
553
556{
557 if (this->status < STATUS_AUTHORIZED) {
558 /* Illegal call, return error and ignore the packet */
559 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
560 }
561
562 if (this->status == STATUS_AUTHORIZED) {
563 Debug(net, 9, "client[{}] SendMap(): first_packet", this->client_id);
564
565 WaitTillSaved();
566 this->savegame = std::make_shared<PacketWriter>(this);
567
568 /* Now send the _frame_counter and how many packets are coming */
569 auto p = std::make_unique<Packet>(this, PACKET_SERVER_MAP_BEGIN);
570 p->Send_uint32(_frame_counter);
571 this->SendPacket(std::move(p));
572
574 Debug(net, 9, "client[{}] status = MAP", this->client_id);
575 this->status = STATUS_MAP;
576 /* Mark the start of download */
579
580 /* Make a dump of the current game */
581 if (SaveWithFilter(this->savegame, true) != SL_OK) UserError("network savedump failed");
582 }
583
584 if (this->status == STATUS_MAP) {
585 bool last_packet = this->savegame->TransferToNetworkQueue();
586 if (last_packet) {
587 Debug(net, 9, "client[{}] SendMap(): last_packet", this->client_id);
588
589 /* Done reading, make sure saving is done as well */
590 this->savegame->Destroy();
591 this->savegame = nullptr;
592
593 /* Set the status to DONE_MAP, no we will wait for the client
594 * to send it is ready (maybe that happens like never ;)) */
595 Debug(net, 9, "client[{}] status = DONE_MAP", this->client_id);
596 this->status = STATUS_DONE_MAP;
597
598 this->CheckNextClientToSendMap();
599 }
600 }
602}
603
609{
610 Debug(net, 9, "client[{}] SendJoin(): client_id={}", this->client_id, client_id);
611
612 auto p = std::make_unique<Packet>(this, PACKET_SERVER_JOIN);
613
614 p->Send_uint32(client_id);
615
616 this->SendPacket(std::move(p));
618}
619
622{
623 auto p = std::make_unique<Packet>(this, PACKET_SERVER_FRAME);
624 p->Send_uint32(_frame_counter);
625 p->Send_uint32(_frame_counter_max);
626#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
627 p->Send_uint32(_sync_seed_1);
628#ifdef NETWORK_SEND_DOUBLE_SEED
629 p->Send_uint32(_sync_seed_2);
630#endif
631#endif
632
633 /* If token equals 0, we need to make a new token and send that. */
634 if (this->last_token == 0) {
635 this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1;
636 p->Send_uint8(this->last_token);
637 }
638
639 this->SendPacket(std::move(p));
641}
642
645{
646 Debug(net, 9, "client[{}] SendSync(), frame_counter={}, sync_seed_1={}", this->client_id, _frame_counter, _sync_seed_1);
647
648 auto p = std::make_unique<Packet>(this, PACKET_SERVER_SYNC);
649 p->Send_uint32(_frame_counter);
650 p->Send_uint32(_sync_seed_1);
651
652#ifdef NETWORK_SEND_DOUBLE_SEED
653 p->Send_uint32(_sync_seed_2);
654#endif
655 this->SendPacket(std::move(p));
657}
658
664{
665 Debug(net, 9, "client[{}] SendCommand(): cmd={}", this->client_id, cp.cmd);
666
667 auto p = std::make_unique<Packet>(this, PACKET_SERVER_COMMAND);
668
670 p->Send_uint32(cp.frame);
671 p->Send_bool (cp.my_cmd);
672
673 this->SendPacket(std::move(p));
675}
676
685NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, const std::string &msg, int64_t data)
686{
687 Debug(net, 9, "client[{}] SendChat(): action={}, client_id={}, self_send={}", this->client_id, action, client_id, self_send);
688
690
691 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHAT);
692
693 p->Send_uint8 (action);
694 p->Send_uint32(client_id);
695 p->Send_bool (self_send);
696 p->Send_string(msg);
697 p->Send_uint64(data);
698
699 this->SendPacket(std::move(p));
701}
702
710NetworkRecvStatus ServerNetworkGameSocketHandler::SendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
711{
712 Debug(net, 9, "client[{}] SendExternalChat(): source={}", this->client_id, source);
713
715
716 auto p = std::make_unique<Packet>(this, PACKET_SERVER_EXTERNAL_CHAT);
717
718 p->Send_string(source);
719 p->Send_uint16(colour);
720 p->Send_string(user);
721 p->Send_string(msg);
722
723 this->SendPacket(std::move(p));
725}
726
733{
734 Debug(net, 9, "client[{}] SendErrorQuit(): client_id={}, errorno={}", this->client_id, client_id, errorno);
735
736 auto p = std::make_unique<Packet>(this, PACKET_SERVER_ERROR_QUIT);
737
738 p->Send_uint32(client_id);
739 p->Send_uint8 (errorno);
740
741 this->SendPacket(std::move(p));
743}
744
750{
751 Debug(net, 9, "client[{}] SendQuit(): client_id={}", this->client_id, client_id);
752
753 auto p = std::make_unique<Packet>(this, PACKET_SERVER_QUIT);
754
755 p->Send_uint32(client_id);
756
757 this->SendPacket(std::move(p));
759}
760
763{
764 Debug(net, 9, "client[{}] SendShutdown()", this->client_id);
765
766 auto p = std::make_unique<Packet>(this, PACKET_SERVER_SHUTDOWN);
767 this->SendPacket(std::move(p));
769}
770
773{
774 Debug(net, 9, "client[{}] SendNewGame()", this->client_id);
775
776 auto p = std::make_unique<Packet>(this, PACKET_SERVER_NEWGAME);
777 this->SendPacket(std::move(p));
779}
780
786NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16_t colour, const std::string &command)
787{
788 Debug(net, 9, "client[{}] SendRConResult()", this->client_id);
789
790 auto p = std::make_unique<Packet>(this, PACKET_SERVER_RCON);
791
792 p->Send_uint16(colour);
793 p->Send_string(command);
794 this->SendPacket(std::move(p));
796}
797
804{
805 Debug(net, 9, "client[{}] SendMove(): client_id={}", this->client_id, client_id);
806
807 auto p = std::make_unique<Packet>(this, PACKET_SERVER_MOVE);
808
809 p->Send_uint32(client_id);
810 p->Send_uint8(company_id);
811 this->SendPacket(std::move(p));
813}
814
817{
818 Debug(net, 9, "client[{}] SendConfigUpdate()", this->client_id);
819
820 auto p = std::make_unique<Packet>(this, PACKET_SERVER_CONFIG_UPDATE);
821
823 p->Send_string(_settings_client.network.server_name);
824 this->SendPacket(std::move(p));
826}
827
828/***********
829 * Receiving functions
830 ************/
831
833{
834 Debug(net, 9, "client[{}] Receive_CLIENT_GAME_INFO()", this->client_id);
835
836 return this->SendGameInfo();
837}
838
840{
841 if (this->status != STATUS_NEWGRFS_CHECK) {
842 /* Illegal call, return error and ignore the packet */
843 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
844 }
845
846 Debug(net, 9, "client[{}] Receive_CLIENT_NEWGRFS_CHECKED()", this->client_id);
847
848 return this->SendWelcome();
849}
850
852{
853 if (this->status != STATUS_INACTIVE) {
854 /* Illegal call, return error and ignore the packet */
855 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
856 }
857
858 if (_network_game_info.clients_on >= _settings_client.network.max_clients) {
859 /* Turns out we are full. Inform the user about this. */
860 return this->SendError(NETWORK_ERROR_FULL);
861 }
862
863 std::string client_revision = p.Recv_string(NETWORK_REVISION_LENGTH);
864 uint32_t newgrf_version = p.Recv_uint32();
865
866 Debug(net, 9, "client[{}] Receive_CLIENT_JOIN(): client_revision={}, newgrf_version={}", this->client_id, client_revision, newgrf_version);
867
868 /* Check if the client has revision control enabled */
869 if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) {
870 /* Different revisions!! */
871 return this->SendError(NETWORK_ERROR_WRONG_REVISION);
872 }
873
874 return this->SendAuthRequest();
875}
876
878{
879 if (this->status != STATUS_IDENTIFY) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
880
881 Debug(net, 9, "client[{}] Receive_CLIENT_IDENTIFY()", this->client_id);
882
883 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
884 CompanyID playas = (Owner)p.Recv_uint8();
885
887
888 /* join another company does not affect these values */
889 switch (playas) {
890 case COMPANY_NEW_COMPANY: // New company
892 return this->SendError(NETWORK_ERROR_FULL);
893 }
894 break;
895 case COMPANY_SPECTATOR: // Spectator
896 break;
897 default: // Join another company (companies 1..MAX_COMPANIES (index 0..(MAX_COMPANIES-1)))
898 if (!Company::IsValidHumanID(playas)) {
899 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
900 }
901
902 if (!Company::Get(playas)->allow_list.Contains(this->peer_public_key)) {
903 /* When we're not authorized, just bump us to a spectator. */
904 playas = COMPANY_SPECTATOR;
905 }
906 break;
907 }
908
909 if (!NetworkIsValidClientName(client_name)) {
910 /* An invalid client name was given. However, the client ensures the name
911 * is valid before it is sent over the network, so something went horribly
912 * wrong. This is probably someone trying to troll us. */
913 return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
914 }
915
916 if (!NetworkMakeClientNameUnique(client_name)) { // Change name if duplicate
917 /* We could not create a name for this client */
918 return this->SendError(NETWORK_ERROR_NAME_IN_USE);
919 }
920
923 this->SetInfo(ci);
925 ci->client_name = client_name;
926 ci->client_playas = playas;
927 ci->public_key = this->peer_public_key;
928 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:02x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, (int)ci->client_playas, (int)ci->index);
929
930 /* Make sure companies to which people try to join are not autocleaned */
931 Company *c = Company::GetIfValid(playas);
932 if (c != nullptr) c->months_empty = 0;
933
934 return this->SendNewGRFCheck();
935}
936
937static NetworkErrorCode GetErrorForAuthenticationMethod(NetworkAuthenticationMethod method)
938{
939 switch (method) {
941 return NETWORK_ERROR_WRONG_PASSWORD;
943 return NETWORK_ERROR_NOT_ON_ALLOW_LIST;
944
945 default:
946 NOT_REACHED();
947 }
948}
949
951{
952 if (this->status != STATUS_AUTH_GAME) {
953 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
954 }
955
956 Debug(net, 9, "client[{}] Receive_CLIENT_AUTH_RESPONSE()", this->client_id);
957
958 auto authentication_method = this->authentication_handler->GetAuthenticationMethod();
959 switch (this->authentication_handler->ReceiveResponse(p)) {
961 break;
962
964 return this->SendAuthRequest();
965
967 default:
968 return this->SendError(GetErrorForAuthenticationMethod(authentication_method));
969 }
970
972 if (status != NETWORK_RECV_STATUS_OKAY) return status;
973
974 this->peer_public_key = this->authentication_handler->GetPeerPublicKey();
975 this->receive_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler();
976 this->send_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler();
977 this->authentication_handler = nullptr;
978
979 Debug(net, 9, "client[{}] status = IDENTIFY", this->client_id);
980 this->status = STATUS_IDENTIFY;
981
982 /* Reset 'lag' counters */
984
986}
987
989{
990 /* The client was never joined.. so this is impossible, right?
991 * Ignore the packet, give the client a warning, and close the connection */
992 if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) {
993 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
994 }
995
996 Debug(net, 9, "client[{}] Receive_CLIENT_GETMAP()", this->client_id);
997
998 /* Check if someone else is receiving the map */
1000 if (new_cs->status == STATUS_MAP) {
1001 /* Tell the new client to wait */
1002 Debug(net, 9, "client[{}] status = MAP_WAIT", this->client_id);
1003 this->status = STATUS_MAP_WAIT;
1004 return this->SendWait();
1005 }
1006 }
1007
1008 /* We receive a request to upload the map.. give it to the client! */
1009 return this->SendMap();
1010}
1011
1013{
1014 /* Client has the map, now start syncing */
1015 if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
1016 Debug(net, 9, "client[{}] Receive_CLIENT_MAP_OK()", this->client_id);
1017
1018 std::string client_name = this->GetClientName();
1019
1020 NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "", this->client_id);
1022
1023 Debug(net, 3, "[{}] Client #{} ({}) joined as {}", ServerNetworkGameSocketHandler::GetName(), this->client_id, this->GetClientIP(), client_name);
1024
1025 /* Mark the client as pre-active, and wait for an ACK
1026 * so we know it is done loading and in sync with us */
1027 Debug(net, 9, "client[{}] status = PRE_ACTIVE", this->client_id);
1028 this->status = STATUS_PRE_ACTIVE;
1030 this->SendFrame();
1031 this->SendSync();
1032
1033 /* This is the frame the client receives
1034 * we need it later on to make sure the client is not too slow */
1035 this->last_frame = _frame_counter;
1037
1039 if (new_cs->status >= STATUS_AUTHORIZED) {
1040 new_cs->SendClientInfo(this->GetInfo());
1041 new_cs->SendJoin(this->client_id);
1042 }
1043 }
1044
1045 NetworkAdminClientInfo(this, true);
1046
1047 /* also update the new client with our max values */
1048 return this->SendConfigUpdate();
1049 }
1050
1051 /* Wrong status for this packet, give a warning to client, and close connection */
1052 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1053}
1054
1060{
1061 /* The client was never joined.. so this is impossible, right?
1062 * Ignore the packet, give the client a warning, and close the connection */
1063 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1064 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1065 }
1066
1068 return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
1069 }
1070
1071 Debug(net, 9, "client[{}] Receive_CLIENT_COMMAND()", this->client_id);
1072
1073 CommandPacket cp;
1074 const char *err = this->ReceiveCommand(p, cp);
1075
1077
1078 NetworkClientInfo *ci = this->GetInfo();
1079
1080 if (err != nullptr) {
1081 IConsolePrint(CC_WARNING, "Dropping client #{} (IP: {}) due to {}.", ci->client_id, this->GetClientIP(), err);
1082 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1083 }
1084
1085
1087 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a server only command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1088 return this->SendError(NETWORK_ERROR_KICKED);
1089 }
1090
1092 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a non-spectator command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1093 return this->SendError(NETWORK_ERROR_KICKED);
1094 }
1095
1101 CompanyCtrlAction cca = cp.cmd == CMD_COMPANY_CTRL ? std::get<0>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_CTRL>::Args>(cp.data)) : CCA_NEW;
1102 if (!(cp.cmd == CMD_COMPANY_CTRL && cca == CCA_NEW && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
1103 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a command as another company {}.",
1104 ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
1105 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
1106 }
1107
1108 if (cp.cmd == CMD_COMPANY_CTRL) {
1109 if (cca != CCA_NEW || cp.company != COMPANY_SPECTATOR) {
1110 return this->SendError(NETWORK_ERROR_CHEATER);
1111 }
1112
1113 /* Check if we are full - else it's possible for spectators to send a CMD_COMPANY_CTRL and the company is created regardless of max_companies! */
1115 NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
1117 }
1118 }
1119
1120 if (cp.cmd == CMD_COMPANY_ALLOW_LIST_CTRL) {
1121 /* Maybe the client just got moved before allowing? */
1123
1124 /* Only allow clients to add/remove currently joined clients. The server owner does not go via this method, so is allowed to do more. */
1125 std::string public_key = std::get<1>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_ALLOW_LIST_CTRL>::Args>(cp.data));
1126 bool found = false;
1128 if (info->public_key == public_key) {
1129 found = true;
1130 break;
1131 }
1132 }
1133
1134 /* Maybe the client just left? */
1135 if (!found) return NETWORK_RECV_STATUS_OKAY;
1136 }
1137
1139
1140 this->incoming_queue.push_back(cp);
1142}
1143
1145{
1146 /* This packets means a client noticed an error and is reporting this
1147 * to us. Display the error and report it to the other clients */
1149
1150 Debug(net, 9, "client[{}] Receive_CLIENT_ERROR(): errorno={}", this->client_id, errorno);
1151
1152 /* The client was never joined.. thank the client for the packet, but ignore it */
1153 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1155 }
1156
1157 std::string client_name = this->GetClientName();
1158 StringID strid = GetNetworkErrorMsg(errorno);
1159
1160 Debug(net, 1, "'{}' reported an error and is closing its connection: {}", client_name, GetString(strid));
1161
1162 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", strid);
1163
1165 if (new_cs->status >= STATUS_AUTHORIZED) {
1166 new_cs->SendErrorQuit(this->client_id, errorno);
1167 }
1168 }
1169
1170 NetworkAdminClientError(this->client_id, errorno);
1171
1173}
1174
1176{
1177 /* The client was never joined.. thank the client for the packet, but ignore it */
1178 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1180 }
1181
1182 Debug(net, 9, "client[{}] Receive_CLIENT_QUIT()", this->client_id);
1183
1184 /* The client wants to leave. Display this and report it to the other clients. */
1185 std::string client_name = this->GetClientName();
1186 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "", STR_NETWORK_MESSAGE_CLIENT_LEAVING);
1187
1189 if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) {
1190 new_cs->SendQuit(this->client_id);
1191 }
1192 }
1193
1195
1197}
1198
1200{
1201 if (this->status < STATUS_AUTHORIZED) {
1202 /* Illegal call, return error and ignore the packet */
1203 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1204 }
1205
1206 uint32_t frame = p.Recv_uint32();
1207
1208 Debug(net, 9, "client[{}] Receive_CLIENT_ACK(): frame={}", this->client_id, frame);
1209
1210 /* The client is trying to catch up with the server */
1211 if (this->status == STATUS_PRE_ACTIVE) {
1212 /* The client is not yet caught up? */
1214
1215 /* Now it is! Unpause the game */
1216 Debug(net, 9, "client[{}] status = ACTIVE", this->client_id);
1217 this->status = STATUS_ACTIVE;
1219
1220 /* Execute script for, e.g. MOTD */
1221 IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
1222 }
1223
1224 /* Get, and validate the token. */
1225 uint8_t token = p.Recv_uint8();
1226 if (token == this->last_token) {
1227 /* We differentiate between last_token_frame and last_frame so the lag
1228 * test uses the actual lag of the client instead of the lag for getting
1229 * the token back and forth; after all, the token is only sent every
1230 * time we receive a PACKET_CLIENT_ACK, after which we will send a new
1231 * token to the client. If the lag would be one day, then we would not
1232 * be sending the new token soon enough for the new daily scheduled
1233 * PACKET_CLIENT_ACK. This would then register the lag of the client as
1234 * two days, even when it's only a single day. */
1236 /* Request a new token. */
1237 this->last_token = 0;
1238 }
1239
1240 /* The client received the frame, make note of it */
1241 this->last_frame = frame;
1242 /* With those 2 values we can calculate the lag realtime */
1245}
1246
1247
1258void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const std::string &msg, ClientID from_id, int64_t data, bool from_admin)
1259{
1260 const NetworkClientInfo *ci, *ci_own, *ci_to;
1261
1262 switch (desttype) {
1263 case DESTTYPE_CLIENT:
1264 /* Are we sending to the server? */
1265 if ((ClientID)dest == CLIENT_ID_SERVER) {
1267 /* Display the text locally, and that is it */
1268 if (ci != nullptr) {
1269 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1270
1272 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1273 }
1274 }
1275 } else {
1276 /* Else find the client to send the message to */
1277 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1278 if (cs->client_id == (ClientID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1279 cs->SendChat(action, from_id, false, msg, data);
1280 break;
1281 }
1282 }
1283 }
1284
1285 /* Display the message locally (so you know you have sent it) */
1286 if (from_id != (ClientID)dest) {
1287 if (from_id == CLIENT_ID_SERVER) {
1290 if (ci != nullptr && ci_to != nullptr) {
1291 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
1292 }
1293 } else {
1294 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1295 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1296 cs->SendChat(action, (ClientID)dest, true, msg, data);
1297 break;
1298 }
1299 }
1300 }
1301 }
1302 break;
1303 case DESTTYPE_TEAM: {
1304 /* If this is false, the message is already displayed on the client who sent it. */
1305 bool show_local = true;
1306 /* Find all clients that belong to this company */
1307 ci_to = nullptr;
1308 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1309 ci = cs->GetInfo();
1310 if (ci != nullptr && ci->client_playas == (CompanyID)dest && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1311 cs->SendChat(action, from_id, false, msg, data);
1312 if (cs->client_id == from_id) show_local = false;
1313 ci_to = ci; // Remember a client that is in the company for company-name
1314 }
1315 }
1316
1317 /* if the server can read it, let the admin network read it, too. */
1319 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1320 }
1321
1324 if (ci != nullptr && ci_own != nullptr && ci_own->client_playas == dest) {
1325 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1326 if (from_id == CLIENT_ID_SERVER) show_local = false;
1327 ci_to = ci_own;
1328 }
1329
1330 /* There is no such client */
1331 if (ci_to == nullptr) break;
1332
1333 /* Display the message locally (so you know you have sent it) */
1334 if (ci != nullptr && show_local) {
1335 if (from_id == CLIENT_ID_SERVER) {
1336 StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
1337 SetDParam(0, ci_to->client_playas);
1338 std::string name = GetString(str);
1339 NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
1340 } else {
1341 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1342 if (cs->client_id == from_id && cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) {
1343 cs->SendChat(action, ci_to->client_id, true, msg, data);
1344 }
1345 }
1346 }
1347 }
1348 break;
1349 }
1350 default:
1351 Debug(net, 1, "Received unknown chat destination type {}; doing broadcast instead", desttype);
1352 [[fallthrough]];
1353
1354 case DESTTYPE_BROADCAST:
1355 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1356 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendChat(action, from_id, false, msg, data);
1357 }
1358
1359 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1360
1362 if (ci != nullptr) {
1363 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data, "");
1364 }
1365 break;
1366 }
1367}
1368
1376void NetworkServerSendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
1377{
1378 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1379 if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) cs->SendExternalChat(source, colour, user, msg);
1380 }
1381 NetworkTextMessage(NETWORK_ACTION_EXTERNAL_CHAT, colour, false, user, msg, 0, source);
1382}
1383
1385{
1386 if (this->status < STATUS_PRE_ACTIVE) {
1387 /* Illegal call, return error and ignore the packet */
1388 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1389 }
1390
1392 DestType desttype = (DestType)p.Recv_uint8();
1393 int dest = p.Recv_uint32();
1394
1395 Debug(net, 9, "client[{}] Receive_CLIENT_CHAT(): action={}, desttype={}, dest={}", this->client_id, action, desttype, dest);
1396
1397 std::string msg = p.Recv_string(NETWORK_CHAT_LENGTH);
1398 int64_t data = p.Recv_uint64();
1399
1400 NetworkClientInfo *ci = this->GetInfo();
1401 switch (action) {
1402 case NETWORK_ACTION_CHAT:
1403 case NETWORK_ACTION_CHAT_CLIENT:
1404 case NETWORK_ACTION_CHAT_COMPANY:
1405 NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
1406 break;
1407 default:
1408 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to unknown chact action.", ci->client_id, this->GetClientIP());
1409 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1410 }
1412}
1413
1415{
1416 if (this->status != STATUS_ACTIVE) {
1417 /* Illegal call, return error and ignore the packet */
1418 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1419 }
1420
1421 Debug(net, 9, "client[{}] Receive_CLIENT_SET_NAME()", this->client_id);
1422
1424
1425 std::string client_name = p.Recv_string(NETWORK_CLIENT_NAME_LENGTH);
1426 ci = this->GetInfo();
1427
1429
1430 if (ci != nullptr) {
1431 if (!NetworkIsValidClientName(client_name)) {
1432 /* An invalid client name was given. However, the client ensures the name
1433 * is valid before it is sent over the network, so something went horribly
1434 * wrong. This is probably someone trying to troll us. */
1435 return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
1436 }
1437
1438 /* Display change */
1439 if (NetworkMakeClientNameUnique(client_name)) {
1440 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);
1441 ci->client_name = client_name;
1443 }
1444 }
1446}
1447
1449{
1450 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1451
1452 Debug(net, 9, "client[{}] Receive_CLIENT_RCON()", this->client_id);
1453
1454 std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
1455 std::string command = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH);
1456
1457 if (_rcon_authorized_key_handler.IsAllowed(this->peer_public_key)) {
1458 /* We are allowed, nothing more to validate. */
1459 } else if (_settings_client.network.rcon_password.empty()) {
1461 } else if (_settings_client.network.rcon_password.compare(password) != 0) {
1462 Debug(net, 1, "[rcon] Wrong password from client-id {}", this->client_id);
1464 }
1465
1466 Debug(net, 3, "[rcon] Client-id {} executed: {}", this->client_id, command);
1467
1469 IConsoleCmdExec(command);
1472}
1473
1475{
1476 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1477
1478 CompanyID company_id = (Owner)p.Recv_uint8();
1479
1480 Debug(net, 9, "client[{}] Receive_CLIENT_MOVE(): company_id={}", this->client_id, company_id);
1481
1482 /* Check if the company is valid, we don't allow moving to AI companies */
1483 if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
1484
1485 if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key)) {
1486 Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1);
1488 }
1489
1490 /* if we get here we can move the client */
1491 NetworkServerDoMove(this->client_id, company_id);
1493}
1494
1500{
1501 memset(stats, 0, sizeof(*stats) * MAX_COMPANIES);
1502
1503 /* Go through all vehicles and count the type of vehicles */
1504 for (const Vehicle *v : Vehicle::Iterate()) {
1505 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
1506 uint8_t type = 0;
1507 switch (v->type) {
1508 case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
1509 case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
1510 case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break;
1511 case VEH_SHIP: type = NETWORK_VEH_SHIP; break;
1512 default: continue;
1513 }
1514 stats[v->owner].num_vehicle[type]++;
1515 }
1516
1517 /* Go through all stations and count the types of stations */
1518 for (const Station *s : Station::Iterate()) {
1519 if (Company::IsValidID(s->owner)) {
1520 NetworkCompanyStats *npi = &stats[s->owner];
1521
1522 if (s->facilities & FACIL_TRAIN) npi->num_station[NETWORK_VEH_TRAIN]++;
1523 if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[NETWORK_VEH_LORRY]++;
1524 if (s->facilities & FACIL_BUS_STOP) npi->num_station[NETWORK_VEH_BUS]++;
1525 if (s->facilities & FACIL_AIRPORT) npi->num_station[NETWORK_VEH_PLANE]++;
1526 if (s->facilities & FACIL_DOCK) npi->num_station[NETWORK_VEH_SHIP]++;
1527 }
1528 }
1529}
1530
1536{
1538
1539 if (ci == nullptr) return;
1540
1541 Debug(desync, 1, "client: {:08x}; {:02x}; {:02x}; {:04x}", TimerGameEconomy::date, TimerGameEconomy::date_fract, (int)ci->client_playas, client_id);
1542
1543 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1545 cs->SendClientInfo(ci);
1546 }
1547 }
1548
1550}
1551
1558{
1559 CompanyMask has_clients = 0;
1560 CompanyMask has_vehicles = 0;
1561
1563
1564 /* Detect the active companies */
1565 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1566 if (Company::IsValidID(ci->client_playas)) SetBit(has_clients, ci->client_playas);
1567 }
1568
1569 if (!_network_dedicated) {
1571 assert(ci != nullptr);
1572 if (Company::IsValidID(ci->client_playas)) SetBit(has_clients, ci->client_playas);
1573 }
1574
1576 for (const Company *c : Company::Iterate()) {
1577 if (std::any_of(std::begin(c->group_all), std::end(c->group_all), [](const GroupStatistics &gs) { return gs.num_vehicle != 0; })) SetBit(has_vehicles, c->index);
1578 }
1579 }
1580
1581 /* Go through all the companies */
1582 for (Company *c : Company::Iterate()) {
1583 /* Skip the non-active once */
1584 if (c->is_ai) continue;
1585
1586 if (!HasBit(has_clients, c->index)) {
1587 /* The company is empty for one month more */
1588 if (c->months_empty != std::numeric_limits<decltype(c->months_empty)>::max()) c->months_empty++;
1589
1590 /* Is the company empty for autoclean_protected-months? */
1592 /* Shut the company down */
1594 IConsolePrint(CC_INFO, "Auto-cleaned company #{}.", c->index + 1);
1595 }
1596 /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
1597 if (_settings_client.network.autoclean_novehicles != 0 && c->months_empty > _settings_client.network.autoclean_novehicles && !HasBit(has_vehicles, c->index)) {
1598 /* Shut the company down */
1600 IConsolePrint(CC_INFO, "Auto-cleaned company #{} with no vehicles.", c->index + 1);
1601 }
1602 } else {
1603 /* It is not empty, reset the date */
1604 c->months_empty = 0;
1605 }
1606 }
1607}
1608
1614bool NetworkMakeClientNameUnique(std::string &name)
1615{
1616 bool is_name_unique = false;
1617 std::string original_name = name;
1618
1619 for (uint number = 1; !is_name_unique && number <= MAX_CLIENTS; number++) { // Something's really wrong when there're more names than clients
1620 is_name_unique = true;
1621 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
1622 if (ci->client_name == name) {
1623 /* Name already in use */
1624 is_name_unique = false;
1625 break;
1626 }
1627 }
1628 /* Check if it is the same as the server-name */
1630 if (ci != nullptr) {
1631 if (ci->client_name == name) is_name_unique = false; // name already in use
1632 }
1633
1634 if (!is_name_unique) {
1635 /* Try a new name (<name> #1, <name> #2, and so on) */
1636 name = original_name + " #" + std::to_string(number);
1637
1638 /* The constructed client name is larger than the limit,
1639 * so... bail out as no valid name can be created. */
1640 if (name.size() >= NETWORK_CLIENT_NAME_LENGTH) return false;
1641 }
1642 }
1643
1644 return is_name_unique;
1645}
1646
1653bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
1654{
1655 /* Check if the name's already in use */
1657 if (ci->client_name.compare(new_name) == 0) return false;
1658 }
1659
1661 if (ci == nullptr) return false;
1662
1663 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name);
1664
1665 ci->client_name = new_name;
1666
1667 NetworkUpdateClientInfo(client_id);
1668 return true;
1669}
1670
1675static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
1676{
1677 for (auto &cp : cs->outgoing_queue) cs->SendCommand(cp);
1678 cs->outgoing_queue.clear();
1679}
1680
1685void NetworkServer_Tick(bool send_frame)
1686{
1687#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1688 bool send_sync = false;
1689#endif
1690
1691#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1694 send_sync = true;
1695 }
1696#endif
1697
1698 /* Now we are done with the frame, inform the clients that they can
1699 * do their frame! */
1700 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1701 /* We allow a number of bytes per frame, but only to the burst amount
1702 * to be available for packet receiving at any particular time. */
1703 cs->receive_limit = std::min<size_t>(cs->receive_limit + _settings_client.network.bytes_per_frame,
1705
1706 /* Check if the speed of the client is what we can expect from a client */
1707 uint lag = NetworkCalculateLag(cs);
1708 switch (cs->status) {
1709 case NetworkClientSocket::STATUS_ACTIVE:
1711 /* Client did still not report in within the specified limit. */
1712
1713 if (cs->last_packet + std::chrono::milliseconds(lag * MILLISECONDS_PER_TICK) > std::chrono::steady_clock::now()) {
1714 /* A packet was received in the last three game days, so the client is likely lagging behind. */
1715 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client's game state is more than {} ticks behind.", cs->client_id, cs->GetClientIP(), lag);
1716 } else {
1717 /* No packet was received in the last three game days; sounds like a lost connection. */
1718 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because the client did not respond for more than {} ticks.", cs->client_id, cs->GetClientIP(), lag);
1719 }
1720 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1721 continue;
1722 }
1723
1724 /* Report once per time we detect the lag, and only when we
1725 * received a packet in the last 2 seconds. If we
1726 * did not receive a packet, then the client is not just
1727 * slow, but the connection is likely severed. Mentioning
1728 * frame_freq is not useful in this case. */
1729 if (lag > (uint)Ticks::DAY_TICKS && cs->lag_test == 0 && cs->last_packet + std::chrono::seconds(2) > std::chrono::steady_clock::now()) {
1730 IConsolePrint(CC_WARNING, "[{}] Client #{} is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
1731 cs->lag_test = 1;
1732 }
1733
1734 if (cs->last_frame_server - cs->last_token_frame >= _settings_client.network.max_lag_time) {
1735 /* This is a bad client! It didn't send the right token back within time. */
1736 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it fails to send valid acks.", cs->client_id, cs->GetClientIP());
1737 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1738 continue;
1739 }
1740 break;
1741
1742 case NetworkClientSocket::STATUS_INACTIVE:
1743 case NetworkClientSocket::STATUS_IDENTIFY:
1744 case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
1745 case NetworkClientSocket::STATUS_AUTHORIZED:
1746 /* NewGRF check and authorized states should be handled almost instantly.
1747 * So give them some lee-way, likewise for the query with inactive. */
1749 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to start the joining process.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_init_time);
1750 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1751 continue;
1752 }
1753 break;
1754
1755 case NetworkClientSocket::STATUS_MAP_WAIT:
1756 /* Send every two seconds a packet to the client, to make sure
1757 * it knows the server is still there; just someone else is
1758 * still receiving the map. */
1759 if (std::chrono::steady_clock::now() > cs->last_packet + std::chrono::seconds(2)) {
1760 cs->SendWait();
1761 /* We need to reset the timer, as otherwise we will be
1762 * spamming the client. Strictly speaking this variable
1763 * tracks when we last received a packet from the client,
1764 * but as it is waiting, it will not send us any till we
1765 * start sending them data. */
1766 cs->last_packet = std::chrono::steady_clock::now();
1767 }
1768 break;
1769
1770 case NetworkClientSocket::STATUS_MAP:
1771 /* Downloading the map... this is the amount of time since starting the saving. */
1773 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to download the map.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_download_time);
1774 cs->SendError(NETWORK_ERROR_TIMEOUT_MAP);
1775 continue;
1776 }
1777 break;
1778
1779 case NetworkClientSocket::STATUS_DONE_MAP:
1780 case NetworkClientSocket::STATUS_PRE_ACTIVE:
1781 /* The map has been sent, so this is for loading the map and syncing up. */
1783 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to join.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_join_time);
1784 cs->SendError(NETWORK_ERROR_TIMEOUT_JOIN);
1785 continue;
1786 }
1787 break;
1788
1789 case NetworkClientSocket::STATUS_AUTH_GAME:
1790 /* These don't block? */
1792 IConsolePrint(CC_WARNING, "Client #{} (IP: {}) is dropped because it took longer than {} ticks to enter the password.", cs->client_id, cs->GetClientIP(), _settings_client.network.max_password_time);
1793 cs->SendError(NETWORK_ERROR_TIMEOUT_PASSWORD);
1794 continue;
1795 }
1796 break;
1797
1798 case NetworkClientSocket::STATUS_END:
1799 /* Bad server/code. */
1800 NOT_REACHED();
1801 }
1802
1803 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
1804 /* Check if we can send command, and if we have anything in the queue */
1806
1807 /* Send an updated _frame_counter_max to the client */
1808 if (send_frame) cs->SendFrame();
1809
1810#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1811 /* Send a sync-check packet */
1812 if (send_sync) cs->SendSync();
1813#endif
1814 }
1815 }
1816}
1817
1820{
1823 case FT_SAVEGAME:
1824 case FT_SCENARIO:
1826 break;
1827
1828 case FT_HEIGHTMAP:
1830 break;
1831
1832 default:
1834 }
1835}
1836
1839{
1840 if (!_network_server) return;
1841
1842 /* If setting is 0, this feature is disabled. */
1843 if (_settings_client.network.restart_hours == 0) return;
1844
1845 Debug(net, 3, "Auto-restarting map: {} hours played", _settings_client.network.restart_hours);
1847});
1848
1854{
1855 if (!_network_server) return;
1856
1858}
1859
1862{
1863 /* If setting is 0, this feature is disabled. */
1865
1867 Debug(net, 3, "Auto-restarting map: year {} reached", TimerGameCalendar::year);
1869 }
1870}
1871
1873static IntervalTimer<TimerGameCalendar> _calendar_network_yearly({ TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE }, [](auto) {
1874 if (!_network_server) return;
1875
1877});
1878
1880static IntervalTimer<TimerGameEconomy> _economy_network_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::NONE}, [](auto)
1881{
1882 if (!_network_server) return;
1883
1885});
1886
1888static IntervalTimer<TimerGameEconomy> _network_quarterly({TimerGameEconomy::QUARTER, TimerGameEconomy::Priority::NONE}, [](auto)
1889{
1890 if (!_network_server) return;
1891
1894});
1895
1897static IntervalTimer<TimerGameEconomy> _network_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::NONE}, [](auto)
1898{
1899 if (!_network_server) return;
1900
1903});
1904
1906static IntervalTimer<TimerGameEconomy> _network_weekly({TimerGameEconomy::WEEK, TimerGameEconomy::Priority::NONE}, [](auto)
1907{
1908 if (!_network_server) return;
1909
1911});
1912
1914static IntervalTimer<TimerGameEconomy> _economy_network_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::NONE}, [](auto)
1915{
1916 if (!_network_server) return;
1917
1919});
1920
1926{
1927 return this->client_address.GetHostname();
1928}
1929
1932{
1933 static const char * const stat_str[] = {
1934 "inactive",
1935 "authorizing",
1936 "identifing client",
1937 "checking NewGRFs",
1938 "authorized",
1939 "waiting",
1940 "loading map",
1941 "map done",
1942 "ready",
1943 "active"
1944 };
1945 static_assert(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
1946
1947 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1948 NetworkClientInfo *ci = cs->GetInfo();
1949 if (ci == nullptr) continue;
1950 uint lag = NetworkCalculateLag(cs);
1951 const char *status;
1952
1953 status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
1954 IConsolePrint(CC_INFO, "Client #{} name: '{}' status: '{}' frame-lag: {} company: {} IP: {}",
1955 cs->client_id, ci->client_name, status, lag,
1956 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
1957 cs->GetClientIP());
1958 }
1959}
1960
1965{
1966 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
1967 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate();
1968 }
1969}
1970
1973{
1974 if (_network_server) FillStaticNetworkServerGameInfo();
1975}
1976
1983void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
1984{
1985 /* Only allow non-dedicated servers and normal clients to be moved */
1986 if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
1987
1989 assert(ci != nullptr);
1990
1991 /* No need to waste network resources if the client is in the company already! */
1992 if (ci->client_playas == company_id) return;
1993
1994 ci->client_playas = company_id;
1995
1996 if (client_id == CLIENT_ID_SERVER) {
1997 SetLocalCompany(company_id);
1998 } else {
1999 NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id);
2000 /* When the company isn't authorized we can't move them yet. */
2001 if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
2002 cs->SendMove(client_id, company_id);
2003 }
2004
2005 /* announce the client's move */
2006 NetworkUpdateClientInfo(client_id);
2007
2008 NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN;
2009 NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
2010
2012}
2013
2020void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const std::string &string)
2021{
2022 NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string);
2023}
2024
2030void NetworkServerKickClient(ClientID client_id, const std::string &reason)
2031{
2032 if (client_id == CLIENT_ID_SERVER) return;
2033 NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED, reason);
2034}
2035
2042uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason)
2043{
2044 return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban, reason);
2045}
2046
2053uint NetworkServerKickOrBanIP(const std::string &ip, bool ban, const std::string &reason)
2054{
2055 /* Add address to ban-list */
2056 if (ban) {
2057 bool contains = false;
2058 for (const auto &iter : _network_ban_list) {
2059 if (iter == ip) {
2060 contains = true;
2061 break;
2062 }
2063 }
2064 if (!contains) _network_ban_list.emplace_back(ip);
2065 }
2066
2067 uint n = 0;
2068
2069 /* There can be multiple clients with the same IP, kick them all but don't kill the server,
2070 * or the client doing the rcon. The latter can't be kicked because kicking frees closes
2071 * and subsequently free the connection related instances, which we would be reading from
2072 * and writing to after returning. So we would read or write data from freed memory up till
2073 * the segfault triggers. */
2074 for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
2075 if (cs->client_id == CLIENT_ID_SERVER) continue;
2076 if (cs->client_id == _redirect_console_to_client) continue;
2077 if (cs->client_address.IsInNetmask(ip)) {
2078 NetworkServerKickClient(cs->client_id, reason);
2079 n++;
2080 }
2081 }
2082
2083 return n;
2084}
2085
2092{
2093 for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
2094 if (ci->client_playas == company) return true;
2095 }
2096 return false;
2097}
2098
2099
2106{
2107 const NetworkClientInfo *ci = this->GetInfo();
2108 if (ci != nullptr && !ci->client_name.empty()) return ci->client_name;
2109
2110 return fmt::format("Client #{}", this->client_id);
2111}
2112
2117{
2119 if (_network_server) {
2120 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {} IP: {}",
2121 ci->client_id,
2122 ci->client_name,
2123 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
2124 ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP());
2125 } else {
2126 IConsolePrint(CC_INFO, "Client #{} name: '{}' company: {}",
2127 ci->client_id,
2128 ci->client_name,
2129 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0));
2130 }
2131 }
2132}
2133
2139std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
2140{
2141 auto socket = NetworkClientSocket::GetByClientID(client_id);
2142 return socket == nullptr ? "" : socket->GetPeerPublicKey();
2143}
2144
2145
2152{
2153 assert(c != nullptr);
2154
2155 if (!_network_server) return;
2156
2157 if (ci != nullptr) {
2158 /* ci is nullptr when replaying, or for AIs. In neither case there is a client. */
2159 ci->client_playas = c->index;
2161
2162 /*
2163 * This function is called from a command, but is only called for the server.
2164 * The client information is managed out-of-band from the commands, so to not have a
2165 * different state/president/company name in the different clients, we need to
2166 * circumvent the normal ::Post logic and go directly to sending the command.
2167 */
2170
2171 NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
2172 }
2173}
std::map< SOCKET, NetworkAddress > SocketList
Type for a mapping between address and socket.
Definition address.h:21
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
void SetInterval(const TPeriod interval, bool reset=true)
Set a new interval for the timer.
Definition timer.h:99
const std::string & GetHostname()
Get the hostname; in case it wasn't given the IPv4 dotted representation is given.
Definition address.cpp:23
Default implementation for the authorized key handler.
bool IsAllowed(std::string_view peer_public_key) const override
Check whether the given public key of the peer is allowed in.
Default implementation of the password provider.
static std::unique_ptr< NetworkAuthenticationServerHandler > Create(const NetworkAuthenticationPasswordProvider *password_provider, const NetworkAuthenticationAuthorizedKeyHandler *authorized_key_handler, NetworkAuthenticationMethodMask client_supported_method_mask=~static_cast< NetworkAuthenticationMethodMask >(0))
Create a NetworkAuthenticationServerHandler.
@ RETRY_NEXT_METHOD
The client failed to authenticate, but there is another method to try.
@ AUTHENTICATED
The client was authenticated successfully.
@ NOT_AUTHENTICATED
All authentications for this handler have been exhausted.
Base socket handler for all TCP sockets.
Definition tcp_game.h:141
uint32_t last_frame
Last frame we have executed.
Definition tcp_game.h:487
NetworkClientInfo * GetInfo() const
Gets the client info of this socket handler.
Definition tcp_game.h:515
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
const char * ReceiveCommand(Packet &p, CommandPacket &cp)
Receives a command from the network.
uint32_t last_frame_server
Last frame the server has executed.
Definition tcp_game.h:488
NetworkClientInfo * info
Client info related to this socket.
Definition tcp_game.h:144
void SendCommand(Packet &p, const CommandPacket &cp)
Sends a command over the network.
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
virtual std::unique_ptr< Packet > ReceivePacket()
Receives a packet for the given client.
Definition tcp.cpp:129
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
Class for handling the server side of the game connection.
NetworkRecvStatus SendRConResult(uint16_t colour, const std::string &command)
Send the result of a console action.
NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet &p) override
Gives the client a new name: string New name of the client.
size_t receive_limit
Amount of bytes that we can receive at this moment.
std::shared_ptr< struct PacketWriter > savegame
Writer used to write the savegame.
static void Send()
Send the packets for the server sockets.
NetworkRecvStatus Receive_CLIENT_MOVE(Packet &p) override
Request the server to move this client into another company: uint8_t ID of the company the client wan...
NetworkRecvStatus SendQuit(ClientID client_id)
Tell the client another client quit.
NetworkRecvStatus Receive_CLIENT_ACK(Packet &p) override
Tell the server we are done with this frame: uint32_t Current frame counter of the client.
NetworkRecvStatus Receive_CLIENT_AUTH_RESPONSE(Packet &p) override
Send the response to the authentication request: 32 * uint8_t Public key of the client.
std::unique_ptr< Packet > ReceivePacket() override
Receives a packet for the given client.
NetworkRecvStatus Receive_CLIENT_COMMAND(Packet &p) override
The client has done a command and wants us to handle it.
NetworkRecvStatus Receive_CLIENT_QUIT(Packet &p) override
The client is quitting the game.
static const char * GetName()
Get the name used by the listener.
const std::string & GetClientIP()
Get the IP address/hostname of the connected client.
NetworkRecvStatus SendWelcome()
Send the client a welcome message with some basic information.
NetworkRecvStatus SendAuthRequest()
Request the game password.
~ServerNetworkGameSocketHandler()
Clear everything related to this client.
std::string GetClientName() const
Get the name of the client, if the user did not send it yet, Client ID is used.
uint8_t last_token
The last random token we did send to verify the client is listening.
NetworkRecvStatus SendFrame()
Tell the client that they may run to a particular frame.
NetworkRecvStatus Receive_CLIENT_ERROR(Packet &p) override
The client made an error and is quitting the game.
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const std::string &msg, int64_t data)
Send a chat message.
NetworkRecvStatus SendGameInfo()
Send the client information about the server.
NetworkRecvStatus SendJoin(ClientID client_id)
Tell that a client joined.
std::string peer_public_key
The public key of our client.
NetworkRecvStatus Receive_CLIENT_CHAT(Packet &p) override
Sends a chat-packet to the server: uint8_t ID of the action (see NetworkAction).
NetworkRecvStatus SendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
Send a chat message from external source.
NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci)
Send the client information about a client.
static bool AllowConnection()
Whether an connection is allowed or not at this moment.
NetworkRecvStatus SendEnableEncryption()
Notify the client that the authentication has completed and tell that for the remainder of this socke...
NetworkRecvStatus SendError(NetworkErrorCode error, const std::string &reason={})
Send an error to the client, and close its connection.
NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p) override
Try to join the server: string OpenTTD revision (norev0000 if no revision).
NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet &p) override
Request game information.
@ STATUS_PRE_ACTIVE
The client is catching up the delayed frames.
@ STATUS_IDENTIFY
The client is identifying itself.
@ STATUS_AUTH_GAME
The client is authorizing with game (server) password.
@ STATUS_NEWGRFS_CHECK
The client is checking NewGRFs.
@ STATUS_AUTHORIZED
The client is authorized.
@ STATUS_INACTIVE
The client is not connected nor active.
@ STATUS_MAP
The client is downloading the map.
@ STATUS_DONE_MAP
The client has downloaded the map.
@ STATUS_ACTIVE
The client is active within in the game.
@ STATUS_MAP_WAIT
The client is waiting as someone else is downloading the map.
NetworkRecvStatus SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
Tell the client another client quit with an error.
NetworkAddress client_address
IP-address of the client (so they can be banned)
NetworkRecvStatus SendNewGame()
Tell the client we're starting a new game.
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet &p) override
Request the map from the server.
NetworkRecvStatus SendSync()
Request the client to sync.
std::unique_ptr< class NetworkAuthenticationServerHandler > authentication_handler
The handler for the authentication.
NetworkRecvStatus SendMove(ClientID client_id, CompanyID company_id)
Tell that a client moved to another company.
NetworkRecvStatus Receive_CLIENT_RCON(Packet &p) override
Send an RCon command to the server: string RCon password.
ServerNetworkGameSocketHandler(SOCKET s)
Create a new socket for the server side of the game connection.
NetworkRecvStatus Receive_CLIENT_IDENTIFY(Packet &p) override
The client tells the server about the identity of the client: string Name of the client (max NETWORK_...
NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override
Close the network connection due to the given status.
NetworkRecvStatus SendMap()
This sends the map to the client.
NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet &p) override
Tell the server that we have the required GRFs.
uint32_t last_token_frame
The last frame we received the right token.
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet &p) override
Tell the server that we are done receiving/loading the map.
NetworkRecvStatus SendShutdown()
Tell the client we're shutting down.
ClientStatus status
Status of this client.
NetworkRecvStatus SendNewGRFCheck()
Send the check for the NewGRFs.
NetworkRecvStatus SendConfigUpdate()
Send an update about the max company/spectator counts.
NetworkRecvStatus SendWait()
Tell the client that its put in a waiting queue.
NetworkRecvStatus SendCommand(const CommandPacket &cp)
Send a command to the client to execute.
Template for TCP listeners.
Definition tcp_listen.h:28
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Year year
Current year, starting at 0.
static Date date
Current date in days (day counter).
static DateFract date_fract
Fractional part of the day.
@ UNPAUSED
Only run when not paused.
CommandFlags GetCommandFlags(Commands cmd)
This function mask the parameter with CMD_ID_MASK and returns the flags which belongs to the given co...
Definition command.cpp:118
@ CMD_COMPANY_CTRL
used in multiplayer to create a new companies etc.
@ CMD_COMPANY_ALLOW_LIST_CTRL
Used in multiplayer to add/remove a client's public key to/from the company's allow list.
@ CMD_SPECTATOR
the command may be initiated by a spectator
@ CMD_SERVER
the command can only be initiated by the server
@ CMD_CLIENT_ID
set p2 with the ClientID of the sending client.
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.
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...
CompanyCtrlAction
The action to do with CMD_COMPANY_CTRL.
@ CCA_DELETE
Delete a company.
@ CCA_NEW
Create a new company.
@ CALCA_ADD
Create a public key.
Owner
Enum for all companies/owners.
@ COMPANY_SPECTATOR
The client is spectating.
@ COMPANY_NEW_COMPANY
The client wants a new company.
@ MAX_COMPANIES
Maximum number of companies.
@ CRR_AUTOCLEAN
The company is removed due to autoclean.
static const size_t TCP_MTU
Number of bytes we can pack in a single TCP packet.
Definition config.h:45
static const uint NETWORK_CLIENT_NAME_LENGTH
The maximum length of a client's name, in bytes including '\0'.
Definition config.h:58
static const uint NETWORK_CHAT_LENGTH
The maximum length of a chat message, in bytes including '\0'.
Definition config.h:61
static const uint NETWORK_REVISION_LENGTH
The maximum length of the revision, in bytes including '\0'.
Definition config.h:56
static const uint NETWORK_RCONCOMMAND_LENGTH
The maximum length of a rconsole command, in bytes including '\0'.
Definition config.h:59
static const uint NETWORK_PASSWORD_LENGTH
The maximum length of the password, in bytes including '\0'.
Definition config.h:57
void IConsoleCmdExec(const std::string &command_string, const uint recurse_count)
Execute a given command passed to us.
Definition console.cpp:291
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
static const TextColour CC_INFO
Colour for information lines.
static const TextColour CC_WARNING
Colour for warning lines.
static const TextColour CC_DEFAULT
Default colour of the console.
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
Definition core.h:23
@ 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_OKAY
Everything is okay.
Definition core.h:24
@ NETWORK_RECV_STATUS_MALFORMED_PACKET
We apparently send a malformed packet.
Definition core.h:29
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
#define DECLARE_POSTFIX_INCREMENT(enum_type)
Some enums need to have allowed incrementing (i.e.
Definition enum_type.hpp:18
@ FT_SCENARIO
old or new scenario
Definition fileio_type.h:19
@ FT_HEIGHTMAP
heightmap file
Definition fileio_type.h:20
@ FT_SAVEGAME
old or new savegame
Definition fileio_type.h:18
static const uint32_t GENERATE_NEW_SEED
Create a new random seed.
Definition genworld.h:24
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
uint32_t _last_sync_frame
Used in the server to store the last time a sync packet was sent to clients.
Definition network.cpp:79
StringID GetNetworkErrorMsg(NetworkErrorCode err)
Retrieve the string id of an internal error number.
Definition network.cpp:313
ClientID _redirect_console_to_client
If not invalid, redirect the console output to a client.
Definition network.cpp:71
uint32_t _frame_counter
The current frame.
Definition network.cpp:78
StringList _network_ban_list
The banned clients.
Definition network.cpp:75
bool _network_dedicated
are we a dedicated server?
Definition network.cpp:68
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
uint8_t _network_clients_connected
The amount of clients connected.
Definition network.cpp:89
uint32_t _frame_counter_max
To where we may go with our clients.
Definition network.cpp:77
void NetworkAdminClientUpdate(const NetworkClientInfo *ci)
Notify the admin network of a client update (if they did opt in for the respective update).
void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const std::string &msg, int64_t data, bool from_admin)
Send chat to the admin network (if they did opt in for the respective update).
void NetworkAdminClientQuit(ClientID client_id)
Notify the admin network that a client quit (if they have opt in for the respective update).
void NetworkAdminUpdate(AdminUpdateFrequency freq)
Send (push) updates to the admin network as they have registered for these updates.
void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client)
Notify the admin network of a new client (if they did opt in for the respective update).
void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code)
Notify the admin network of a client error (if they have opt in for the respective update).
Server part of the admin network protocol.
Base core network types and some helper functions to access them.
bool NetworkIsValidClientName(const std::string_view client_name)
Check whether the given client name is deemed valid for use in network games.
void NetworkSyncCommandQueue(NetworkClientSocket *cs)
Sync our local command queue to the command queue of the given socket.
void NetworkReplaceCommandClientId(CommandPacket &cp, ClientID client_id)
Insert a client ID into the command data in a command packet.
NetworkAuthenticationMethod
The authentication method that can be used.
@ NETWORK_AUTH_METHOD_X25519_PAKE
Authentication using x25519 password-authenticated key agreement.
@ NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY
Authentication using x22519 key exchange and authorized keys.
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const std::string &msg, ClientID from_id, int64_t data=0, bool from_admin=false)
Send an actual chat message.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
bool NetworkMakeClientNameUnique(std::string &new_name)
Check whether a name is unique, and otherwise try to make it unique.
static IntervalTimer< TimerGameEconomy > _network_quarterly({TimerGameEconomy::QUARTER, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY);})
Quarterly "callback".
static IntervalTimer< TimerGameEconomy > _economy_network_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY);})
Daily "callback".
bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_name)
Change the client name of the given client.
void NetworkPrintClients()
Print all the clients to the console.
void NetworkServerUpdateGameInfo()
Update the server's NetworkServerGameInfo due to changes in settings.
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const std::string &string)
Send an rcon reply to the client.
void NetworkUpdateClientInfo(ClientID client_id)
Send updated client info of a particular client.
static NetworkAuthenticationDefaultAuthorizedKeyHandler _rcon_authorized_key_handler(_settings_client.network.rcon_authorized_keys)
Provides the authorized key validation for rcon.
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const std::string &reason)
Ban, or kick, everyone joined from the given client's IP.
static IntervalTimer< TimerGameEconomy > _economy_network_yearly({TimerGameEconomy::YEAR, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(ADMIN_FREQUENCY_ANUALLY);})
Economy yearly "callback".
static NetworkAuthenticationDefaultPasswordProvider _password_provider(_settings_client.network.server_password)
Provides the password validation for the game's password.
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats)
Populate the company stats.
void NetworkServerSendConfigUpdate()
Send Config Update.
void NetworkServerKickClient(ClientID client_id, const std::string &reason)
Kick a single client.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
static IntervalTimer< TimerGameEconomy > _network_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAutoCleanCompanies();NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY);})
Economy monthly "callback".
void ChangeNetworkRestartTime(bool reset)
Reset the automatic network restart time interval.
bool NetworkCompanyHasClients(CompanyID company)
Check whether a particular company has clients.
static void NetworkRestartMap()
Helper function to restart the map.
static void NetworkCheckRestartMapYear()
Check if we want to restart the map based on the year.
static IntervalTimer< TimerGameCalendar > _calendar_network_yearly({ TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE }, [](auto) { if(!_network_server) return;NetworkCheckRestartMapYear();})
Calendar yearly "callback".
bool NetworkMakeClientNameUnique(std::string &name)
Check whether a name is unique, and otherwise try to make it unique.
static ClientID _network_client_id
The identifier counter for new clients (is never decreased)
std::string_view NetworkGetPublicKeyOfClient(ClientID client_id)
Get the public key of the client with the given id.
static NetworkAuthenticationDefaultAuthorizedKeyHandler _authorized_key_handler(_settings_client.network.server_authorized_keys)
Provides the authorized key handling for the game authentication.
static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
Handle the command-queue of a socket.
static IntervalTimer< TimerGameEconomy > _network_weekly({TimerGameEconomy::WEEK, TimerGameEconomy::Priority::NONE}, [](auto) { if(!_network_server) return;NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);})
Economy weekly "callback".
void NetworkServerShowStatusToConsole()
Show the status message of all clients on the console.
void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
Perform all the server specific administration of a new company.
void NetworkServerSendExternalChat(const std::string &source, TextColour colour, const std::string &user, const std::string &msg)
Send a chat message from external source.
void NetworkServer_Tick(bool send_frame)
This is called every tick if this is a _network_server.
NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket")
Make very sure the preconditions given in network_type.h are actually followed.
static IntervalTimer< TimerGameRealtime > _network_restart_map_timer({std::chrono::hours::zero(), TimerGameRealtime::UNPAUSED}, [](auto) { if(!_network_server) return;if(_settings_client.network.restart_hours==0) return;Debug(net, 3, "Auto-restarting map: {} hours played", _settings_client.network.restart_hours);NetworkRestartMap();})
Timer to restart a network server automatically based on real-time hours played.
static void NetworkAutoCleanCompanies()
Remove companies that have not been used depending on the autoclean_companies setting and values for ...
void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const std::string &msg, ClientID from_id, int64_t data, bool from_admin)
Send an actual chat message.
Server part of the network protocol.
DestType
Destination of our chat messages.
@ DESTTYPE_CLIENT
Send message/notice to only a certain client (Private)
@ DESTTYPE_TEAM
Send message/notice to everyone playing the same company (Team)
@ DESTTYPE_BROADCAST
Send message/notice to all clients (All)
static const uint MAX_CLIENT_SLOTS
The number of slots; must be at least 1 more than MAX_CLIENTS.
static const uint MAX_CLIENTS
How many clients can we have.
NetworkAction
Actions that can be used for NetworkTextMessage.
ClientID
'Unique' identifier to be given to clients
@ INVALID_CLIENT_ID
Client is not part of anything.
@ CLIENT_ID_SERVER
Servers always have this ID.
@ CLIENT_ID_FIRST
The first client ID.
NetworkErrorCode
The error codes we send around in the protocols.
Sending and receiving UDP messages.
GRFConfig * _grfconfig
First item in list of current GRF set up.
@ GCF_STATIC
GRF file is used statically (can be used in any MP game)
@ SM_START_HEIGHTMAP
Load a heightmap and start a new game from it.
Definition openttd.h:38
@ SM_LOAD_GAME
Load game, Play Scenario.
Definition openttd.h:32
@ SM_NEWGAME
New Game --> 'Random game'.
Definition openttd.h:28
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
void SlError(StringID string, const std::string &extra_msg)
Error handler.
Definition saveload.cpp:321
SaveOrLoadResult SaveWithFilter(std::shared_ptr< SaveFilter > writer, bool threaded)
Save the game using a (writer) filter.
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
Definition saveload.cpp:60
@ SL_OK
completed successfully
Definition saveload.h:404
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:58
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
@ FACIL_DOCK
Station with a dock.
@ FACIL_BUS_STOP
Station with bus stops.
@ FACIL_AIRPORT
Station with an airport.
@ FACIL_TRUCK_STOP
Station with truck stops.
@ FACIL_TRAIN
Station with train station.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:280
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:333
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
NetworkSettings network
settings related to the network
Everything we need to know about a command to be able to execute it.
CommandDataBuffer data
command parameters.
uint32_t frame
the frame in which this packet is executed
CompanyID company
company that is executing the command
bool my_cmd
did the command originate from "me"
Commands cmd
command being executed.
Defines the traits of a command.
uint8_t months_empty
NOSAVE: Number of months this company has not had a client in multiplayer.
static bool IsValidHumanID(size_t index)
Is this company a valid company, not controlled by a NoAI program?
AbstractFileType abstract_ftype
Abstract type of file (scenario, heightmap, etc).
Definition saveload.h:413
Information about GRF, used in the game and (part of it) in savegames.
uint8_t flags
NOSAVE: GCF_Flags, bitset.
struct GRFConfig * next
NOSAVE: Next item in the linked list.
GRFIdentifier ident
grfid and md5sum to uniquely identify newgrfs
uint32_t generation_seed
noise seed for world generation
GameCreationSettings game_creation
settings used during the creation of a game (map)
Statistics and caches on the vehicles in a group.
Definition group.h:24
Container for all information known about a client.
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:116
TimerGameEconomy::Date join_date
Gamedate the client has joined.
CompanyID client_playas
As which company is this client playing (CompanyID)
ClientID client_id
Client identifier (same as ClientState->client_id)
std::string client_name
Name of the client.
std::string public_key
The public key of the client.
Simple calculated statistics of a company.
uint16_t num_vehicle[NETWORK_VEH_END]
How many vehicles are there of this type?
uint16_t num_station[NETWORK_VEH_END]
How many stations are there of this type?
uint8_t clients_on
Current count of clients on server.
uint8_t max_clients
maximum amount of clients
uint16_t bytes_per_frame_burst
how many bytes may, over a short period, be received?
bool autoclean_companies
automatically remove companies that are not in use
bool server_admin_chat
allow private chat for the server to be distributed to the admin network
TimerGameCalendar::Year restart_game_year
year the server restarts
uint8_t max_companies
maximum amount of companies
uint8_t autoclean_protected
Remove companies after this many months.
uint16_t max_password_time
maximum amount of time, in game ticks, a client may take to enter the password
uint16_t max_join_time
maximum amount of time, in game ticks, a client may take to sync up during joining
uint16_t bytes_per_frame
how many bytes may, over a long period, be received per frame?
uint16_t max_init_time
maximum amount of time, in game ticks, a client may take to initiate joining
uint16_t max_lag_time
maximum amount of time, in game ticks, a client may be lagging behind the server
uint8_t autoclean_novehicles
remove companies with no vehicles after this many months
uint16_t max_commands_in_queue
how many commands may there be in the incoming queue before dropping the connection?
std::string server_name
name of the server
uint16_t restart_hours
number of hours to run the server before automatic restart
uint16_t max_download_time
maximum amount of time, in game ticks, a client may take to download the map
uint16_t sync_freq
how often do we check whether we are still in-sync
std::string rcon_password
password for rconsole (server side)
static void ResetUser(uint32_t user)
Reset an user's OrderBackup if needed.
Writing a savegame directly to a number of packets.
void Write(uint8_t *buf, size_t size) override
Write a given number of bytes into the savegame.
std::unique_ptr< Packet > current
The packet we're currently writing to.
PacketWriter(ServerNetworkGameSocketHandler *cs)
Create the packet writer.
size_t total_size
Total size of the compressed savegame.
std::condition_variable exit_sig
Signal for threaded destruction of this packet writer.
void Finish() override
Prepare everything to finish writing the savegame.
ServerNetworkGameSocketHandler * cs
Socket we are associated with.
std::mutex mutex
Mutex for making threaded saving safe.
void Destroy()
Begin the destruction of this packet writer.
bool TransferToNetworkQueue()
Transfer all packets from here to the network's queue while holding the lock on our mutex.
~PacketWriter()
Make sure everything is cleaned up.
std::deque< std::unique_ptr< Packet > > packets
Packet queue of the savegame; send these "slowly" to the client. Cannot be a std::queue as we want to...
Internal entity of a packet.
Definition packet.h:42
uint64_t Recv_uint64()
Read a 64 bits integer from the packet.
Definition packet.cpp:364
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
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
Tindex index
Index of this pool item.
static size_t GetNumItems()
Returns number of valid items in the pool.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
Base class for all pools.
Definition pool_type.hpp:80
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
Definition pool_type.hpp:84
Interface for filtering a savegame till it is written.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Station data structure.
Vehicle data structure.
@ SPS_CLOSED
The connection got closed.
Definition tcp.h:24
@ ADMIN_FREQUENCY_MONTHLY
The admin gets information about this on a monthly basis.
Definition tcp_admin.h:100
@ ADMIN_FREQUENCY_QUARTERLY
The admin gets information about this on a quarterly basis.
Definition tcp_admin.h:101
@ ADMIN_FREQUENCY_ANUALLY
The admin gets information about this on a yearly basis.
Definition tcp_admin.h:102
@ ADMIN_FREQUENCY_WEEKLY
The admin gets information about this on a weekly basis.
Definition tcp_admin.h:99
@ ADMIN_FREQUENCY_DAILY
The admin gets information about this on a daily basis.
Definition tcp_admin.h:98
@ PACKET_SERVER_JOIN
Tells clients that a new client has joined.
Definition tcp_game.h:87
@ PACKET_SERVER_MAP_SIZE
Server tells the client what the (compressed) size of the map is.
Definition tcp_game.h:82
@ PACKET_SERVER_RCON
Response of the executed command on the server.
Definition tcp_game.h:111
@ PACKET_SERVER_MAP_BEGIN
Server tells the client that it is beginning to send the map.
Definition tcp_game.h:81
@ PACKET_SERVER_SYNC
Server tells the client what the random state should be.
Definition tcp_game.h:98
@ PACKET_SERVER_WAIT
Server tells the client there are some people waiting for the map as well.
Definition tcp_game.h:80
@ PACKET_SERVER_CONFIG_UPDATE
Some network configuration important to the client changed.
Definition tcp_game.h:119
@ PACKET_SERVER_ENABLE_ENCRYPTION
The server tells that authentication has completed and requests to enable encryption with the keys of...
Definition tcp_game.h:65
@ PACKET_SERVER_GAME_INFO
Information about the server.
Definition tcp_game.h:45
@ PACKET_SERVER_ERROR_QUIT
A server tells that a client has hit an error and did quit.
Definition tcp_game.h:125
@ PACKET_SERVER_CLIENT_INFO
Server sends you information about a client.
Definition tcp_game.h:76
@ PACKET_SERVER_WELCOME
Server welcomes you and gives you your ClientID.
Definition tcp_game.h:75
@ PACKET_SERVER_BANNED
The server has banned you.
Definition tcp_game.h:34
@ PACKET_SERVER_FRAME
Server tells the client what frame it is in, and thus to where the client may progress.
Definition tcp_game.h:96
@ PACKET_SERVER_EXTERNAL_CHAT
Server distributing the message from external source.
Definition tcp_game.h:107
@ PACKET_SERVER_CHAT
Server distributing the message of a client (or itself).
Definition tcp_game.h:106
@ PACKET_SERVER_COMMAND
Server distributes a command to (all) the clients.
Definition tcp_game.h:102
@ PACKET_SERVER_SHUTDOWN
The server is shutting down.
Definition tcp_game.h:50
@ PACKET_SERVER_AUTH_REQUEST
The server requests the client to authenticate using a number of methods.
Definition tcp_game.h:63
@ PACKET_SERVER_NEWGAME
The server is preparing to start a new game.
Definition tcp_game.h:49
@ PACKET_SERVER_MOVE
Server tells everyone that someone is moved to another company.
Definition tcp_game.h:115
@ PACKET_SERVER_MAP_DATA
Server sends bits of the map to the client.
Definition tcp_game.h:83
@ PACKET_SERVER_FULL
The server is full and has no place for you.
Definition tcp_game.h:33
@ PACKET_SERVER_QUIT
A server tells that a client has quit.
Definition tcp_game.h:123
@ PACKET_SERVER_ERROR
Server sending an error message to the client.
Definition tcp_game.h:38
@ PACKET_SERVER_CHECK_NEWGRFS
Server sends NewGRF IDs and MD5 checksums for the client to check.
Definition tcp_game.h:71
@ PACKET_SERVER_MAP_DONE
Server tells it has just sent the last bits of the map to the client.
Definition tcp_game.h:84
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
std::mutex lock
synchronization for playback status fields
Definition win32_m.cpp:35
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:3219
@ WC_CLIENT_LIST
Client list; Window numbers: