00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifdef ENABLE_NETWORK
00013
00014 #include "../stdafx.h"
00015 #include "../strings_func.h"
00016 #include "../date_func.h"
00017 #include "network_admin.h"
00018 #include "network_server.h"
00019 #include "network_udp.h"
00020 #include "network_base.h"
00021 #include "../console_func.h"
00022 #include "../company_base.h"
00023 #include "../command_func.h"
00024 #include "../saveload/saveload.h"
00025 #include "../saveload/saveload_filter.h"
00026 #include "../station_base.h"
00027 #include "../genworld.h"
00028 #include "../company_func.h"
00029 #include "../company_gui.h"
00030 #include "../window_func.h"
00031 #include "../roadveh.h"
00032 #include "../order_backup.h"
00033 #include "../core/pool_func.hpp"
00034 #include "../core/random_func.hpp"
00035 #include "../rev.h"
00036
00037
00038
00039
00040 DECLARE_POSTFIX_INCREMENT(ClientID)
00042 static ClientID _network_client_id = CLIENT_ID_FIRST;
00043
00045 assert_compile(MAX_CLIENT_SLOTS > MAX_CLIENTS);
00047 assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS);
00048
00050 NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket");
00051 INSTANTIATE_POOL_METHODS(NetworkClientSocket)
00052
00054 template SocketList TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED>::sockets;
00055
00057 struct PacketWriter : SaveFilter {
00058 ServerNetworkGameSocketHandler *cs;
00059 Packet *current;
00060 size_t total_size;
00061
00066 PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0)
00067 {
00068 this->cs->savegame_mutex = ThreadMutex::New();
00069 }
00070
00072 ~PacketWriter()
00073 {
00074
00075 if (this->cs != NULL) {
00076 if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->BeginCritical();
00077 this->cs->savegame = NULL;
00078 if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->EndCritical();
00079
00080 delete this->cs->savegame_mutex;
00081 this->cs->savegame_mutex = NULL;
00082 }
00083
00084 delete this->current;
00085 }
00086
00088 void AppendQueue()
00089 {
00090 if (this->current == NULL) return;
00091
00092 Packet **p = &this->cs->savegame_packets;
00093 while (*p != NULL) {
00094 p = &(*p)->next;
00095 }
00096 *p = this->current;
00097
00098 this->current = NULL;
00099 }
00100
00101 void Write(byte *buf, size_t size)
00102 {
00103
00104 if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
00105
00106 if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA);
00107
00108 if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->BeginCritical();
00109
00110 byte *bufe = buf + size;
00111 while (buf != bufe) {
00112 size_t to_write = min(SEND_MTU - this->current->size, bufe - buf);
00113 memcpy(this->current->buffer + this->current->size, buf, to_write);
00114 this->current->size += (PacketSize)to_write;
00115 buf += to_write;
00116
00117 if (this->current->size == SEND_MTU) {
00118 this->AppendQueue();
00119 if (buf != bufe) this->current = new Packet(PACKET_SERVER_MAP_DATA);
00120 }
00121 }
00122
00123 if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->EndCritical();
00124
00125 this->total_size += size;
00126 }
00127
00128 void Finish()
00129 {
00130
00131 if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
00132
00133 if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->BeginCritical();
00134
00135
00136 this->AppendQueue();
00137
00138
00139 this->current = new Packet(PACKET_SERVER_MAP_DONE);
00140 this->AppendQueue();
00141
00142
00143 Packet *p = new Packet(PACKET_SERVER_MAP_SIZE);
00144 p->Send_uint32((uint32)this->total_size);
00145 this->cs->NetworkTCPSocketHandler::SendPacket(p);
00146
00147 if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->EndCritical();
00148 }
00149 };
00150
00151
00156 ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s)
00157 {
00158 this->status = STATUS_INACTIVE;
00159 this->client_id = _network_client_id++;
00160 this->receive_limit = _settings_client.network.bytes_per_frame_burst;
00161
00162
00163
00164
00165 assert_compile(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE);
00166 }
00167
00171 ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler()
00172 {
00173 if (_redirect_console_to_client == this->client_id) _redirect_console_to_client = INVALID_CLIENT_ID;
00174 OrderBackup::ResetUser(this->client_id);
00175
00176 if (this->savegame_mutex != NULL) this->savegame_mutex->BeginCritical();
00177 if (this->savegame != NULL) this->savegame->cs = NULL;
00178 if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
00179
00180
00181
00182
00183
00184 WaitTillSaved();
00185 ProcessAsyncSaveFinish();
00186
00187 while (this->savegame_packets != NULL) {
00188 Packet *p = this->savegame_packets->next;
00189 delete this->savegame_packets;
00190 this->savegame_packets = p;
00191 }
00192
00193 delete this->savegame_mutex;
00194 }
00195
00196 Packet *ServerNetworkGameSocketHandler::ReceivePacket()
00197 {
00198
00199
00200 if (this->receive_limit <= 0) return NULL;
00201
00202
00203
00204 Packet *p = this->NetworkTCPSocketHandler::ReceivePacket();
00205 if (p != NULL) this->receive_limit -= p->size;
00206 return p;
00207 }
00208
00209 void ServerNetworkGameSocketHandler::SendPacket(Packet *packet)
00210 {
00211 if (this->savegame_mutex != NULL) this->savegame_mutex->BeginCritical();
00212 this->NetworkTCPSocketHandler::SendPacket(packet);
00213 if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
00214 }
00215
00216 NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
00217 {
00218 assert(status != NETWORK_RECV_STATUS_OKAY);
00219
00220
00221
00222
00223
00224
00225
00226 if (this->sock == INVALID_SOCKET) return status;
00227
00228 if (status != NETWORK_RECV_STATUS_CONN_LOST && !this->HasClientQuit() && this->status >= STATUS_AUTHORIZED) {
00229
00230 char client_name[NETWORK_CLIENT_NAME_LENGTH];
00231 NetworkClientSocket *new_cs;
00232
00233 this->GetClientName(client_name, sizeof(client_name));
00234
00235 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
00236
00237
00238 FOR_ALL_CLIENT_SOCKETS(new_cs) {
00239 if (new_cs->status > STATUS_AUTHORIZED && this != new_cs) {
00240 new_cs->SendErrorQuit(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
00241 }
00242 }
00243 }
00244
00245 NetworkAdminClientError(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
00246 DEBUG(net, 1, "Closed client connection %d", this->client_id);
00247
00248
00249 if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
00250 extern byte _network_clients_connected;
00251 _network_clients_connected--;
00252
00253 DeleteWindowById(WC_CLIENT_LIST_POPUP, this->client_id);
00254 SetWindowDirty(WC_CLIENT_LIST, 0);
00255
00256 this->SendPackets(true);
00257
00258 delete this->GetInfo();
00259 delete this;
00260
00261 return status;
00262 }
00263
00268 bool ServerNetworkGameSocketHandler::AllowConnection()
00269 {
00270 extern byte _network_clients_connected;
00271 bool accept = _network_clients_connected < MAX_CLIENTS && _network_game_info.clients_on < _settings_client.network.max_clients;
00272
00273
00274
00275 assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1);
00276 assert(!accept || ServerNetworkGameSocketHandler::CanAllocateItem());
00277 return accept;
00278 }
00279
00281 void ServerNetworkGameSocketHandler::Send()
00282 {
00283 NetworkClientSocket *cs;
00284 FOR_ALL_CLIENT_SOCKETS(cs) {
00285 if (cs->writable) {
00286 if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
00287
00288 cs->SendMap();
00289 }
00290 }
00291 }
00292 }
00293
00294 static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
00295
00296
00297
00298
00299
00300
00305 NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientInfo *ci)
00306 {
00307 if (ci->client_id != INVALID_CLIENT_ID) {
00308 Packet *p = new Packet(PACKET_SERVER_CLIENT_INFO);
00309 p->Send_uint32(ci->client_id);
00310 p->Send_uint8 (ci->client_playas);
00311 p->Send_string(ci->client_name);
00312
00313 this->SendPacket(p);
00314 }
00315 return NETWORK_RECV_STATUS_OKAY;
00316 }
00317
00319 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo()
00320 {
00321
00322 NetworkCompanyStats company_stats[MAX_COMPANIES];
00323 NetworkPopulateCompanyStats(company_stats);
00324
00325
00326 char clients[MAX_COMPANIES][NETWORK_CLIENTS_LENGTH];
00327 NetworkClientSocket *csi;
00328 memset(clients, 0, sizeof(clients));
00329
00330
00331 const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
00332 if (ci != NULL && Company::IsValidID(ci->client_playas)) {
00333 strecpy(clients[ci->client_playas], ci->client_name, lastof(clients[ci->client_playas]));
00334 }
00335
00336 FOR_ALL_CLIENT_SOCKETS(csi) {
00337 char client_name[NETWORK_CLIENT_NAME_LENGTH];
00338
00339 ((ServerNetworkGameSocketHandler*)csi)->GetClientName(client_name, sizeof(client_name));
00340
00341 ci = csi->GetInfo();
00342 if (ci != NULL && Company::IsValidID(ci->client_playas)) {
00343 if (!StrEmpty(clients[ci->client_playas])) {
00344 strecat(clients[ci->client_playas], ", ", lastof(clients[ci->client_playas]));
00345 }
00346
00347 strecat(clients[ci->client_playas], client_name, lastof(clients[ci->client_playas]));
00348 }
00349 }
00350
00351
00352
00353 Company *company;
00354 Packet *p;
00355
00356 FOR_ALL_COMPANIES(company) {
00357 p = new Packet(PACKET_SERVER_COMPANY_INFO);
00358
00359 p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
00360 p->Send_bool (true);
00361 this->SendCompanyInformation(p, company, &company_stats[company->index]);
00362
00363 if (StrEmpty(clients[company->index])) {
00364 p->Send_string("<none>");
00365 } else {
00366 p->Send_string(clients[company->index]);
00367 }
00368
00369 this->SendPacket(p);
00370 }
00371
00372 p = new Packet(PACKET_SERVER_COMPANY_INFO);
00373
00374 p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
00375 p->Send_bool (false);
00376
00377 this->SendPacket(p);
00378 return NETWORK_RECV_STATUS_OKAY;
00379 }
00380
00385 NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error)
00386 {
00387 char str[100];
00388 Packet *p = new Packet(PACKET_SERVER_ERROR);
00389
00390 p->Send_uint8(error);
00391 this->SendPacket(p);
00392
00393 StringID strid = GetNetworkErrorMsg(error);
00394 GetString(str, strid, lastof(str));
00395
00396
00397 if (this->status > STATUS_AUTHORIZED) {
00398 NetworkClientSocket *new_cs;
00399 char client_name[NETWORK_CLIENT_NAME_LENGTH];
00400
00401 this->GetClientName(client_name, sizeof(client_name));
00402
00403 DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
00404
00405 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid);
00406
00407 FOR_ALL_CLIENT_SOCKETS(new_cs) {
00408 if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
00409
00410
00411 if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) {
00412 error = NETWORK_ERROR_ILLEGAL_PACKET;
00413 }
00414 new_cs->SendErrorQuit(this->client_id, error);
00415 }
00416 }
00417
00418 NetworkAdminClientError(this->client_id, error);
00419 } else {
00420 DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", this->client_id, str);
00421 }
00422
00423
00424 return this->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
00425 }
00426
00428 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
00429 {
00430 Packet *p = new Packet(PACKET_SERVER_CHECK_NEWGRFS);
00431 const GRFConfig *c;
00432 uint grf_count = 0;
00433
00434 for (c = _grfconfig; c != NULL; c = c->next) {
00435 if (!HasBit(c->flags, GCF_STATIC)) grf_count++;
00436 }
00437
00438 p->Send_uint8 (grf_count);
00439 for (c = _grfconfig; c != NULL; c = c->next) {
00440 if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
00441 }
00442
00443 this->SendPacket(p);
00444 return NETWORK_RECV_STATUS_OKAY;
00445 }
00446
00448 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
00449 {
00450
00451 if (this->status >= STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
00452
00453 this->status = STATUS_AUTH_GAME;
00454
00455 Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
00456 this->SendPacket(p);
00457 return NETWORK_RECV_STATUS_OKAY;
00458 }
00459
00461 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
00462 {
00463
00464 if (this->status >= STATUS_AUTH_COMPANY) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
00465
00466 this->status = STATUS_AUTH_COMPANY;
00467
00468 Packet *p = new Packet(PACKET_SERVER_NEED_COMPANY_PASSWORD);
00469 p->Send_uint32(_settings_game.game_creation.generation_seed);
00470 p->Send_string(_settings_client.network.network_id);
00471 this->SendPacket(p);
00472 return NETWORK_RECV_STATUS_OKAY;
00473 }
00474
00476 NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
00477 {
00478 Packet *p;
00479 NetworkClientSocket *new_cs;
00480
00481
00482 if (this->status >= STATUS_AUTHORIZED) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
00483
00484 this->status = STATUS_AUTHORIZED;
00485 _network_game_info.clients_on++;
00486
00487 p = new Packet(PACKET_SERVER_WELCOME);
00488 p->Send_uint32(this->client_id);
00489 p->Send_uint32(_settings_game.game_creation.generation_seed);
00490 p->Send_string(_settings_client.network.network_id);
00491 this->SendPacket(p);
00492
00493
00494 FOR_ALL_CLIENT_SOCKETS(new_cs) {
00495 if (new_cs != this && new_cs->status > STATUS_AUTHORIZED) {
00496 this->SendClientInfo(new_cs->GetInfo());
00497 }
00498 }
00499
00500 return this->SendClientInfo(NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER));
00501 }
00502
00504 NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait()
00505 {
00506 int waiting = 0;
00507 NetworkClientSocket *new_cs;
00508 Packet *p;
00509
00510
00511 FOR_ALL_CLIENT_SOCKETS(new_cs) {
00512 if (new_cs->status != STATUS_MAP_WAIT) continue;
00513 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++;
00514 }
00515
00516 p = new Packet(PACKET_SERVER_WAIT);
00517 p->Send_uint8(waiting);
00518 this->SendPacket(p);
00519 return NETWORK_RECV_STATUS_OKAY;
00520 }
00521
00523 NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
00524 {
00525 static uint sent_packets;
00526
00527 if (this->status < STATUS_AUTHORIZED) {
00528
00529 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
00530 }
00531
00532 if (this->status == STATUS_AUTHORIZED) {
00533 this->savegame = new PacketWriter(this);
00534
00535
00536 Packet *p = new Packet(PACKET_SERVER_MAP_BEGIN);
00537 p->Send_uint32(_frame_counter);
00538 this->SendPacket(p);
00539
00540 NetworkSyncCommandQueue(this);
00541 this->status = STATUS_MAP;
00542
00543 this->last_frame = _frame_counter;
00544 this->last_frame_server = _frame_counter;
00545
00546 sent_packets = 4;
00547
00548
00549 if (SaveWithFilter(this->savegame, true) != SL_OK) usererror("network savedump failed");
00550 }
00551
00552 if (this->status == STATUS_MAP) {
00553 if (this->savegame_mutex != NULL) this->savegame_mutex->BeginCritical();
00554
00555 bool last_packet = false;
00556
00557 for (uint i = 0; i < sent_packets && this->savegame_packets != NULL; i++) {
00558 Packet *p = this->savegame_packets;
00559 last_packet = p->buffer[2] == PACKET_SERVER_MAP_DONE;
00560
00561
00562 this->savegame_packets = p->next;
00563 p->next = NULL;
00564 this->NetworkTCPSocketHandler::SendPacket(p);
00565
00566 if (last_packet) {
00567
00568 break;
00569 }
00570 }
00571
00572 if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
00573
00574 if (last_packet) {
00575
00576 WaitTillSaved();
00577
00578
00579
00580 this->status = STATUS_DONE_MAP;
00581
00582
00583 NetworkClientSocket *new_cs;
00584 NetworkClientSocket *best = NULL;
00585 FOR_ALL_CLIENT_SOCKETS(new_cs) {
00586 if (new_cs->status == STATUS_MAP_WAIT) {
00587 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)) {
00588 best = new_cs;
00589 }
00590 }
00591 }
00592
00593
00594 if (best != NULL) {
00595
00596 best->status = STATUS_AUTHORIZED;
00597 best->SendMap();
00598
00599
00600 FOR_ALL_CLIENT_SOCKETS(new_cs) {
00601 if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait();
00602 }
00603 }
00604 }
00605
00606 switch (this->SendPackets()) {
00607 case SPS_CLOSED:
00608 return NETWORK_RECV_STATUS_CONN_LOST;
00609
00610 case SPS_ALL_SENT:
00611
00612 if (this->savegame_packets != NULL) sent_packets *= 2;
00613 break;
00614
00615 case SPS_PARTLY_SENT:
00616
00617 break;
00618
00619 case SPS_NONE_SENT:
00620
00621 if (sent_packets > 1) sent_packets /= 2;
00622 break;
00623 }
00624 }
00625 return NETWORK_RECV_STATUS_OKAY;
00626 }
00627
00632 NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
00633 {
00634 Packet *p = new Packet(PACKET_SERVER_JOIN);
00635
00636 p->Send_uint32(client_id);
00637
00638 this->SendPacket(p);
00639 return NETWORK_RECV_STATUS_OKAY;
00640 }
00641
00643 NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
00644 {
00645 Packet *p = new Packet(PACKET_SERVER_FRAME);
00646 p->Send_uint32(_frame_counter);
00647 p->Send_uint32(_frame_counter_max);
00648 #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
00649 p->Send_uint32(_sync_seed_1);
00650 #ifdef NETWORK_SEND_DOUBLE_SEED
00651 p->Send_uint32(_sync_seed_2);
00652 #endif
00653 #endif
00654
00655
00656 if (this->last_token == 0) {
00657 this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1;
00658 p->Send_uint8(this->last_token);
00659 }
00660
00661 this->SendPacket(p);
00662 return NETWORK_RECV_STATUS_OKAY;
00663 }
00664
00666 NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
00667 {
00668 Packet *p = new Packet(PACKET_SERVER_SYNC);
00669 p->Send_uint32(_frame_counter);
00670 p->Send_uint32(_sync_seed_1);
00671
00672 #ifdef NETWORK_SEND_DOUBLE_SEED
00673 p->Send_uint32(_sync_seed_2);
00674 #endif
00675 this->SendPacket(p);
00676 return NETWORK_RECV_STATUS_OKAY;
00677 }
00678
00683 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCommand(const CommandPacket *cp)
00684 {
00685 Packet *p = new Packet(PACKET_SERVER_COMMAND);
00686
00687 this->NetworkGameSocketHandler::SendCommand(p, cp);
00688 p->Send_uint32(cp->frame);
00689 p->Send_bool (cp->my_cmd);
00690
00691 this->SendPacket(p);
00692 return NETWORK_RECV_STATUS_OKAY;
00693 }
00694
00703 NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, int64 data)
00704 {
00705 if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_OKAY;
00706
00707 Packet *p = new Packet(PACKET_SERVER_CHAT);
00708
00709 p->Send_uint8 (action);
00710 p->Send_uint32(client_id);
00711 p->Send_bool (self_send);
00712 p->Send_string(msg);
00713 p->Send_uint64(data);
00714
00715 this->SendPacket(p);
00716 return NETWORK_RECV_STATUS_OKAY;
00717 }
00718
00724 NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
00725 {
00726 Packet *p = new Packet(PACKET_SERVER_ERROR_QUIT);
00727
00728 p->Send_uint32(client_id);
00729 p->Send_uint8 (errorno);
00730
00731 this->SendPacket(p);
00732 return NETWORK_RECV_STATUS_OKAY;
00733 }
00734
00739 NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
00740 {
00741 Packet *p = new Packet(PACKET_SERVER_QUIT);
00742
00743 p->Send_uint32(client_id);
00744
00745 this->SendPacket(p);
00746 return NETWORK_RECV_STATUS_OKAY;
00747 }
00748
00750 NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
00751 {
00752 Packet *p = new Packet(PACKET_SERVER_SHUTDOWN);
00753 this->SendPacket(p);
00754 return NETWORK_RECV_STATUS_OKAY;
00755 }
00756
00758 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame()
00759 {
00760 Packet *p = new Packet(PACKET_SERVER_NEWGAME);
00761 this->SendPacket(p);
00762 return NETWORK_RECV_STATUS_OKAY;
00763 }
00764
00770 NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16 colour, const char *command)
00771 {
00772 Packet *p = new Packet(PACKET_SERVER_RCON);
00773
00774 p->Send_uint16(colour);
00775 p->Send_string(command);
00776 this->SendPacket(p);
00777 return NETWORK_RECV_STATUS_OKAY;
00778 }
00779
00785 NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, CompanyID company_id)
00786 {
00787 Packet *p = new Packet(PACKET_SERVER_MOVE);
00788
00789 p->Send_uint32(client_id);
00790 p->Send_uint8(company_id);
00791 this->SendPacket(p);
00792 return NETWORK_RECV_STATUS_OKAY;
00793 }
00794
00796 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
00797 {
00798 Packet *p = new Packet(PACKET_SERVER_COMPANY_UPDATE);
00799
00800 p->Send_uint16(_network_company_passworded);
00801 this->SendPacket(p);
00802 return NETWORK_RECV_STATUS_OKAY;
00803 }
00804
00806 NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
00807 {
00808 Packet *p = new Packet(PACKET_SERVER_CONFIG_UPDATE);
00809
00810 p->Send_uint8(_settings_client.network.max_companies);
00811 p->Send_uint8(_settings_client.network.max_spectators);
00812 this->SendPacket(p);
00813 return NETWORK_RECV_STATUS_OKAY;
00814 }
00815
00816
00817
00818
00819
00820
00821 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_INFO(Packet *p)
00822 {
00823 return this->SendCompanyInfo();
00824 }
00825
00826 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet *p)
00827 {
00828 if (this->status != STATUS_NEWGRFS_CHECK) {
00829
00830 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00831 }
00832
00833 NetworkClientInfo *ci = this->GetInfo();
00834
00835
00836 if (!StrEmpty(_settings_client.network.server_password)) {
00837 return this->SendNeedGamePassword();
00838 }
00839
00840 if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
00841 return this->SendNeedCompanyPassword();
00842 }
00843
00844 return this->SendWelcome();
00845 }
00846
00847 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p)
00848 {
00849 if (this->status != STATUS_INACTIVE) {
00850
00851 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00852 }
00853
00854 char name[NETWORK_CLIENT_NAME_LENGTH];
00855 CompanyID playas;
00856 NetworkLanguage client_lang;
00857 char client_revision[NETWORK_REVISION_LENGTH];
00858
00859 p->Recv_string(client_revision, sizeof(client_revision));
00860
00861
00862 if (!IsNetworkCompatibleVersion(client_revision)) {
00863
00864 return this->SendError(NETWORK_ERROR_WRONG_REVISION);
00865 }
00866
00867 p->Recv_string(name, sizeof(name));
00868 playas = (Owner)p->Recv_uint8();
00869 client_lang = (NetworkLanguage)p->Recv_uint8();
00870
00871 if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
00872
00873
00874 switch (playas) {
00875 case COMPANY_NEW_COMPANY:
00876 if (Company::GetNumItems() >= _settings_client.network.max_companies) {
00877 return this->SendError(NETWORK_ERROR_FULL);
00878 }
00879 break;
00880 case COMPANY_SPECTATOR:
00881 if (NetworkSpectatorCount() >= _settings_client.network.max_spectators) {
00882 return this->SendError(NETWORK_ERROR_FULL);
00883 }
00884 break;
00885 default:
00886 if (!Company::IsValidHumanID(playas)) {
00887 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
00888 }
00889 break;
00890 }
00891
00892
00893 if (StrEmpty(name)) strecpy(name, "Player", lastof(name));
00894
00895 if (!NetworkFindName(name)) {
00896
00897 return this->SendError(NETWORK_ERROR_NAME_IN_USE);
00898 }
00899
00900 assert(NetworkClientInfo::CanAllocateItem());
00901 NetworkClientInfo *ci = new NetworkClientInfo(this->client_id);
00902 this->SetInfo(ci);
00903 ci->join_date = _date;
00904 strecpy(ci->client_name, name, lastof(ci->client_name));
00905 ci->client_playas = playas;
00906 ci->client_lang = client_lang;
00907 DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, ci->index);
00908
00909
00910 if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0;
00911
00912 this->status = STATUS_NEWGRFS_CHECK;
00913
00914 if (_grfconfig == NULL) {
00915
00916 return this->Receive_CLIENT_NEWGRFS_CHECKED(NULL);
00917 }
00918
00919 return this->SendNewGRFCheck();
00920 }
00921
00922 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p)
00923 {
00924 if (this->status != STATUS_AUTH_GAME) {
00925 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00926 }
00927
00928 char password[NETWORK_PASSWORD_LENGTH];
00929 p->Recv_string(password, sizeof(password));
00930
00931
00932 if (!StrEmpty(_settings_client.network.server_password) &&
00933 strcmp(password, _settings_client.network.server_password) != 0) {
00934
00935 return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
00936 }
00937
00938 const NetworkClientInfo *ci = this->GetInfo();
00939 if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
00940 return this->SendNeedCompanyPassword();
00941 }
00942
00943
00944 return this->SendWelcome();
00945 }
00946
00947 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p)
00948 {
00949 if (this->status != STATUS_AUTH_COMPANY) {
00950 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00951 }
00952
00953 char password[NETWORK_PASSWORD_LENGTH];
00954 p->Recv_string(password, sizeof(password));
00955
00956
00957
00958
00959 CompanyID playas = this->GetInfo()->client_playas;
00960 if (Company::IsValidID(playas) && !StrEmpty(_network_company_states[playas].password) &&
00961 strcmp(password, _network_company_states[playas].password) != 0) {
00962
00963 return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
00964 }
00965
00966 return this->SendWelcome();
00967 }
00968
00969 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p)
00970 {
00971 NetworkClientSocket *new_cs;
00972
00973
00974
00975
00976
00977
00978
00979
00980 if (IsReleasedVersion()) {
00981 if (_openttd_newgrf_version != p->Recv_uint32()) {
00982
00983
00984 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00985 }
00986 } else if (p->size != 3) {
00987
00988
00989 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00990 }
00991
00992
00993
00994 if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) {
00995 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
00996 }
00997
00998
00999 FOR_ALL_CLIENT_SOCKETS(new_cs) {
01000 if (new_cs->status == STATUS_MAP) {
01001
01002 this->status = STATUS_MAP_WAIT;
01003 return this->SendWait();
01004 }
01005 }
01006
01007
01008 return this->SendMap();
01009 }
01010
01011 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *p)
01012 {
01013
01014 if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
01015 char client_name[NETWORK_CLIENT_NAME_LENGTH];
01016 NetworkClientSocket *new_cs;
01017
01018 this->GetClientName(client_name, sizeof(client_name));
01019
01020 NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, NULL, this->client_id);
01021
01022
01023
01024 this->status = STATUS_PRE_ACTIVE;
01025 NetworkHandleCommandQueue(this);
01026 this->SendFrame();
01027 this->SendSync();
01028
01029
01030
01031 this->last_frame = _frame_counter;
01032 this->last_frame_server = _frame_counter;
01033
01034 FOR_ALL_CLIENT_SOCKETS(new_cs) {
01035 if (new_cs->status > STATUS_AUTHORIZED) {
01036 new_cs->SendClientInfo(this->GetInfo());
01037 new_cs->SendJoin(this->client_id);
01038 }
01039 }
01040
01041 NetworkAdminClientInfo(this, true);
01042
01043
01044 this->SendConfigUpdate();
01045
01046
01047 return this->SendCompanyUpdate();
01048 }
01049
01050
01051 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01052 }
01053
01058 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet *p)
01059 {
01060
01061
01062 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01063 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01064 }
01065
01066 if (this->incoming_queue.Count() >= _settings_client.network.max_commands_in_queue) {
01067 return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
01068 }
01069
01070 CommandPacket cp;
01071 const char *err = this->ReceiveCommand(p, &cp);
01072
01073 if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
01074
01075 NetworkClientInfo *ci = this->GetInfo();
01076
01077 if (err != NULL) {
01078 IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, this->GetClientIP());
01079 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01080 }
01081
01082
01083 if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER) {
01084 IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
01085 return this->SendError(NETWORK_ERROR_KICKED);
01086 }
01087
01088 if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) {
01089 IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
01090 return this->SendError(NETWORK_ERROR_KICKED);
01091 }
01092
01098 if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
01099 IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
01100 ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
01101 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
01102 }
01103
01104 if (cp.cmd == CMD_COMPANY_CTRL) {
01105 if (cp.p1 != 0 || cp.company != COMPANY_SPECTATOR) {
01106 return this->SendError(NETWORK_ERROR_CHEATER);
01107 }
01108
01109
01110 if (Company::GetNumItems() >= _settings_client.network.max_companies) {
01111 NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
01112 return NETWORK_RECV_STATUS_OKAY;
01113 }
01114 }
01115
01116 if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) cp.p2 = this->client_id;
01117
01118 this->incoming_queue.Append(&cp);
01119 return NETWORK_RECV_STATUS_OKAY;
01120 }
01121
01122 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p)
01123 {
01124
01125
01126 NetworkClientSocket *new_cs;
01127 char str[100];
01128 char client_name[NETWORK_CLIENT_NAME_LENGTH];
01129 NetworkErrorCode errorno = (NetworkErrorCode)p->Recv_uint8();
01130
01131
01132 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01133 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01134 }
01135
01136 this->GetClientName(client_name, sizeof(client_name));
01137
01138 StringID strid = GetNetworkErrorMsg(errorno);
01139 GetString(str, strid, lastof(str));
01140
01141 DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
01142
01143 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid);
01144
01145 FOR_ALL_CLIENT_SOCKETS(new_cs) {
01146 if (new_cs->status > STATUS_AUTHORIZED) {
01147 new_cs->SendErrorQuit(this->client_id, errorno);
01148 }
01149 }
01150
01151 NetworkAdminClientError(this->client_id, errorno);
01152
01153 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01154 }
01155
01156 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p)
01157 {
01158
01159
01160 NetworkClientSocket *new_cs;
01161 char client_name[NETWORK_CLIENT_NAME_LENGTH];
01162
01163
01164 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01165 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01166 }
01167
01168 this->GetClientName(client_name, sizeof(client_name));
01169
01170 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING);
01171
01172 FOR_ALL_CLIENT_SOCKETS(new_cs) {
01173 if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
01174 new_cs->SendQuit(this->client_id);
01175 }
01176 }
01177
01178 NetworkAdminClientQuit(this->client_id);
01179
01180 return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01181 }
01182
01183 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p)
01184 {
01185 if (this->status < STATUS_AUTHORIZED) {
01186
01187 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
01188 }
01189
01190 uint32 frame = p->Recv_uint32();
01191
01192
01193 if (this->status == STATUS_PRE_ACTIVE) {
01194
01195 if (frame + DAY_TICKS < _frame_counter) return NETWORK_RECV_STATUS_OKAY;
01196
01197
01198 this->status = STATUS_ACTIVE;
01199 this->last_token_frame = _frame_counter;
01200
01201
01202 IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
01203 }
01204
01205
01206 uint8 token = p->Recv_uint8();
01207 if (token == this->last_token) {
01208
01209
01210
01211
01212
01213
01214
01215
01216 this->last_token_frame = _frame_counter;
01217
01218 this->last_token = 0;
01219 }
01220
01221
01222 this->last_frame = frame;
01223
01224 this->last_frame_server = _frame_counter;
01225 return NETWORK_RECV_STATUS_OKAY;
01226 }
01227
01228
01239 void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, ClientID from_id, int64 data, bool from_admin)
01240 {
01241 NetworkClientSocket *cs;
01242 const NetworkClientInfo *ci, *ci_own, *ci_to;
01243
01244 switch (desttype) {
01245 case DESTTYPE_CLIENT:
01246
01247 if ((ClientID)dest == CLIENT_ID_SERVER) {
01248 ci = NetworkClientInfo::GetByClientID(from_id);
01249
01250 if (ci != NULL) {
01251 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01252
01253 if (_settings_client.network.server_admin_chat) {
01254 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01255 }
01256 }
01257 } else {
01258
01259 FOR_ALL_CLIENT_SOCKETS(cs) {
01260 if (cs->client_id == (ClientID)dest) {
01261 cs->SendChat(action, from_id, false, msg, data);
01262 break;
01263 }
01264 }
01265 }
01266
01267
01268 if (from_id != (ClientID)dest) {
01269 if (from_id == CLIENT_ID_SERVER) {
01270 ci = NetworkClientInfo::GetByClientID(from_id);
01271 ci_to = NetworkClientInfo::GetByClientID((ClientID)dest);
01272 if (ci != NULL && ci_to != NULL) {
01273 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
01274 }
01275 } else {
01276 FOR_ALL_CLIENT_SOCKETS(cs) {
01277 if (cs->client_id == from_id) {
01278 cs->SendChat(action, (ClientID)dest, true, msg, data);
01279 break;
01280 }
01281 }
01282 }
01283 }
01284 break;
01285 case DESTTYPE_TEAM: {
01286
01287 bool show_local = true;
01288
01289 ci_to = NULL;
01290 FOR_ALL_CLIENT_SOCKETS(cs) {
01291 ci = cs->GetInfo();
01292 if (ci != NULL && ci->client_playas == (CompanyID)dest) {
01293 cs->SendChat(action, from_id, false, msg, data);
01294 if (cs->client_id == from_id) show_local = false;
01295 ci_to = ci;
01296 }
01297 }
01298
01299
01300 if (_local_company == (CompanyID)dest && _settings_client.network.server_admin_chat) {
01301 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01302 }
01303
01304 ci = NetworkClientInfo::GetByClientID(from_id);
01305 ci_own = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
01306 if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
01307 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01308 if (from_id == CLIENT_ID_SERVER) show_local = false;
01309 ci_to = ci_own;
01310 }
01311
01312
01313 if (ci_to == NULL) break;
01314
01315
01316 if (ci != NULL && show_local) {
01317 if (from_id == CLIENT_ID_SERVER) {
01318 char name[NETWORK_NAME_LENGTH];
01319 StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
01320 SetDParam(0, ci_to->client_playas);
01321 GetString(name, str, lastof(name));
01322 NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
01323 } else {
01324 FOR_ALL_CLIENT_SOCKETS(cs) {
01325 if (cs->client_id == from_id) {
01326 cs->SendChat(action, ci_to->client_id, true, msg, data);
01327 }
01328 }
01329 }
01330 }
01331 break;
01332 }
01333 default:
01334 DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
01335
01336 case DESTTYPE_BROADCAST:
01337 FOR_ALL_CLIENT_SOCKETS(cs) {
01338 cs->SendChat(action, from_id, false, msg, data);
01339 }
01340
01341 NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01342
01343 ci = NetworkClientInfo::GetByClientID(from_id);
01344 if (ci != NULL) {
01345 NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01346 }
01347 break;
01348 }
01349 }
01350
01351 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p)
01352 {
01353 if (this->status < STATUS_AUTHORIZED) {
01354
01355 return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
01356 }
01357
01358 NetworkAction action = (NetworkAction)p->Recv_uint8();
01359 DestType desttype = (DestType)p->Recv_uint8();
01360 int dest = p->Recv_uint32();
01361 char msg[NETWORK_CHAT_LENGTH];
01362
01363 p->Recv_string(msg, NETWORK_CHAT_LENGTH);
01364 int64 data = p->Recv_uint64();
01365
01366 NetworkClientInfo *ci = this->GetInfo();
01367 switch (action) {
01368 case NETWORK_ACTION_GIVE_MONEY:
01369 if (!Company::IsValidID(ci->client_playas)) break;
01370
01371 case NETWORK_ACTION_CHAT:
01372 case NETWORK_ACTION_CHAT_CLIENT:
01373 case NETWORK_ACTION_CHAT_COMPANY:
01374 NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
01375 break;
01376 default:
01377 IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, this->GetClientIP());
01378 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01379 }
01380 return NETWORK_RECV_STATUS_OKAY;
01381 }
01382
01383 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet *p)
01384 {
01385 if (this->status != STATUS_ACTIVE) {
01386
01387 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01388 }
01389
01390 char password[NETWORK_PASSWORD_LENGTH];
01391 const NetworkClientInfo *ci;
01392
01393 p->Recv_string(password, sizeof(password));
01394 ci = this->GetInfo();
01395
01396 NetworkServerSetCompanyPassword(ci->client_playas, password);
01397 return NETWORK_RECV_STATUS_OKAY;
01398 }
01399
01400 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p)
01401 {
01402 if (this->status != STATUS_ACTIVE) {
01403
01404 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01405 }
01406
01407 char client_name[NETWORK_CLIENT_NAME_LENGTH];
01408 NetworkClientInfo *ci;
01409
01410 p->Recv_string(client_name, sizeof(client_name));
01411 ci = this->GetInfo();
01412
01413 if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
01414
01415 if (ci != NULL) {
01416
01417 if (NetworkFindName(client_name)) {
01418 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);
01419 strecpy(ci->client_name, client_name, lastof(ci->client_name));
01420 NetworkUpdateClientInfo(ci->client_id);
01421 }
01422 }
01423 return NETWORK_RECV_STATUS_OKAY;
01424 }
01425
01426 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
01427 {
01428 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01429
01430 char pass[NETWORK_PASSWORD_LENGTH];
01431 char command[NETWORK_RCONCOMMAND_LENGTH];
01432
01433 if (StrEmpty(_settings_client.network.rcon_password)) return NETWORK_RECV_STATUS_OKAY;
01434
01435 p->Recv_string(pass, sizeof(pass));
01436 p->Recv_string(command, sizeof(command));
01437
01438 if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
01439 DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
01440 return NETWORK_RECV_STATUS_OKAY;
01441 }
01442
01443 DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", this->client_id, command);
01444
01445 _redirect_console_to_client = this->client_id;
01446 IConsoleCmdExec(command);
01447 _redirect_console_to_client = INVALID_CLIENT_ID;
01448 return NETWORK_RECV_STATUS_OKAY;
01449 }
01450
01451 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p)
01452 {
01453 if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01454
01455 CompanyID company_id = (Owner)p->Recv_uint8();
01456
01457
01458 if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
01459
01460
01461 if (company_id != COMPANY_SPECTATOR && !StrEmpty(_network_company_states[company_id].password)) {
01462
01463 char password[NETWORK_PASSWORD_LENGTH];
01464 p->Recv_string(password, sizeof(password));
01465
01466
01467 if (strcmp(password, _network_company_states[company_id].password) != 0) {
01468 DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", this->client_id, company_id + 1);
01469 return NETWORK_RECV_STATUS_OKAY;
01470 }
01471 }
01472
01473
01474 NetworkServerDoMove(this->client_id, company_id);
01475 return NETWORK_RECV_STATUS_OKAY;
01476 }
01477
01485 void NetworkSocketHandler::SendCompanyInformation(Packet *p, const Company *c, const NetworkCompanyStats *stats, uint max_len)
01486 {
01487
01488 char company_name[NETWORK_COMPANY_NAME_LENGTH];
01489 SetDParam(0, c->index);
01490
01491 assert(max_len <= lengthof(company_name));
01492 GetString(company_name, STR_COMPANY_NAME, company_name + max_len - 1);
01493
01494
01495 Money income = 0;
01496 if (_cur_year - 1 == c->inaugurated_year) {
01497
01498 for (uint i = 0; i < lengthof(c->yearly_expenses[2]); i++) {
01499 income -= c->yearly_expenses[2][i];
01500 }
01501 } else {
01502 for (uint i = 0; i < lengthof(c->yearly_expenses[1]); i++) {
01503 income -= c->yearly_expenses[1][i];
01504 }
01505 }
01506
01507
01508 p->Send_uint8 (c->index);
01509 p->Send_string(company_name);
01510 p->Send_uint32(c->inaugurated_year);
01511 p->Send_uint64(c->old_economy[0].company_value);
01512 p->Send_uint64(c->money);
01513 p->Send_uint64(income);
01514 p->Send_uint16(c->old_economy[0].performance_history);
01515
01516
01517 p->Send_bool (!StrEmpty(_network_company_states[c->index].password));
01518
01519 for (uint i = 0; i < NETWORK_VEH_END; i++) {
01520 p->Send_uint16(stats->num_vehicle[i]);
01521 }
01522
01523 for (uint i = 0; i < NETWORK_VEH_END; i++) {
01524 p->Send_uint16(stats->num_station[i]);
01525 }
01526
01527 p->Send_bool(c->is_ai);
01528 }
01529
01534 void NetworkPopulateCompanyStats(NetworkCompanyStats *stats)
01535 {
01536 const Vehicle *v;
01537 const Station *s;
01538
01539 memset(stats, 0, sizeof(*stats) * MAX_COMPANIES);
01540
01541
01542 FOR_ALL_VEHICLES(v) {
01543 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
01544 byte type = 0;
01545 switch (v->type) {
01546 case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
01547 case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
01548 case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break;
01549 case VEH_SHIP: type = NETWORK_VEH_SHIP; break;
01550 default: continue;
01551 }
01552 stats[v->owner].num_vehicle[type]++;
01553 }
01554
01555
01556 FOR_ALL_STATIONS(s) {
01557 if (Company::IsValidID(s->owner)) {
01558 NetworkCompanyStats *npi = &stats[s->owner];
01559
01560 if (s->facilities & FACIL_TRAIN) npi->num_station[NETWORK_VEH_TRAIN]++;
01561 if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[NETWORK_VEH_LORRY]++;
01562 if (s->facilities & FACIL_BUS_STOP) npi->num_station[NETWORK_VEH_BUS]++;
01563 if (s->facilities & FACIL_AIRPORT) npi->num_station[NETWORK_VEH_PLANE]++;
01564 if (s->facilities & FACIL_DOCK) npi->num_station[NETWORK_VEH_SHIP]++;
01565 }
01566 }
01567 }
01568
01573 void NetworkUpdateClientInfo(ClientID client_id)
01574 {
01575 NetworkClientSocket *cs;
01576 NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
01577
01578 if (ci == NULL) return;
01579
01580 DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id);
01581
01582 FOR_ALL_CLIENT_SOCKETS(cs) {
01583 cs->SendClientInfo(ci);
01584 }
01585
01586 NetworkAdminClientUpdate(ci);
01587 }
01588
01590 static void NetworkCheckRestartMap()
01591 {
01592 if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) {
01593 DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year);
01594
01595 StartNewGameWithoutGUI(GENERATE_NEW_SEED);
01596 }
01597 }
01598
01605 static void NetworkAutoCleanCompanies()
01606 {
01607 const NetworkClientInfo *ci;
01608 const Company *c;
01609 bool clients_in_company[MAX_COMPANIES];
01610 int vehicles_in_company[MAX_COMPANIES];
01611
01612 if (!_settings_client.network.autoclean_companies) return;
01613
01614 memset(clients_in_company, 0, sizeof(clients_in_company));
01615
01616
01617 FOR_ALL_CLIENT_INFOS(ci) {
01618 if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
01619 }
01620
01621 if (!_network_dedicated) {
01622 ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
01623 if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
01624 }
01625
01626 if (_settings_client.network.autoclean_novehicles != 0) {
01627 memset(vehicles_in_company, 0, sizeof(vehicles_in_company));
01628
01629 const Vehicle *v;
01630 FOR_ALL_VEHICLES(v) {
01631 if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
01632 vehicles_in_company[v->owner]++;
01633 }
01634 }
01635
01636
01637 FOR_ALL_COMPANIES(c) {
01638
01639 if (c->is_ai) continue;
01640
01641 if (!clients_in_company[c->index]) {
01642
01643 _network_company_states[c->index].months_empty++;
01644
01645
01646 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)) {
01647
01648 DoCommandP(0, 2 | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL);
01649 IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1);
01650 }
01651
01652 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)) {
01653
01654 _network_company_states[c->index].password[0] = '\0';
01655 IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", c->index + 1);
01656 _network_company_states[c->index].months_empty = 0;
01657 NetworkServerUpdateCompanyPassworded(c->index, false);
01658 }
01659
01660 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) {
01661
01662 DoCommandP(0, 2 | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL);
01663 IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1);
01664 }
01665 } else {
01666
01667 _network_company_states[c->index].months_empty = 0;
01668 }
01669 }
01670 }
01671
01677 bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH])
01678 {
01679 bool found_name = false;
01680 uint number = 0;
01681 char original_name[NETWORK_CLIENT_NAME_LENGTH];
01682
01683
01684 ttd_strlcpy(original_name, new_name, NETWORK_CLIENT_NAME_LENGTH);
01685
01686 while (!found_name) {
01687 const NetworkClientInfo *ci;
01688
01689 found_name = true;
01690 FOR_ALL_CLIENT_INFOS(ci) {
01691 if (strcmp(ci->client_name, new_name) == 0) {
01692
01693 found_name = false;
01694 break;
01695 }
01696 }
01697
01698 ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
01699 if (ci != NULL) {
01700 if (strcmp(ci->client_name, new_name) == 0) found_name = false;
01701 }
01702
01703 if (!found_name) {
01704
01705
01706
01707 if (number++ > MAX_CLIENTS) break;
01708 snprintf(new_name, NETWORK_CLIENT_NAME_LENGTH, "%s #%d", original_name, number);
01709 }
01710 }
01711
01712 return found_name;
01713 }
01714
01721 bool NetworkServerChangeClientName(ClientID client_id, const char *new_name)
01722 {
01723 NetworkClientInfo *ci;
01724
01725 FOR_ALL_CLIENT_INFOS(ci) {
01726 if (strcmp(ci->client_name, new_name) == 0) return false;
01727 }
01728
01729 ci = NetworkClientInfo::GetByClientID(client_id);
01730 if (ci == NULL) return false;
01731
01732 NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name);
01733
01734 strecpy(ci->client_name, new_name, lastof(ci->client_name));
01735
01736 NetworkUpdateClientInfo(client_id);
01737 return true;
01738 }
01739
01746 void NetworkServerSetCompanyPassword(CompanyID company_id, const char *password, bool already_hashed)
01747 {
01748 if (!Company::IsValidHumanID(company_id)) return;
01749
01750 if (!already_hashed) {
01751 password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed);
01752 }
01753
01754 strecpy(_network_company_states[company_id].password, password, lastof(_network_company_states[company_id].password));
01755 NetworkServerUpdateCompanyPassworded(company_id, !StrEmpty(_network_company_states[company_id].password));
01756 }
01757
01762 static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
01763 {
01764 CommandPacket *cp;
01765 while ((cp = cs->outgoing_queue.Pop()) != NULL) {
01766 cs->SendCommand(cp);
01767 free(cp);
01768 }
01769 }
01770
01775 void NetworkServer_Tick(bool send_frame)
01776 {
01777 NetworkClientSocket *cs;
01778 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
01779 bool send_sync = false;
01780 #endif
01781
01782 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
01783 if (_frame_counter >= _last_sync_frame + _settings_client.network.sync_freq) {
01784 _last_sync_frame = _frame_counter;
01785 send_sync = true;
01786 }
01787 #endif
01788
01789
01790
01791 FOR_ALL_CLIENT_SOCKETS(cs) {
01792
01793
01794 cs->receive_limit = min(cs->receive_limit + _settings_client.network.bytes_per_frame,
01795 _settings_client.network.bytes_per_frame_burst);
01796
01797
01798 if (cs->status == NetworkClientSocket::STATUS_ACTIVE) {
01799
01800 uint lag = NetworkCalculateLag(cs) / DAY_TICKS;
01801 if (lag > 0) {
01802 if (lag > 3) {
01803
01804
01805 IConsolePrintF(CC_ERROR, cs->last_packet + 3 * DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick ?
01806
01807 "Client #%d is dropped because the client's game state is more than 4 game-days behind" :
01808
01809 "Client #%d is dropped because the client did not respond for more than 4 game-days",
01810 cs->client_id);
01811 cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01812 continue;
01813 }
01814
01815
01816
01817
01818
01819
01820 if (cs->lag_test == 0 && cs->last_packet + DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick) {
01821 IConsolePrintF(CC_WARNING,"[%d] Client #%d is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
01822 cs->lag_test = 1;
01823 }
01824 } else {
01825 cs->lag_test = 0;
01826 }
01827 if (cs->last_frame_server - cs->last_token_frame >= 5 * DAY_TICKS) {
01828
01829 IConsolePrintF(CC_ERROR, "Client #%d is dropped because it fails to send valid acks", cs->client_id);
01830 cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01831 continue;
01832 }
01833 } else if (cs->status == NetworkClientSocket::STATUS_PRE_ACTIVE) {
01834 uint lag = NetworkCalculateLag(cs);
01835 if (lag > _settings_client.network.max_join_time) {
01836 IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->client_id, _settings_client.network.max_join_time);
01837 cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01838 continue;
01839 }
01840 } else if (cs->status == NetworkClientSocket::STATUS_INACTIVE) {
01841 uint lag = NetworkCalculateLag(cs);
01842 if (lag > 4 * DAY_TICKS) {
01843 IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->client_id, 4 * DAY_TICKS);
01844 cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01845 continue;
01846 }
01847 }
01848
01849 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
01850
01851 NetworkHandleCommandQueue(cs);
01852
01853
01854 if (send_frame) cs->SendFrame();
01855
01856 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
01857
01858 if (send_sync) cs->SendSync();
01859 #endif
01860 }
01861 }
01862
01863
01864 NetworkUDPAdvertise();
01865 }
01866
01868 void NetworkServerYearlyLoop()
01869 {
01870 NetworkCheckRestartMap();
01871 NetworkAdminUpdate(ADMIN_FREQUENCY_ANUALLY);
01872 }
01873
01875 void NetworkServerMonthlyLoop()
01876 {
01877 NetworkAutoCleanCompanies();
01878 NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY);
01879 if ((_cur_month % 3) == 0) NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY);
01880 }
01881
01883 void NetworkServerDailyLoop()
01884 {
01885 NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY);
01886 if ((_date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);
01887 }
01888
01893 const char *ServerNetworkGameSocketHandler::GetClientIP()
01894 {
01895 return this->client_address.GetHostname();
01896 }
01897
01899 void NetworkServerShowStatusToConsole()
01900 {
01901 static const char * const stat_str[] = {
01902 "inactive",
01903 "checking NewGRFs",
01904 "authorizing (server password)",
01905 "authorizing (company password)",
01906 "authorized",
01907 "waiting",
01908 "loading map",
01909 "map done",
01910 "ready",
01911 "active"
01912 };
01913 assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
01914
01915 NetworkClientSocket *cs;
01916 FOR_ALL_CLIENT_SOCKETS(cs) {
01917 NetworkClientInfo *ci = cs->GetInfo();
01918 if (ci == NULL) continue;
01919 uint lag = NetworkCalculateLag(cs);
01920 const char *status;
01921
01922 status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
01923 IConsolePrintF(CC_INFO, "Client #%1d name: '%s' status: '%s' frame-lag: %3d company: %1d IP: %s",
01924 cs->client_id, ci->client_name, status, lag,
01925 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
01926 cs->GetClientIP());
01927 }
01928 }
01929
01933 void NetworkServerSendConfigUpdate()
01934 {
01935 NetworkClientSocket *cs;
01936
01937 FOR_ALL_CLIENT_SOCKETS(cs) {
01938 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate();
01939 }
01940 }
01941
01947 void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded)
01948 {
01949 if (NetworkCompanyIsPassworded(company_id) == passworded) return;
01950
01951 SB(_network_company_passworded, company_id, 1, !!passworded);
01952 SetWindowClassesDirty(WC_COMPANY);
01953
01954 NetworkClientSocket *cs;
01955 FOR_ALL_CLIENT_SOCKETS(cs) {
01956 if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendCompanyUpdate();
01957 }
01958
01959 NetworkAdminCompanyUpdate(Company::GetIfValid(company_id));
01960 }
01961
01968 void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
01969 {
01970
01971 if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
01972
01973 NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
01974
01975
01976 if (ci->client_playas == company_id) return;
01977
01978 ci->client_playas = company_id;
01979
01980 if (client_id == CLIENT_ID_SERVER) {
01981 SetLocalCompany(company_id);
01982 } else {
01983 NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id);
01984
01985 if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
01986 cs->SendMove(client_id, company_id);
01987 }
01988
01989
01990 NetworkUpdateClientInfo(client_id);
01991
01992 NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN;
01993 NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
01994 }
01995
02002 void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string)
02003 {
02004 NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string);
02005 }
02006
02011 void NetworkServerKickClient(ClientID client_id)
02012 {
02013 if (client_id == CLIENT_ID_SERVER) return;
02014 NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED);
02015 }
02016
02022 uint NetworkServerKickOrBanIP(ClientID client_id, bool ban)
02023 {
02024 return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban);
02025 }
02026
02032 uint NetworkServerKickOrBanIP(const char *ip, bool ban)
02033 {
02034
02035 if (ban) *_network_ban_list.Append() = strdup(ip);
02036
02037 uint n = 0;
02038
02039
02040 NetworkClientSocket *cs;
02041 FOR_ALL_CLIENT_SOCKETS(cs) {
02042 if (cs->client_id == CLIENT_ID_SERVER) continue;
02043 if (cs->client_address.IsInNetmask(const_cast<char *>(ip))) {
02044 NetworkServerKickClient(cs->client_id);
02045 n++;
02046 }
02047 }
02048
02049 return n;
02050 }
02051
02057 bool NetworkCompanyHasClients(CompanyID company)
02058 {
02059 const NetworkClientInfo *ci;
02060 FOR_ALL_CLIENT_INFOS(ci) {
02061 if (ci->client_playas == company) return true;
02062 }
02063 return false;
02064 }
02065
02066
02072 void ServerNetworkGameSocketHandler::GetClientName(char *client_name, size_t size) const
02073 {
02074 const NetworkClientInfo *ci = this->GetInfo();
02075
02076 if (ci == NULL || StrEmpty(ci->client_name)) {
02077 snprintf(client_name, size, "Client #%4d", this->client_id);
02078 } else {
02079 ttd_strlcpy(client_name, ci->client_name, size);
02080 }
02081 }
02082
02086 void NetworkPrintClients()
02087 {
02088 NetworkClientInfo *ci;
02089 FOR_ALL_CLIENT_INFOS(ci) {
02090 IConsolePrintF(CC_INFO, _network_server ? "Client #%1d name: '%s' company: %1d IP: %s" : "Client #%1d name: '%s' company: %1d",
02091 ci->client_id,
02092 ci->client_name,
02093 ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
02094 _network_server ? (ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP()) : "");
02095 }
02096 }
02097
02098 #endif