OpenTTD: src/network/network_server.cpp Source File

OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

network_server.cpp
Go to the documentation of this file.
1 /* $Id: network_server.cpp 27893 2017-08-13 18:38:42Z frosch $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
9
12 #ifdef ENABLE_NETWORK
13
14 #include "../stdafx.h"
15 #include "../strings_func.h"
16 #include "../date_func.h"
17 #include "network_admin.h"
18 #include "network_server.h"
19 #include "network_udp.h"
20 #include "network_base.h"
21 #include "../console_func.h"
22 #include "../company_base.h"
23 #include "../command_func.h"
24 #include "../saveload/saveload.h"
25 #include "../saveload/saveload_filter.h"
26 #include "../station_base.h"
27 #include "../genworld.h"
28 #include "../company_func.h"
29 #include "../company_gui.h"
30 #include "../roadveh.h"
31 #include "../order_backup.h"
32 #include "../core/pool_func.hpp"
33 #include "../core/random_func.hpp"
34 #include "../rev.h"
35
36 #include "../safeguards.h"
37
38
39 /* This file handles all the server-commands */
40
41 DECLARE_POSTFIX_INCREMENT(ClientID)
43 static ClientID _network_client_id = CLIENT_ID_FIRST;
44
46 assert_compile(MAX_CLIENT_SLOTS > MAX_CLIENTS);
48 assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS);
49
51 NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket");
52 INSTANTIATE_POOL_METHODS(NetworkClientSocket)
53
55 template SocketList TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED>::sockets;
56
58 struct PacketWriter : SaveFilter {
59 ServerNetworkGameSocketHandler *cs;
60 Packet *current;
61 size_t total_size;
62 Packet *packets;
63 ThreadMutex *mutex;
64
69 PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0), packets(NULL)
70 {
71 this->mutex = ThreadMutex::New();
72 }
73
75 ~PacketWriter()
76 {
77 if (this->mutex != NULL) this->mutex->BeginCritical();
78
79 if (this->cs != NULL && this->mutex != NULL) {
80 this->mutex->WaitForSignal();
81 }
82
83 /* This must all wait until the Destroy function is called. */
84
85 while (this->packets != NULL) {
86 Packet *p = this->packets->next;
87 delete this->packets;
88 this->packets = p;
89 }
90
91 delete this->current;
92
93 if (this->mutex != NULL) this->mutex->EndCritical();
94
95 delete this->mutex;
96 this->mutex = NULL;
97 }
98
109 void Destroy()
110 {
111 if (this->mutex != NULL) this->mutex->BeginCritical();
112
113 this->cs = NULL;
114
115 if (this->mutex != NULL) this->mutex->SendSignal();
116
117 if (this->mutex != NULL) this->mutex->EndCritical();
118
119 /* Make sure the saving is completely cancelled. Yes,
120 * we need to handle the save finish as well as the
121 * next connection might just be requesting a map. */
122 WaitTillSaved();
123 ProcessAsyncSaveFinish();
124 }
125
133 bool HasPackets()
134 {
135 return this->packets != NULL;
136 }
137
141 Packet *PopPacket()
142 {
143 if (this->mutex != NULL) this->mutex->BeginCritical();
144
145 Packet *p = this->packets;
146 this->packets = p->next;
147 p->next = NULL;
148
149 if (this->mutex != NULL) this->mutex->EndCritical();
150
151 return p;
152 }
153
155 void AppendQueue()
156 {
157 if (this->current == NULL) return;
158
159 Packet **p = &this->packets;
160 while (*p != NULL) {
161 p = &(*p)->next;
162 }
163 *p = this->current;
164
165 this->current = NULL;
166 }
167
168 /* virtual */ void Write(byte *buf, size_t size)
169 {
170 /* We want to abort the saving when the socket is closed. */
171 if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
172
173 if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA);
174
175 if (this->mutex != NULL) this->mutex->BeginCritical();
176
177 byte *bufe = buf + size;
178 while (buf != bufe) {
179 size_t to_write = min(SEND_MTU - this->current->size, bufe - buf);
180 memcpy(this->current->buffer + this->current->size, buf, to_write);
181 this->current->size += (PacketSize)to_write;
182 buf += to_write;
183
184 if (this->current->size == SEND_MTU) {
185 this->AppendQueue();
186 if (buf != bufe) this->current = new Packet(PACKET_SERVER_MAP_DATA);
187 }
188 }
189
190 if (this->mutex != NULL) this->mutex->EndCritical();
191
192 this->total_size += size;
193 }
194
195 /* virtual */ void Finish()
196 {
197 /* We want to abort the saving when the socket is closed. */
198 if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
199
200 if (this->mutex != NULL) this->mutex->BeginCritical();
201
202 /* Make sure the last packet is flushed. */
203 this->AppendQueue();
204
205 /* Add a packet stating that this is the end to the queue. */
206 this->current = new Packet(PACKET_SERVER_MAP_DONE);
207 this->AppendQueue();
208
209 /* Fast-track the size to the client. */
210 Packet *p = new Packet(PACKET_SERVER_MAP_SIZE);
211 p->Send_uint32((uint32)this->total_size);
212 this->cs->NetworkTCPSocketHandler::SendPacket(p);
213
214 if (this->mutex != NULL) this->mutex->EndCritical();
215 }
216 };
217
218
223 ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s)
224 {
225 this->status = STATUS_INACTIVE;
226 this->client_id = _network_client_id++;
227 this->receive_limit = _settings_client.network.bytes_per_frame_burst;
228
229 /* The Socket and Info pools need to be the same in size. After all,
230 * each Socket will be associated with at most one Info object. As
231 * such if the Socket was allocated the Info object can as well. */
232 assert_compile(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE);
233 }
234
238 ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler()
239 {
240 if (_redirect_console_to_client == this->client_id) _redirect_console_to_client = INVALID_CLIENT_ID;
241 OrderBackup::ResetUser(this->client_id);
242
243 if (this->savegame != NULL) {
244 this->savegame->Destroy();
245 this->savegame = NULL;
246 }
247 }
248
249 Packet *ServerNetworkGameSocketHandler::ReceivePacket()
250 {
251 /* Only allow receiving when we have some buffer free; this value
252 * can go negative, but eventually it will become positive again. */
253 if (this->receive_limit <= 0) return NULL;
254
255 /* We can receive a packet, so try that and if needed account for
256 * the amount of received data. */
257 Packet *p = this->NetworkTCPSocketHandler::ReceivePacket();
258 if (p != NULL) this->receive_limit -= p->size;
259 return p;
260 }
261
262 NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
263 {
264 assert(status != NETWORK_RECV_STATUS_OKAY);
265 /*
266 * Sending a message just before leaving the game calls cs->SendPackets.
267 * This might invoke this function, which means that when we close the
268 * connection after cs->SendPackets we will close an already closed
269 * connection. This handles that case gracefully without having to make
270 * that code any more complex or more aware of the validity of the socket.
271 */
272 if (this->sock == INVALID_SOCKET) return status;
273
274 if (status != NETWORK_RECV_STATUS_CONN_LOST && !this->HasClientQuit() && this->status >= STATUS_AUTHORIZED) {
275 /* We did not receive a leave message from this client... */
276 char client_name[NETWORK_CLIENT_NAME_LENGTH];
277 NetworkClientSocket *new_cs;
278
279 this->GetClientName(client_name, lastof(client_name));
280
281 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
282
283 /* Inform other clients of this... strange leaving ;) */
284 FOR_ALL_CLIENT_SOCKETS(new_cs) {
285 if (new_cs->status > STATUS_AUTHORIZED && this != new_cs) {
286 new_cs->SendErrorQuit(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
287 }
288 }
289 }
290
291 NetworkAdminClientError(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
292 DEBUG(net, 1, "Closed client connection %d", this->client_id);
293
294 /* We just lost one client :( */
295 if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
296 extern byte _network_clients_connected;
297 _network_clients_connected--;
298
299 DeleteWindowById(WC_CLIENT_LIST_POPUP, this->client_id);
300 SetWindowDirty(WC_CLIENT_LIST, 0);
301
302 this->SendPackets(true);
303
304 delete this->GetInfo();
305 delete this;
306
307 return status;
308 }
309
314 /* static */ bool ServerNetworkGameSocketHandler::AllowConnection()
315 {
316 extern byte _network_clients_connected;
317 bool accept = _network_clients_connected < MAX_CLIENTS && _network_game_info.clients_on < _settings_client.network.max_clients;
318
319 /* We can't go over the MAX_CLIENTS limit here. However, the
320 * pool must have place for all clients and ourself. */
321 assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1);
322 assert(!accept || ServerNetworkGameSocketHandler::CanAllocateItem());
323 return accept;
324 }
325
327 /* static */ void ServerNetworkGameSocketHandler::Send()
328 {
329 NetworkClientSocket *cs;
330 FOR_ALL_CLIENT_SOCKETS(cs) {
331 if (cs->writable) {
332 if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
333 /* This client is in the middle of a map-send, call the function for that */
334 cs->SendMap();
335 }
336 }
337 }
338 }
339
340 static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
341
342 /***********
343 * Sending functions
344 * DEF_SERVER_SEND_COMMAND has parameter: NetworkClientSocket *cs
345 ************/
346
351 NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientInfo *ci)
352 {
353 if (ci->client_id != INVALID_CLIENT_ID) {
354 Packet *p = new Packet(PACKET_SERVER_CLIENT_INFO);
355 p->Send_uint32(ci->client_id);
356 p->Send_uint8 (ci->client_playas);
357 p->Send_string(ci->client_name);
358
359 this->SendPacket(p);
360 }
361 return NETWORK_RECV_STATUS_OKAY;
362 }
363
365 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo()
366 {
367 /* Fetch the latest version of the stats */
368 NetworkCompanyStats company_stats[MAX_COMPANIES];
369 NetworkPopulateCompanyStats(company_stats);
370
371 /* Make a list of all clients per company */
372 char clients[MAX_COMPANIES][NETWORK_CLIENTS_LENGTH];
373 NetworkClientSocket *csi;
374 memset(clients, 0, sizeof(clients));
375
376 /* Add the local player (if not dedicated) */
377 const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
378 if (ci != NULL && Company::IsValidID(ci->client_playas)) {
379 strecpy(clients[ci->client_playas], ci->client_name, lastof(clients[ci->client_playas]));
380 }
381
382 FOR_ALL_CLIENT_SOCKETS(csi) {
383 char client_name[NETWORK_CLIENT_NAME_LENGTH];
384
385 ((ServerNetworkGameSocketHandler*)csi)->GetClientName(client_name, lastof(client_name));
386
387 ci = csi->GetInfo();
388 if (ci != NULL && Company::IsValidID(ci->client_playas)) {
389 if (!StrEmpty(clients[ci->client_playas])) {
390 strecat(clients[ci->client_playas], ", ", lastof(clients[ci->client_playas]));
391 }
392
393 strecat(clients[ci->client_playas], client_name, lastof(clients[ci->client_playas]));
394 }
395 }
396
397 /* Now send the data */
398
399 Company *company;
400 Packet *p;
401
402 FOR_ALL_COMPANIES(company) {
403 p = new Packet(PACKET_SERVER_COMPANY_INFO);
404
405 p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
406 p->Send_bool (true);
407 this->SendCompanyInformation(p, company, &company_stats[company->index]);
408
409 if (StrEmpty(clients[company->index])) {
410 p->Send_string("<none>");
411 } else {
412 p->Send_string(clients[company->index]);
413 }
414
415 this->SendPacket(p);
416 }
417
418 p = new Packet(PACKET_SERVER_COMPANY_INFO);
419
420 p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
421 p->Send_bool (false);
422
423 this->SendPacket(p);
424 return NETWORK_RECV_STATUS_OKAY;
425 }
426
431 NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error)
432 {
433 char str[100];
434 Packet *p = new Packet(PACKET_SERVER_ERROR);
435
436 p->Send_uint8(error);
437 this->SendPacket(p);
438
439 StringID strid = GetNetworkErrorMsg(error);
440 GetString(str, strid, lastof(str));
441
442 /* Only send when the current client was in game */
443 if (this->status > STATUS_AUTHORIZED) {
444 NetworkClientSocket *new_cs;
445 char client_name[NETWORK_CLIENT_NAME_LENGTH];
446
447 this->GetClientName(client_name, lastof(client_name));
448
449 DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
450
451 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid);
452
453 FOR_ALL_CLIENT_SOCKETS(new_cs) {
454 if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
455 /* Some errors we filter to a more general error. Clients don't have to know the real
456 * reason a joining failed. */
457 if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) {
458 error = NETWORK_ERROR_ILLEGAL_PACKET;
459 }
460 new_cs->SendErrorQuit(this->client_id, error);
461 }
462 }
463
464 NetworkAdminClientError(this->client_id, error);
465 } else {
466 DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", this->client_id, str);
467 }
468
469 /* The client made a mistake, so drop his connection now! */
470 return this->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
471 }
472
474 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
475 {
476 Packet *p = new Packet(PACKET_SERVER_CHECK_NEWGRFS);
477 const GRFConfig *c;
478 uint grf_count = 0;
479
480 for (c = _grfconfig; c != NULL; c = c->next) {
481 if (!HasBit(c->flags, GCF_STATIC)) grf_count++;
482 }
483
484 p->Send_uint8 (grf_count);
485 for (c = _grfconfig; c != NULL; c = c->next) {
486 if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
487 }
488
489 this->SendPacket(p);
490 return NETWORK_RECV_STATUS_OKAY;
491 }
492
494 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
495 {
496 /* Invalid packet when status is STATUS_AUTH_GAME or higher */
497 if (this->status >= STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
498
499 this->status = STATUS_AUTH_GAME;
500 /* Reset 'lag' counters */
501 this->last_frame = this->last_frame_server = _frame_counter;
502
503 Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
504 this->SendPacket(p);
505 return NETWORK_RECV_STATUS_OKAY;
506 }
507
509 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
510 {
511 /* Invalid packet when status is STATUS_AUTH_COMPANY or higher */
512 if (this->status >= STATUS_AUTH_COMPANY) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
513
514 this->status = STATUS_AUTH_COMPANY;
515 /* Reset 'lag' counters */
516 this->last_frame = this->last_frame_server = _frame_counter;
517
518 Packet *p = new Packet(PACKET_SERVER_NEED_COMPANY_PASSWORD);
519 p->Send_uint32(_settings_game.game_creation.generation_seed);
520 p->Send_string(_settings_client.network.network_id);
521 this->SendPacket(p);
522 return NETWORK_RECV_STATUS_OKAY;
523 }
524
526 NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
527 {
528 Packet *p;
529 NetworkClientSocket *new_cs;
530
531 /* Invalid packet when status is AUTH or higher */
532 if (this->status >= STATUS_AUTHORIZED) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
533
534 this->status = STATUS_AUTHORIZED;
535 /* Reset 'lag' counters */
536 this->last_frame = this->last_frame_server = _frame_counter;
537
538 _network_game_info.clients_on++;
539
540 p = new Packet(PACKET_SERVER_WELCOME);
541 p->Send_uint32(this->client_id);
542 p->Send_uint32(_settings_game.game_creation.generation_seed);
543 p->Send_string(_settings_client.network.network_id);
544 this->SendPacket(p);
545
546 /* Transmit info about all the active clients */
547 FOR_ALL_CLIENT_SOCKETS(new_cs) {
548 if (new_cs != this && new_cs->status > STATUS_AUTHORIZED) {
549 this->SendClientInfo(new_cs->GetInfo());
550 }
551 }
552 /* Also send the info of the server */
553 return this->SendClientInfo(NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER));
554 }
555
557 NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait()
558 {
559 int waiting = 0;
560 NetworkClientSocket *new_cs;
561 Packet *p;
562
563 /* Count how many clients are waiting in the queue, in front of you! */
564 FOR_ALL_CLIENT_SOCKETS(new_cs) {
565 if (new_cs->status != STATUS_MAP_WAIT) continue;
566 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++;
567 }
568
569 p = new Packet(PACKET_SERVER_WAIT);
570 p->Send_uint8(waiting);
571 this->SendPacket(p);
572 return NETWORK_RECV_STATUS_OKAY;
573 }
574
576 NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
577 {
578 static uint sent_packets; // How many packets we did send successfully last time
579
580 if (this->status < STATUS_AUTHORIZED) {
581 /* Illegal call, return error and ignore the packet */
582 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
583 }
584
585 if (this->status == STATUS_AUTHORIZED) {
586 this->savegame = new PacketWriter(this);
587
588 /* Now send the _frame_counter and how many packets are coming */
589 Packet *p = new Packet(PACKET_SERVER_MAP_BEGIN);
590 p->Send_uint32(_frame_counter);
591 this->SendPacket(p);
592
593 NetworkSyncCommandQueue(this);
594 this->status = STATUS_MAP;
595 /* Mark the start of download */
596 this->last_frame = _frame_counter;
597 this->last_frame_server = _frame_counter;
598
599 sent_packets = 4; // We start with trying 4 packets
600
601 /* Make a dump of the current game */
602 if (SaveWithFilter(this->savegame, true) != SL_OK) usererror("network savedump failed");
603 }
604
605 if (this->status == STATUS_MAP) {
606 bool last_packet = false;
607 bool has_packets = false;
608
609 for (uint i = 0; (has_packets = this->savegame->HasPackets()) && i < sent_packets; i++) {
610 Packet *p = this->savegame->PopPacket();
611 last_packet = p->buffer[2] == PACKET_SERVER_MAP_DONE;
612
613 this->SendPacket(p);
614
615 if (last_packet) {
616 /* There is no more data, so break the for */
617 break;
618 }
619 }
620
621 if (last_packet) {
622 /* Done reading, make sure saving is done as well */
623 this->savegame->Destroy();
624 this->savegame = NULL;
625
626 /* Set the status to DONE_MAP, no we will wait for the client
627 * to send it is ready (maybe that happens like never ;)) */
628 this->status = STATUS_DONE_MAP;
629
630 /* Find the best candidate for joining, i.e. the first joiner. */
631 NetworkClientSocket *new_cs;
632 NetworkClientSocket *best = NULL;
633 FOR_ALL_CLIENT_SOCKETS(new_cs) {
634 if (new_cs->status == STATUS_MAP_WAIT) {
635 if (best == NULL || 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)) {
636 best = new_cs;
637 }
638 }
639 }
640
641 /* Is there someone else to join? */
642 if (best != NULL) {
643 /* Let the first start joining. */
644 best->status = STATUS_AUTHORIZED;
645 best->SendMap();
646
647 /* And update the rest. */
648 FOR_ALL_CLIENT_SOCKETS(new_cs) {
649 if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait();
650 }
651 }
652 }
653
654 switch (this->SendPackets()) {
655 case SPS_CLOSED:
656 return NETWORK_RECV_STATUS_CONN_LOST;
657
658 case SPS_ALL_SENT:
659 /* All are sent, increase the sent_packets */
660 if (has_packets) sent_packets *= 2;
661 break;
662
663 case SPS_PARTLY_SENT:
664 /* Only a part is sent; leave the transmission state. */
665 break;
666
667 case SPS_NONE_SENT:
668 /* Not everything is sent, decrease the sent_packets */
669 if (sent_packets > 1) sent_packets /= 2;
670 break;
671 }
672 }
673 return NETWORK_RECV_STATUS_OKAY;
674 }
675
680 NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
681 {
682 Packet *p = new Packet(PACKET_SERVER_JOIN);
683
684 p->Send_uint32(client_id);
685
686 this->SendPacket(p);
687 return NETWORK_RECV_STATUS_OKAY;
688 }
689
691 NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
692 {
693 Packet *p = new Packet(PACKET_SERVER_FRAME);
694 p->Send_uint32(_frame_counter);
695 p->Send_uint32(_frame_counter_max);
696 #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
697 p->Send_uint32(_sync_seed_1);
698 #ifdef NETWORK_SEND_DOUBLE_SEED
699 p->Send_uint32(_sync_seed_2);
700 #endif
701 #endif
702
703 /* If token equals 0, we need to make a new token and send that. */
704 if (this->last_token == 0) {
705 this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1;
706 p->Send_uint8(this->last_token);
707 }
708
709 this->SendPacket(p);
710 return NETWORK_RECV_STATUS_OKAY;
711 }
712
714 NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
715 {
716 Packet *p = new Packet(PACKET_SERVER_SYNC);
717 p->Send_uint32(_frame_counter);
718 p->Send_uint32(_sync_seed_1);
719
720 #ifdef NETWORK_SEND_DOUBLE_SEED
721 p->Send_uint32(_sync_seed_2);
722 #endif
723 this->SendPacket(p);
724 return NETWORK_RECV_STATUS_OKAY;
725 }
726
731 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCommand(const CommandPacket *cp)
732 {
733 Packet *p = new Packet(PACKET_SERVER_COMMAND);
734
735 this->NetworkGameSocketHandler::SendCommand(p, cp);
736 p->Send_uint32(cp->frame);
737 p->Send_bool (cp->my_cmd);
738
739 this->SendPacket(p);
740 return NETWORK_RECV_STATUS_OKAY;
741 }
742
751 NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, int64 data)
752 {
753 if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
754
755 Packet *p = new Packet(PACKET_SERVER_CHAT);
756
757 p->Send_uint8 (action);
758 p->Send_uint32(client_id);
759 p->Send_bool (self_send);
760 p->Send_string(msg);
761 p->Send_uint64(data);
762
763 this->SendPacket(p);
764 return NETWORK_RECV_STATUS_OKAY;
765 }
766
772 NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
773 {
774 Packet *p = new Packet(PACKET_SERVER_ERROR_QUIT);
775
776 p->Send_uint32(client_id);
777 p->Send_uint8 (errorno);
778
779 this->SendPacket(p);
780 return NETWORK_RECV_STATUS_OKAY;
781 }
782
787 NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
788 {
789 Packet *p = new Packet(PACKET_SERVER_QUIT);
790
791 p->Send_uint32(client_id);
792
793 this->SendPacket(p);
794 return NETWORK_RECV_STATUS_OKAY;
795 }
796
798 NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
799 {
800 Packet *p = new Packet(PACKET_SERVER_SHUTDOWN);
801 this->SendPacket(p);
802 return NETWORK_RECV_STATUS_OKAY;
803 }
804
806 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame()
807 {
808 Packet *p = new Packet(PACKET_SERVER_NEWGAME);
809 this->SendPacket(p);
810 return NETWORK_RECV_STATUS_OKAY;
811 }
812
818 NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16 colour, const char *command)
819 {
820 Packet *p = new Packet(PACKET_SERVER_RCON);
821
822 p->Send_uint16(colour);
823 p->Send_string(command);
824 this->SendPacket(p);
825 return NETWORK_RECV_STATUS_OKAY;
826 }
827
833 NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, CompanyID company_id)
834 {
835 Packet *p = new Packet(PACKET_SERVER_MOVE);
836
837 p->Send_uint32(client_id);
838 p->Send_uint8(company_id);
839 this->SendPacket(p);
840 return NETWORK_RECV_STATUS_OKAY;
841 }
842
844 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
845 {
846 Packet *p = new Packet(PACKET_SERVER_COMPANY_UPDATE);
847
848 p->Send_uint16(_network_company_passworded);
849 this->SendPacket(p);
850 return NETWORK_RECV_STATUS_OKAY;
851 }
852
854 NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
855 {
856 Packet *p = new Packet(PACKET_SERVER_CONFIG_UPDATE);
857
858 p->Send_uint8(_settings_client.network.max_companies);
859 p->Send_uint8(_settings_client.network.max_spectators);
860 this->SendPacket(p);
861 return NETWORK_RECV_STATUS_OKAY;
862 }
863
864 /***********
865 * Receiving functions
866 * DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p
867 ************/
868
869 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_INFO(Packet *p)
870 {
871 return this->SendCompanyInfo();
872 }
873
874 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet *p)
875 {
876 if (this->status != STATUS_NEWGRFS_CHECK) {
877 /* Illegal call, return error and ignore the packet */
878 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
879 }
880
881 NetworkClientInfo *ci = this->GetInfo();
882
883 /* We now want a password from the client else we do not allow him in! */
884 if (!StrEmpty(_settings_client.network.server_password)) {
885 return this->SendNeedGamePassword();
886 }
887
888 if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
889 return this->SendNeedCompanyPassword();
890 }
891
892 return this->SendWelcome();
893 }
894
895 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p)
896 {
897 if (this->status != STATUS_INACTIVE) {
898 /* Illegal call, return error and ignore the packet */
899 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
900 }
901
902 char name[NETWORK_CLIENT_NAME_LENGTH];
903 CompanyID playas;
904 NetworkLanguage client_lang;
905 char client_revision[NETWORK_REVISION_LENGTH];
906
907 p->Recv_string(client_revision, sizeof(client_revision));
908 uint32 newgrf_version = p->Recv_uint32();
909
910 /* Check if the client has revision control enabled */
911 if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) {
912 /* Different revisions!! */
913 return this->SendError(NETWORK_ERROR_WRONG_REVISION);
914 }
915
916 p->Recv_string(name, sizeof(name));
917 playas = (Owner)p->Recv_uint8();
918 client_lang = (NetworkLanguage)p->Recv_uint8();
919
920 if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
921
922 /* join another company does not affect these values */
923 switch (playas) {
924 case COMPANY_NEW_COMPANY: // New company
925 if (Company::GetNumItems() >= _settings_client.network.max_companies) {
926 return this->SendError(NETWORK_ERROR_FULL);
927 }
928 break;
929 case COMPANY_SPECTATOR: // Spectator
930 if (NetworkSpectatorCount() >= _settings_client.network.max_spectators) {
931 return this->SendError(NETWORK_ERROR_FULL);
932 }
933 break;
934 default: // Join another company (companies 1-8 (index 0-7))
935 if (!Company::IsValidHumanID(playas)) {
936 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
937 }
938 break;
939 }
940
941 /* We need a valid name.. make it Player */
942 if (StrEmpty(name)) strecpy(name, "Player", lastof(name));
943
944 if (!NetworkFindName(name, lastof(name))) { // Change name if duplicate
945 /* We could not create a name for this client */
946 return this->SendError(NETWORK_ERROR_NAME_IN_USE);
947 }
948
949 assert(NetworkClientInfo::CanAllocateItem());
950 NetworkClientInfo *ci = new NetworkClientInfo(this->client_id);
951 this->SetInfo(ci);
952 ci->join_date = _date;
953 strecpy(ci->client_name, name, lastof(ci->client_name));
954 ci->client_playas = playas;
955 ci->client_lang = client_lang;
956 DEBUG(desync, 1, "client: %08x; %02x; %02x; %02x", _date, _date_fract, (int)ci->client_playas, (int)ci->index);
957
958 /* Make sure companies to which people try to join are not autocleaned */
959 if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0;
960
961 this->status = STATUS_NEWGRFS_CHECK;
962
963 if (_grfconfig == NULL) {
964 /* Behave as if we received PACKET_CLIENT_NEWGRFS_CHECKED */
965 return this->Receive_CLIENT_NEWGRFS_CHECKED(NULL);
966 }
967
968 return this->SendNewGRFCheck();
969 }
970
971 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p)
972 {
973 if (this->status != STATUS_AUTH_GAME) {
974 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
975 }
976
977 char password[NETWORK_PASSWORD_LENGTH];
978 p->Recv_string(password, sizeof(password));
979
980 /* Check game password. Allow joining if we cleared the password meanwhile */
981 if (!StrEmpty(_settings_client.network.server_password) &&
982 strcmp(password, _settings_client.network.server_password) != 0) {
983 /* Password is invalid */
984 return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
985 }
986
987 const NetworkClientInfo *ci = this->GetInfo();
988 if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
989 return this->SendNeedCompanyPassword();
990 }
991
992 /* Valid password, allow user */
993 return this->SendWelcome();
994 }
995
996 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p)
997 {
998 if (this->status != STATUS_AUTH_COMPANY) {
999 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1000 }
1001
1002 char password[NETWORK_PASSWORD_LENGTH];
1003 p->Recv_string(password, sizeof(password));
1004
1005 /* Check company password. Allow joining if we cleared the password meanwhile.
1006 * Also, check the company is still valid - client could be moved to spectators
1007 * in the middle of the authorization process */
1008 CompanyID playas = this->GetInfo()->client_playas;
1009 if (Company::IsValidID(playas) && !StrEmpty(_network_company_states[playas].password) &&
1010 strcmp(password, _network_company_states[playas].password) != 0) {
1011 /* Password is invalid */
1012 return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
1013 }
1014
1015 return this->SendWelcome();
1016 }
1017
1018 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p)
1019 {
1020 NetworkClientSocket *new_cs;
1021 /* The client was never joined.. so this is impossible, right?
1022 * Ignore the packet, give the client a warning, and close his connection */
1023 if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) {
1024 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1025 }
1026
1027 /* Check if someone else is receiving the map */
1028 FOR_ALL_CLIENT_SOCKETS(new_cs) {
1029 if (new_cs->status == STATUS_MAP) {
1030 /* Tell the new client to wait */
1031 this->status = STATUS_MAP_WAIT;
1032 return this->SendWait();
1033 }
1034 }
1035
1036 /* We receive a request to upload the map.. give it to the client! */
1037 return this->SendMap();
1038 }
1039
1040 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *p)
1041 {
1042 /* Client has the map, now start syncing */
1043 if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
1044 char client_name[NETWORK_CLIENT_NAME_LENGTH];
1045 NetworkClientSocket *new_cs;
1046
1047 this->GetClientName(client_name, lastof(client_name));
1048
1049 NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, NULL, this->client_id);
1050
1051 /* Mark the client as pre-active, and wait for an ACK
1052 * so we know he is done loading and in sync with us */
1053 this->status = STATUS_PRE_ACTIVE;
1054 NetworkHandleCommandQueue(this);
1055 this->SendFrame();
1056 this->SendSync();
1057
1058 /* This is the frame the client receives
1059 * we need it later on to make sure the client is not too slow */
1060 this->last_frame = _frame_counter;
1061 this->last_frame_server = _frame_counter;
1062
1063 FOR_ALL_CLIENT_SOCKETS(new_cs) {
1064 if (new_cs->status > STATUS_AUTHORIZED) {
1065 new_cs->SendClientInfo(this->GetInfo());
1066 new_cs->SendJoin(this->client_id);
1067 }
1068 }
1069
1070 NetworkAdminClientInfo(this, true);
1071
1072 /* also update the new client with our max values */
1073 this->SendConfigUpdate();
1074
1075 /* quickly update the syncing client with company details */
1076 return this->SendCompanyUpdate();
1077 }
1078
1079 /* Wrong status for this packet, give a warning to client, and close connection */
1080 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1081 }
1082
1087 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet *p)
1088 {
1089 /* The client was never joined.. so this is impossible, right?
1090 * Ignore the packet, give the client a warning, and close his connection */
1091 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1092 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1093 }
1094
1095 if (this->incoming_queue.Count() >= _settings_client.network.max_commands_in_queue) {
1096 return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
1097 }
1098
1099 CommandPacket cp;
1100 const char *err = this->ReceiveCommand(p, &cp);
1101
1102 if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
1103
1104 NetworkClientInfo *ci = this->GetInfo();
1105
1106 if (err != NULL) {
1107 IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, this->GetClientIP());
1108 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1109 }
1110
1111
1112 if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER) {
1113 IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
1114 return this->SendError(NETWORK_ERROR_KICKED);
1115 }
1116
1117 if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) {
1118 IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
1119 return this->SendError(NETWORK_ERROR_KICKED);
1120 }
1121
1127 if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
1128 IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
1129 ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
1130 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
1131 }
1132
1133 if (cp.cmd == CMD_COMPANY_CTRL) {
1134 if (cp.p1 != 0 || cp.company != COMPANY_SPECTATOR) {
1135 return this->SendError(NETWORK_ERROR_CHEATER);
1136 }
1137
1138 /* 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! */
1139 if (Company::GetNumItems() >= _settings_client.network.max_companies) {
1140 NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
1141 return NETWORK_RECV_STATUS_OKAY;
1142 }
1143 }
1144
1145 if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) cp.p2 = this->client_id;
1146
1147 this->incoming_queue.Append(&cp);
1148 return NETWORK_RECV_STATUS_OKAY;
1149 }
1150
1151 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p)
1152 {
1153 /* This packets means a client noticed an error and is reporting this
1154 * to us. Display the error and report it to the other clients */
1155 NetworkClientSocket *new_cs;
1156 char str[100];
1157 char client_name[NETWORK_CLIENT_NAME_LENGTH];
1158 NetworkErrorCode errorno = (NetworkErrorCode)p->Recv_uint8();
1159
1160 /* The client was never joined.. thank the client for the packet, but ignore it */
1161 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1162 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
1163 }
1164
1165 this->GetClientName(client_name, lastof(client_name));
1166
1167 StringID strid = GetNetworkErrorMsg(errorno);
1168 GetString(str, strid, lastof(str));
1169
1170 DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
1171
1172 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid);
1173
1174 FOR_ALL_CLIENT_SOCKETS(new_cs) {
1175 if (new_cs->status > STATUS_AUTHORIZED) {
1176 new_cs->SendErrorQuit(this->client_id, errorno);
1177 }
1178 }
1179
1180 NetworkAdminClientError(this->client_id, errorno);
1181
1182 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
1183 }
1184
1185 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p)
1186 {
1187 /* The client wants to leave. Display this and report it to the other
1188 * clients. */
1189 NetworkClientSocket *new_cs;
1190 char client_name[NETWORK_CLIENT_NAME_LENGTH];
1191
1192 /* The client was never joined.. thank the client for the packet, but ignore it */
1193 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1194 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
1195 }
1196
1197 this->GetClientName(client_name, lastof(client_name));
1198
1199 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING);
1200
1201 FOR_ALL_CLIENT_SOCKETS(new_cs) {
1202 if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
1203 new_cs->SendQuit(this->client_id);
1204 }
1205 }
1206
1207 NetworkAdminClientQuit(this->client_id);
1208
1209 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
1210 }
1211
1212 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p)
1213 {
1214 if (this->status < STATUS_AUTHORIZED) {
1215 /* Illegal call, return error and ignore the packet */
1216 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1217 }
1218
1219 uint32 frame = p->Recv_uint32();
1220
1221 /* The client is trying to catch up with the server */
1222 if (this->status == STATUS_PRE_ACTIVE) {
1223 /* The client is not yet catched up? */
1224 if (frame + DAY_TICKS < _frame_counter) return NETWORK_RECV_STATUS_OKAY;
1225
1226 /* Now he is! Unpause the game */
1227 this->status = STATUS_ACTIVE;
1228 this->last_token_frame = _frame_counter;
1229
1230 /* Execute script for, e.g. MOTD */
1231 IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
1232 }
1233
1234 /* Get, and validate the token. */
1235 uint8 token = p->Recv_uint8();
1236 if (token == this->last_token) {
1237 /* We differentiate between last_token_frame and last_frame so the lag
1238 * test uses the actual lag of the client instead of the lag for getting
1239 * the token back and forth; after all, the token is only sent every
1240 * time we receive a PACKET_CLIENT_ACK, after which we will send a new
1241 * token to the client. If the lag would be one day, then we would not
1242 * be sending the new token soon enough for the new daily scheduled
1243 * PACKET_CLIENT_ACK. This would then register the lag of the client as
1244 * two days, even when it's only a single day. */
1245 this->last_token_frame = _frame_counter;
1246 /* Request a new token. */
1247 this->last_token = 0;
1248 }
1249
1250 /* The client received the frame, make note of it */
1251 this->last_frame = frame;
1252 /* With those 2 values we can calculate the lag realtime */
1253 this->last_frame_server = _frame_counter;
1254 return NETWORK_RECV_STATUS_OKAY;
1255 }
1256
1257
1268 void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, ClientID from_id, int64 data, bool from_admin)
1269 {
1270 NetworkClientSocket *cs;
1271 const NetworkClientInfo *ci, *ci_own, *ci_to;
1272
1273 switch (desttype) {
1274 case DESTTYPE_CLIENT:
1275 /* Are we sending to the server? */
1276 if ((ClientID)dest == CLIENT_ID_SERVER) {
1277 ci = NetworkClientInfo::GetByClientID(from_id);
1278 /* Display the text locally, and that is it */
1279 if (ci != NULL) {
1280 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1281
1282 if (_settings_client.network.server_admin_chat) {
1283 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1284 }
1285 }
1286 } else {
1287 /* Else find the client to send the message to */
1288 FOR_ALL_CLIENT_SOCKETS(cs) {
1289 if (cs->client_id == (ClientID)dest) {
1290 cs->SendChat(action, from_id, false, msg, data);
1291 break;
1292 }
1293 }
1294 }
1295
1296 /* Display the message locally (so you know you have sent it) */
1297 if (from_id != (ClientID)dest) {
1298 if (from_id == CLIENT_ID_SERVER) {
1299 ci = NetworkClientInfo::GetByClientID(from_id);
1300 ci_to = NetworkClientInfo::GetByClientID((ClientID)dest);
1301 if (ci != NULL && ci_to != NULL) {
1302 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
1303 }
1304 } else {
1305 FOR_ALL_CLIENT_SOCKETS(cs) {
1306 if (cs->client_id == from_id) {
1307 cs->SendChat(action, (ClientID)dest, true, msg, data);
1308 break;
1309 }
1310 }
1311 }
1312 }
1313 break;
1314 case DESTTYPE_TEAM: {
1315 /* If this is false, the message is already displayed on the client who sent it. */
1316 bool show_local = true;
1317 /* Find all clients that belong to this company */
1318 ci_to = NULL;
1319 FOR_ALL_CLIENT_SOCKETS(cs) {
1320 ci = cs->GetInfo();
1321 if (ci != NULL && ci->client_playas == (CompanyID)dest) {
1322 cs->SendChat(action, from_id, false, msg, data);
1323 if (cs->client_id == from_id) show_local = false;
1324 ci_to = ci; // Remember a client that is in the company for company-name
1325 }
1326 }
1327
1328 /* if the server can read it, let the admin network read it, too. */
1329 if (_local_company == (CompanyID)dest && _settings_client.network.server_admin_chat) {
1330 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1331 }
1332
1333 ci = NetworkClientInfo::GetByClientID(from_id);
1334 ci_own = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
1335 if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
1336 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1337 if (from_id == CLIENT_ID_SERVER) show_local = false;
1338 ci_to = ci_own;
1339 }
1340
1341 /* There is no such client */
1342 if (ci_to == NULL) break;
1343
1344 /* Display the message locally (so you know you have sent it) */
1345 if (ci != NULL && show_local) {
1346 if (from_id == CLIENT_ID_SERVER) {
1347 char name[NETWORK_NAME_LENGTH];
1348 StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
1349 SetDParam(0, ci_to->client_playas);
1350 GetString(name, str, lastof(name));
1351 NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
1352 } else {
1353 FOR_ALL_CLIENT_SOCKETS(cs) {
1354 if (cs->client_id == from_id) {
1355 cs->SendChat(action, ci_to->client_id, true, msg, data);
1356 }
1357 }
1358 }
1359 }
1360 break;
1361 }
1362 default:
1363 DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
1364 FALLTHROUGH;
1365
1366 case DESTTYPE_BROADCAST:
1367 FOR_ALL_CLIENT_SOCKETS(cs) {
1368 cs->SendChat(action, from_id, false, msg, data);
1369 }
1370
1371 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
1372
1373 ci = NetworkClientInfo::GetByClientID(from_id);
1374 if (ci != NULL) {
1375 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
1376 }
1377 break;
1378 }
1379 }
1380
1381 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p)
1382 {
1383 if (this->status < STATUS_PRE_ACTIVE) {
1384 /* Illegal call, return error and ignore the packet */
1385 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
1386 }
1387
1388 NetworkAction action = (NetworkAction)p->Recv_uint8();
1389 DestType desttype = (DestType)p->Recv_uint8();
1390 int dest = p->Recv_uint32();
1391 char msg[NETWORK_CHAT_LENGTH];
1392
1393 p->Recv_string(msg, NETWORK_CHAT_LENGTH);
1394 int64 data = p->Recv_uint64();
1395
1396 NetworkClientInfo *ci = this->GetInfo();
1397 switch (action) {
1398 case NETWORK_ACTION_GIVE_MONEY:
1399 if (!Company::IsValidID(ci->client_playas)) break;
1400 FALLTHROUGH;
1401 case NETWORK_ACTION_CHAT:
1402 case NETWORK_ACTION_CHAT_CLIENT:
1403 case NETWORK_ACTION_CHAT_COMPANY:
1404 NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
1405 break;
1406 default:
1407 IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, this->GetClientIP());
1408 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1409 }
1410 return NETWORK_RECV_STATUS_OKAY;
1411 }
1412
1413 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet *p)
1414 {
1415 if (this->status != STATUS_ACTIVE) {
1416 /* Illegal call, return error and ignore the packet */
1417 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1418 }
1419
1420 char password[NETWORK_PASSWORD_LENGTH];
1421 const NetworkClientInfo *ci;
1422
1423 p->Recv_string(password, sizeof(password));
1424 ci = this->GetInfo();
1425
1426 NetworkServerSetCompanyPassword(ci->client_playas, password);
1427 return NETWORK_RECV_STATUS_OKAY;
1428 }
1429
1430 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p)
1431 {
1432 if (this->status != STATUS_ACTIVE) {
1433 /* Illegal call, return error and ignore the packet */
1434 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1435 }
1436
1437 char client_name[NETWORK_CLIENT_NAME_LENGTH];
1438 NetworkClientInfo *ci;
1439
1440 p->Recv_string(client_name, sizeof(client_name));
1441 ci = this->GetInfo();
1442
1443 if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
1444
1445 if (ci != NULL) {
1446 /* Display change */
1447 if (NetworkFindName(client_name, lastof(client_name))) {
1448 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);
1449 strecpy(ci->client_name, client_name, lastof(ci->client_name));
1450 NetworkUpdateClientInfo(ci->client_id);
1451 }
1452 }
1453 return NETWORK_RECV_STATUS_OKAY;
1454 }
1455
1456 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
1457 {
1458 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1459
1460 char pass[NETWORK_PASSWORD_LENGTH];
1461 char command[NETWORK_RCONCOMMAND_LENGTH];
1462
1463 if (StrEmpty(_settings_client.network.rcon_password)) return NETWORK_RECV_STATUS_OKAY;
1464
1465 p->Recv_string(pass, sizeof(pass));
1466 p->Recv_string(command, sizeof(command));
1467
1468 if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
1469 DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
1470 return NETWORK_RECV_STATUS_OKAY;
1471 }
1472
1473 DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", this->client_id, command);
1474
1475 _redirect_console_to_client = this->client_id;
1476 IConsoleCmdExec(command);
1477 _redirect_console_to_client = INVALID_CLIENT_ID;
1478 return NETWORK_RECV_STATUS_OKAY;
1479 }
1480
1481 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p)
1482 {
1483 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1484
1485 CompanyID company_id = (Owner)p->Recv_uint8();
1486
1487 /* Check if the company is valid, we don't allow moving to AI companies */
1488 if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
1489
1490 /* Check if we require a password for this company */
1491 if (company_id != COMPANY_SPECTATOR && !StrEmpty(_network_company_states[company_id].password)) {
1492 /* we need a password from the client - should be in this packet */
1493 char password[NETWORK_PASSWORD_LENGTH];
1494 p->Recv_string(password, sizeof(password));
1495
1496 /* Incorrect password sent, return! */
1497 if (strcmp(password, _network_company_states[company_id].password) != 0) {
1498 DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", this->client_id, company_id + 1);
1499 return NETWORK_RECV_STATUS_OKAY;
1500 }
1501 }
1502
1503 /* if we get here we can move the client */
1504 NetworkServerDoMove(this->client_id, company_id);
1505 return NETWORK_RECV_STATUS_OKAY;
1506 }
1507
1515 void NetworkSocketHandler::SendCompanyInformation(Packet *p, const Company *c, const NetworkCompanyStats *stats, uint max_len)
1516 {
1517 /* Grab the company name */
1518 char company_name[NETWORK_COMPANY_NAME_LENGTH];
1519 SetDParam(0, c->index);
1520
1521 assert(max_len <= lengthof(company_name));
1522 GetString(company_name, STR_COMPANY_NAME, company_name + max_len - 1);
1523
1524 /* Get the income */
1525 Money income = 0;
1526 if (_cur_year - 1 == c->inaugurated_year) {
1527 /* The company is here just 1 year, so display [2], else display[1] */
1528 for (uint i = 0; i < lengthof(c->yearly_expenses[2]); i++) {
1529 income -= c->yearly_expenses[2][i];
1530 }
1531 } else {
1532 for (uint i = 0; i < lengthof(c->yearly_expenses[1]); i++) {
1533 income -= c->yearly_expenses[1][i];
1534 }
1535 }
1536
1537 /* Send the information */
1538 p->Send_uint8 (c->index);
1539 p->Send_string(company_name);
1540 p->Send_uint32(c->inaugurated_year);
1541 p->Send_uint64(c->old_economy[0].company_value);
1542 p->Send_uint64(c->money);
1543 p->Send_uint64(income);
1544 p->Send_uint16(c->old_economy[0].performance_history);
1545
1546 /* Send 1 if there is a password for the company else send 0 */
1547 p->Send_bool (!StrEmpty(_network_company_states[c->index].password));
1548
1549 for (uint i = 0; i < NETWORK_VEH_END; i++) {
1550 p->Send_uint16(stats->num_vehicle[i]);
1551 }
1552
1553 for (uint i = 0; i < NETWORK_VEH_END; i++) {
1554 p->Send_uint16(stats->num_station[i]);
1555 }
1556
1557 p->Send_bool(c->is_ai);
1558 }
1559
1564 void NetworkPopulateCompanyStats(NetworkCompanyStats *stats)
1565 {
1566 const Vehicle *v;
1567 const Station *s;
1568
1569 memset(stats, 0, sizeof(*stats) * MAX_COMPANIES);
1570
1571 /* Go through all vehicles and count the type of vehicles */
1572 FOR_ALL_VEHICLES(v) {
1573 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
1574 byte type = 0;
1575 switch (v->type) {
1576 case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
1577 case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
1578 case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break;
1579 case VEH_SHIP: type = NETWORK_VEH_SHIP; break;
1580 default: continue;
1581 }
1582 stats[v->owner].num_vehicle[type]++;
1583 }
1584
1585 /* Go through all stations and count the types of stations */
1586 FOR_ALL_STATIONS(s) {
1587 if (Company::IsValidID(s->owner)) {
1588 NetworkCompanyStats *npi = &stats[s->owner];
1589
1590 if (s->facilities & FACIL_TRAIN) npi->num_station[NETWORK_VEH_TRAIN]++;
1591 if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[NETWORK_VEH_LORRY]++;
1592 if (s->facilities & FACIL_BUS_STOP) npi->num_station[NETWORK_VEH_BUS]++;
1593 if (s->facilities & FACIL_AIRPORT) npi->num_station[NETWORK_VEH_PLANE]++;
1594 if (s->facilities & FACIL_DOCK) npi->num_station[NETWORK_VEH_SHIP]++;
1595 }
1596 }
1597 }
1598
1603 void NetworkUpdateClientInfo(ClientID client_id)
1604 {
1605 NetworkClientSocket *cs;
1606 NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
1607
1608 if (ci == NULL) return;
1609
1610 DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id);
1611
1612 FOR_ALL_CLIENT_SOCKETS(cs) {
1613 cs->SendClientInfo(ci);
1614 }
1615
1616 NetworkAdminClientUpdate(ci);
1617 }
1618
1620 static void NetworkCheckRestartMap()
1621 {
1622 if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) {
1623 DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year);
1624
1625 StartNewGameWithoutGUI(GENERATE_NEW_SEED);
1626 }
1627 }
1628
1635 static void NetworkAutoCleanCompanies()
1636 {
1637 const NetworkClientInfo *ci;
1638 const Company *c;
1639 bool clients_in_company[MAX_COMPANIES];
1640 int vehicles_in_company[MAX_COMPANIES];
1641
1642 if (!_settings_client.network.autoclean_companies) return;
1643
1644 memset(clients_in_company, 0, sizeof(clients_in_company));
1645
1646 /* Detect the active companies */
1647 FOR_ALL_CLIENT_INFOS(ci) {
1648 if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
1649 }
1650
1651 if (!_network_dedicated) {
1652 ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
1653 if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
1654 }
1655
1656 if (_settings_client.network.autoclean_novehicles != 0) {
1657 memset(vehicles_in_company, 0, sizeof(vehicles_in_company));
1658
1659 const Vehicle *v;
1660 FOR_ALL_VEHICLES(v) {
1661 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
1662 vehicles_in_company[v->owner]++;
1663 }
1664 }
1665
1666 /* Go through all the companies */
1667 FOR_ALL_COMPANIES(c) {
1668 /* Skip the non-active once */
1669 if (c->is_ai) continue;
1670
1671 if (!clients_in_company[c->index]) {
1672 /* The company is empty for one month more */
1673 _network_company_states[c->index].months_empty++;
1674
1675 /* Is the company empty for autoclean_unprotected-months, and is there no protection? */
1676 if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && StrEmpty(_network_company_states[c->index].password)) {
1677 /* Shut the company down */
1678 DoCommandP(0, 2 | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL);
1679 IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1);
1680 }
1681 /* Is the company empty for autoclean_protected-months, and there is a protection? */
1682 if (_settings_client.network.autoclean_protected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_protected && !StrEmpty(_network_company_states[c->index].password)) {
1683 /* Unprotect the company */
1684 _network_company_states[c->index].password[0] = '\0';
1685 IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", c->index + 1);
1686 _network_company_states[c->index].months_empty = 0;
1687 NetworkServerUpdateCompanyPassworded(c->index, false);
1688 }
1689 /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
1690 if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) {
1691 /* Shut the company down */
1692 DoCommandP(0, 2 | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL);
1693 IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1);
1694 }
1695 } else {
1696 /* It is not empty, reset the date */
1697 _network_company_states[c->index].months_empty = 0;
1698 }
1699 }
1700 }
1701
1708 bool NetworkFindName(char *new_name, const char *last)
1709 {
1710 bool found_name = false;
1711 uint number = 0;
1712 char original_name[NETWORK_CLIENT_NAME_LENGTH];
1713
1714 strecpy(original_name, new_name, lastof(original_name));
1715
1716 while (!found_name) {
1717 const NetworkClientInfo *ci;
1718
1719 found_name = true;
1720 FOR_ALL_CLIENT_INFOS(ci) {
1721 if (strcmp(ci->client_name, new_name) == 0) {
1722 /* Name already in use */
1723 found_name = false;
1724 break;
1725 }
1726 }
1727 /* Check if it is the same as the server-name */
1728 ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
1729 if (ci != NULL) {
1730 if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use
1731 }
1732
1733 if (!found_name) {
1734 /* Try a new name (<name> #1, <name> #2, and so on) */
1735
1736 /* Something's really wrong when there're more names than clients */
1737 if (number++ > MAX_CLIENTS) break;
1738 seprintf(new_name, last, "%s #%d", original_name, number);
1739 }
1740 }
1741
1742 return found_name;
1743 }
1744
1751 bool NetworkServerChangeClientName(ClientID client_id, const char *new_name)
1752 {
1753 NetworkClientInfo *ci;
1754 /* Check if the name's already in use */
1755 FOR_ALL_CLIENT_INFOS(ci) {
1756 if (strcmp(ci->client_name, new_name) == 0) return false;
1757 }
1758
1759 ci = NetworkClientInfo::GetByClientID(client_id);
1760 if (ci == NULL) return false;
1761
1762 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name);
1763
1764 strecpy(ci->client_name, new_name, lastof(ci->client_name));
1765
1766 NetworkUpdateClientInfo(client_id);
1767 return true;
1768 }
1769
1776 void NetworkServerSetCompanyPassword(CompanyID company_id, const char *password, bool already_hashed)
1777 {
1778 if (!Company::IsValidHumanID(company_id)) return;
1779
1780 if (!already_hashed) {
1781 password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed);
1782 }
1783
1784 strecpy(_network_company_states[company_id].password, password, lastof(_network_company_states[company_id].password));
1785 NetworkServerUpdateCompanyPassworded(company_id, !StrEmpty(_network_company_states[company_id].password));
1786 }
1787
1792 static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
1793 {
1794 CommandPacket *cp;
1795 while ((cp = cs->outgoing_queue.Pop()) != NULL) {
1796 cs->SendCommand(cp);
1797 free(cp);
1798 }
1799 }
1800
1805 void NetworkServer_Tick(bool send_frame)
1806 {
1807 NetworkClientSocket *cs;
1808 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1809 bool send_sync = false;
1810 #endif
1811
1812 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1813 if (_frame_counter >= _last_sync_frame + _settings_client.network.sync_freq) {
1814 _last_sync_frame = _frame_counter;
1815 send_sync = true;
1816 }
1817 #endif
1818
1819 /* Now we are done with the frame, inform the clients that they can
1820 * do their frame! */
1821 FOR_ALL_CLIENT_SOCKETS(cs) {
1822 /* We allow a number of bytes per frame, but only to the burst amount
1823 * to be available for packet receiving at any particular time. */
1824 cs->receive_limit = min(cs->receive_limit + _settings_client.network.bytes_per_frame,
1825 _settings_client.network.bytes_per_frame_burst);
1826
1827 /* Check if the speed of the client is what we can expect from a client */
1828 uint lag = NetworkCalculateLag(cs);
1829 switch (cs->status) {
1830 case NetworkClientSocket::STATUS_ACTIVE:
1831 if (lag > _settings_client.network.max_lag_time) {
1832 /* Client did still not report in within the specified limit. */
1833 IConsolePrintF(CC_ERROR, cs->last_packet + lag * MILLISECONDS_PER_TICK > _realtime_tick ?
1834 /* A packet was received in the last three game days, so the client is likely lagging behind. */
1835 "Client #%d is dropped because the client's game state is more than %d ticks behind" :
1836 /* No packet was received in the last three game days; sounds like a lost connection. */
1837 "Client #%d is dropped because the client did not respond for more than %d ticks",
1838 cs->client_id, lag);
1839 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1840 continue;
1841 }
1842
1843 /* Report once per time we detect the lag, and only when we
1844 * received a packet in the last 2000 milliseconds. If we
1845 * did not receive a packet, then the client is not just
1846 * slow, but the connection is likely severed. Mentioning
1847 * frame_freq is not useful in this case. */
1848 if (lag > (uint)DAY_TICKS && cs->lag_test == 0 && cs->last_packet + 2000 > _realtime_tick) {
1849 IConsolePrintF(CC_WARNING, "[%d] Client #%d is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
1850 cs->lag_test = 1;
1851 }
1852
1853 if (cs->last_frame_server - cs->last_token_frame >= _settings_client.network.max_lag_time) {
1854 /* This is a bad client! It didn't send the right token back within time. */
1855 IConsolePrintF(CC_ERROR, "Client #%d is dropped because it fails to send valid acks", cs->client_id);
1856 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1857 continue;
1858 }
1859 break;
1860
1861 case NetworkClientSocket::STATUS_INACTIVE:
1862 case NetworkClientSocket::STATUS_NEWGRFS_CHECK:
1863 case NetworkClientSocket::STATUS_AUTHORIZED:
1864 /* NewGRF check and authorized states should be handled almost instantly.
1865 * So give them some lee-way, likewise for the query with inactive. */
1866 if (lag > _settings_client.network.max_init_time) {
1867 IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->client_id, _settings_client.network.max_init_time);
1868 cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER);
1869 continue;
1870 }
1871 break;
1872
1873 case NetworkClientSocket::STATUS_MAP:
1874 /* Downloading the map... this is the amount of time since starting the saving. */
1875 if (lag > _settings_client.network.max_download_time) {
1876 IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to download the map", cs->client_id, _settings_client.network.max_download_time);
1877 cs->SendError(NETWORK_ERROR_TIMEOUT_MAP);
1878 continue;
1879 }
1880 break;
1881
1882 case NetworkClientSocket::STATUS_DONE_MAP:
1883 case NetworkClientSocket::STATUS_PRE_ACTIVE:
1884 /* The map has been sent, so this is for loading the map and syncing up. */
1885 if (lag > _settings_client.network.max_join_time) {
1886 IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to join", cs->client_id, _settings_client.network.max_join_time);
1887 cs->SendError(NETWORK_ERROR_TIMEOUT_JOIN);
1888 continue;
1889 }
1890 break;
1891
1892 case NetworkClientSocket::STATUS_AUTH_GAME:
1893 case NetworkClientSocket::STATUS_AUTH_COMPANY:
1894 /* These don't block? */
1895 if (lag > _settings_client.network.max_password_time) {
1896 IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to enter the password", cs->client_id, _settings_client.network.max_password_time);
1897 cs->SendError(NETWORK_ERROR_TIMEOUT_PASSWORD);
1898 continue;
1899 }
1900 break;
1901
1902 case NetworkClientSocket::STATUS_MAP_WAIT:
1903 /* This is an internal state where we do not wait
1904 * on the client to move to a different state. */
1905 break;
1906
1907 case NetworkClientSocket::STATUS_END:
1908 /* Bad server/code. */
1909 NOT_REACHED();
1910 }
1911
1912 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
1913 /* Check if we can send command, and if we have anything in the queue */
1914 NetworkHandleCommandQueue(cs);
1915
1916 /* Send an updated _frame_counter_max to the client */
1917 if (send_frame) cs->SendFrame();
1918
1919 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
1920 /* Send a sync-check packet */
1921 if (send_sync) cs->SendSync();
1922 #endif
1923 }
1924 }
1925
1926 /* See if we need to advertise */
1927 NetworkUDPAdvertise();
1928 }
1929
1931 void NetworkServerYearlyLoop()
1932 {
1933 NetworkCheckRestartMap();
1934 NetworkAdminUpdate(ADMIN_FREQUENCY_ANUALLY);
1935 }
1936
1938 void NetworkServerMonthlyLoop()
1939 {
1940 NetworkAutoCleanCompanies();
1941 NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY);
1942 if ((_cur_month % 3) == 0) NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY);
1943 }
1944
1946 void NetworkServerDailyLoop()
1947 {
1948 NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY);
1949 if ((_date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);
1950 }
1951
1956 const char *ServerNetworkGameSocketHandler::GetClientIP()
1957 {
1958 return this->client_address.GetHostname();
1959 }
1960
1962 void NetworkServerShowStatusToConsole()
1963 {
1964 static const char * const stat_str[] = {
1965 "inactive",
1966 "checking NewGRFs",
1967 "authorizing (server password)",
1968 "authorizing (company password)",
1969 "authorized",
1970 "waiting",
1971 "loading map",
1972 "map done",
1973 "ready",
1974 "active"
1975 };
1976 assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
1977
1978 NetworkClientSocket *cs;
1979 FOR_ALL_CLIENT_SOCKETS(cs) {
1980 NetworkClientInfo *ci = cs->GetInfo();
1981 if (ci == NULL) continue;
1982 uint lag = NetworkCalculateLag(cs);
1983 const char *status;
1984
1985 status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
1986 IConsolePrintF(CC_INFO, "Client #%1d name: '%s' status: '%s' frame-lag: %3d company: %1d IP: %s",
1987 cs->client_id, ci->client_name, status, lag,
1988 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
1989 cs->GetClientIP());
1990 }
1991 }
1992
1996 void NetworkServerSendConfigUpdate()
1997 {
1998 NetworkClientSocket *cs;
1999
2000 FOR_ALL_CLIENT_SOCKETS(cs) {
2001 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate();
2002 }
2003 }
2004
2010 void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded)
2011 {
2012 if (NetworkCompanyIsPassworded(company_id) == passworded) return;
2013
2014 SB(_network_company_passworded, company_id, 1, !!passworded);
2015 SetWindowClassesDirty(WC_COMPANY);
2016
2017 NetworkClientSocket *cs;
2018 FOR_ALL_CLIENT_SOCKETS(cs) {
2019 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendCompanyUpdate();
2020 }
2021
2022 NetworkAdminCompanyUpdate(Company::GetIfValid(company_id));
2023 }
2024
2031 void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
2032 {
2033 /* Only allow non-dedicated servers and normal clients to be moved */
2034 if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
2035
2036 NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
2037
2038 /* No need to waste network resources if the client is in the company already! */
2039 if (ci->client_playas == company_id) return;
2040
2041 ci->client_playas = company_id;
2042
2043 if (client_id == CLIENT_ID_SERVER) {
2044 SetLocalCompany(company_id);
2045 } else {
2046 NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id);
2047 /* When the company isn't authorized we can't move them yet. */
2048 if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
2049 cs->SendMove(client_id, company_id);
2050 }
2051
2052 /* announce the client's move */
2053 NetworkUpdateClientInfo(client_id);
2054
2055 NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN;
2056 NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
2057 }
2058
2065 void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string)
2066 {
2067 NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string);
2068 }
2069
2074 void NetworkServerKickClient(ClientID client_id)
2075 {
2076 if (client_id == CLIENT_ID_SERVER) return;
2077 NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED);
2078 }
2079
2085 uint NetworkServerKickOrBanIP(ClientID client_id, bool ban)
2086 {
2087 return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban);
2088 }
2089
2095 uint NetworkServerKickOrBanIP(const char *ip, bool ban)
2096 {
2097 /* Add address to ban-list */
2098 if (ban) {
2099 bool contains = false;
2100 for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) {
2101 if (strcmp(*iter, ip) == 0) {
2102 contains = true;
2103 break;
2104 }
2105 }
2106 if (!contains) *_network_ban_list.Append() = stredup(ip);
2107 }
2108
2109 uint n = 0;
2110
2111 /* There can be multiple clients with the same IP, kick them all */
2112 NetworkClientSocket *cs;
2113 FOR_ALL_CLIENT_SOCKETS(cs) {
2114 if (cs->client_id == CLIENT_ID_SERVER) continue;
2115 if (cs->client_address.IsInNetmask(const_cast<char *>(ip))) {
2116 NetworkServerKickClient(cs->client_id);
2117 n++;
2118 }
2119 }
2120
2121 return n;
2122 }
2123
2129 bool NetworkCompanyHasClients(CompanyID company)
2130 {
2131 const NetworkClientInfo *ci;
2132 FOR_ALL_CLIENT_INFOS(ci) {
2133 if (ci->client_playas == company) return true;
2134 }
2135 return false;
2136 }
2137
2138
2144 void ServerNetworkGameSocketHandler::GetClientName(char *client_name, const char *last) const
2145 {
2146 const NetworkClientInfo *ci = this->GetInfo();
2147
2148 if (ci == NULL || StrEmpty(ci->client_name)) {
2149 seprintf(client_name, last, "Client #%4d", this->client_id);
2150 } else {
2151 strecpy(client_name, ci->client_name, last);
2152 }
2153 }
2154
2158 void NetworkPrintClients()
2159 {
2160 NetworkClientInfo *ci;
2161 FOR_ALL_CLIENT_INFOS(ci) {
2162 if (_network_server) {
2163 IConsolePrintF(CC_INFO, "Client #%1d name: '%s' company: %1d IP: %s",
2164 ci->client_id,
2165 ci->client_name,
2166 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
2167 ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP());
2168 } else {
2169 IConsolePrintF(CC_INFO, "Client #%1d name: '%s' company: %1d",
2170 ci->client_id,
2171 ci->client_name,
2172 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0));
2173 }
2174 }
2175 }
2176
2182 void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
2183 {
2184 assert(c != NULL);
2185
2186 if (!_network_server) return;
2187
2188 _network_company_states[c->index].months_empty = 0;
2189 _network_company_states[c->index].password[0] = '\0';
2190 NetworkServerUpdateCompanyPassworded(c->index, false);
2191
2192 if (ci != NULL) {
2193 /* ci is NULL when replaying, or for AIs. In neither case there is a client. */
2194 ci->client_playas = c->index;
2195 NetworkUpdateClientInfo(ci->client_id);
2196 NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, c->index);
2197 }
2198
2199 /* Announce new company on network. */
2200 NetworkAdminCompanyInfo(c, true);
2201
2202 if (ci != NULL) {
2203 /* ci is NULL when replaying, or for AIs. In neither case there is a client.
2204 We need to send Admin port update here so that they first know about the new company
2205 and then learn about a possibly joining client (see FS#6025) */
2206 NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
2207 }
2208 }
2209
2210 #endif /* ENABLE_NETWORK */