network_server.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
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 /* This file handles all the server-commands */
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     /* Prevent double frees. */
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   /* virtual */ void Write(byte *buf, size_t size)
00102   {
00103     /* We want to abort the saving when the socket is closed. */
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   /* virtual */ void Finish()
00129   {
00130     /* We want to abort the saving when the socket is closed. */
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     /* Make sure the last packet is flushed. */
00136     this->AppendQueue();
00137 
00138     /* Add a packet stating that this is the end to the queue. */
00139     this->current = new Packet(PACKET_SERVER_MAP_DONE);
00140     this->AppendQueue();
00141 
00142     /* Fast-track the size to the client. */
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   /* The Socket and Info pools need to be the same in size. After all,
00163    * each Socket will be associated with at most one Info object. As
00164    * such if the Socket was allocated the Info object can as well. */
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   /* Make sure the saving is completely cancelled.
00181    * Yes, we need to handle the save finish as well
00182    * as the next connection in this "loop" might
00183    * just be requesting the map and such. */
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   /* Only allow receiving when we have some buffer free; this value
00199    * can go negative, but eventually it will become positive again. */
00200   if (this->receive_limit <= 0) return NULL;
00201 
00202   /* We can receive a packet, so try that and if needed account for
00203    * the amount of received data. */
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    * Sending a message just before leaving the game calls cs->SendPackets.
00221    * This might invoke this function, which means that when we close the
00222    * connection after cs->SendPackets we will close an already closed
00223    * connection. This handles that case gracefully without having to make
00224    * that code any more complex or more aware of the validity of the socket.
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     /* We did not receive a leave message from this client... */
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     /* Inform other clients of this... strange leaving ;) */
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   /* We just lost one client :( */
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 /* static */ 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   /* We can't go over the MAX_CLIENTS limit here. However, the
00274    * pool must have place for all clients and ourself. */
00275   assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1);
00276   assert(!accept || ServerNetworkGameSocketHandler::CanAllocateItem());
00277   return accept;
00278 }
00279 
00281 /* static */ 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         /* This client is in the middle of a map-send, call the function for that */
00288         cs->SendMap();
00289       }
00290     }
00291   }
00292 }
00293 
00294 static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
00295 
00296 /***********
00297  * Sending functions
00298  *   DEF_SERVER_SEND_COMMAND has parameter: NetworkClientSocket *cs
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   /* Fetch the latest version of the stats */
00322   NetworkCompanyStats company_stats[MAX_COMPANIES];
00323   NetworkPopulateCompanyStats(company_stats);
00324 
00325   /* Make a list of all clients per company */
00326   char clients[MAX_COMPANIES][NETWORK_CLIENTS_LENGTH];
00327   NetworkClientSocket *csi;
00328   memset(clients, 0, sizeof(clients));
00329 
00330   /* Add the local player (if not dedicated) */
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   /* Now send the data */
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   /* Only send when the current client was in game */
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         /* Some errors we filter to a more general error. Clients don't have to know the real
00410          *  reason a joining failed. */
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   /* The client made a mistake, so drop his connection now! */
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   /* Invalid packet when status is STATUS_AUTH_GAME or higher */
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   /* Invalid packet when status is STATUS_AUTH_COMPANY or higher */
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   /* Invalid packet when status is AUTH or higher */
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   /* Transmit info about all the active clients */
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   /* Also send the info of the server */
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   /* Count how many clients are waiting in the queue, in front of you! */
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; // How many packets we did send succecfully last time
00526 
00527   if (this->status < STATUS_AUTHORIZED) {
00528     /* Illegal call, return error and ignore the packet */
00529     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
00530   }
00531 
00532   if (this->status == STATUS_AUTHORIZED) {
00533     this->savegame = new PacketWriter(this);
00534 
00535     /* Now send the _frame_counter and how many packets are coming */
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     /* Mark the start of download */
00543     this->last_frame = _frame_counter;
00544     this->last_frame_server = _frame_counter;
00545 
00546     sent_packets = 4; // We start with trying 4 packets
00547 
00548     /* Make a dump of the current game */
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       /* Remove the packet from the savegame queue and put it in the real queue. */
00562       this->savegame_packets = p->next;
00563       p->next = NULL;
00564       this->NetworkTCPSocketHandler::SendPacket(p);
00565 
00566       if (last_packet) {
00567         /* There is no more data, so break the for */
00568         break;
00569       }
00570     }
00571 
00572     if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
00573 
00574     if (last_packet) {
00575       /* Done reading, make sure saving is done as well */
00576       WaitTillSaved();
00577 
00578       /* Set the status to DONE_MAP, no we will wait for the client
00579        *  to send it is ready (maybe that happens like never ;)) */
00580       this->status = STATUS_DONE_MAP;
00581 
00582       /* Find the best candidate for joining, i.e. the first joiner. */
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       /* Is there someone else to join? */
00594       if (best != NULL) {
00595         /* Let the first start joining. */
00596         best->status = STATUS_AUTHORIZED;
00597         best->SendMap();
00598 
00599         /* And update the rest. */
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         /* All are sent, increase the sent_packets */
00612         if (this->savegame_packets != NULL) sent_packets *= 2;
00613         break;
00614 
00615       case SPS_PARTLY_SENT:
00616         /* Only a part is sent; leave the transmission state. */
00617         break;
00618 
00619       case SPS_NONE_SENT:
00620         /* Not everything is sent, decrease the sent_packets */
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   /* If token equals 0, we need to make a new token and send that. */
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   Packet *p = new Packet(PACKET_SERVER_CHAT);
00706 
00707   p->Send_uint8 (action);
00708   p->Send_uint32(client_id);
00709   p->Send_bool  (self_send);
00710   p->Send_string(msg);
00711   p->Send_uint64(data);
00712 
00713   this->SendPacket(p);
00714   return NETWORK_RECV_STATUS_OKAY;
00715 }
00716 
00722 NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
00723 {
00724   Packet *p = new Packet(PACKET_SERVER_ERROR_QUIT);
00725 
00726   p->Send_uint32(client_id);
00727   p->Send_uint8 (errorno);
00728 
00729   this->SendPacket(p);
00730   return NETWORK_RECV_STATUS_OKAY;
00731 }
00732 
00737 NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
00738 {
00739   Packet *p = new Packet(PACKET_SERVER_QUIT);
00740 
00741   p->Send_uint32(client_id);
00742 
00743   this->SendPacket(p);
00744   return NETWORK_RECV_STATUS_OKAY;
00745 }
00746 
00748 NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
00749 {
00750   Packet *p = new Packet(PACKET_SERVER_SHUTDOWN);
00751   this->SendPacket(p);
00752   return NETWORK_RECV_STATUS_OKAY;
00753 }
00754 
00756 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame()
00757 {
00758   Packet *p = new Packet(PACKET_SERVER_NEWGAME);
00759   this->SendPacket(p);
00760   return NETWORK_RECV_STATUS_OKAY;
00761 }
00762 
00768 NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16 colour, const char *command)
00769 {
00770   Packet *p = new Packet(PACKET_SERVER_RCON);
00771 
00772   p->Send_uint16(colour);
00773   p->Send_string(command);
00774   this->SendPacket(p);
00775   return NETWORK_RECV_STATUS_OKAY;
00776 }
00777 
00783 NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, CompanyID company_id)
00784 {
00785   Packet *p = new Packet(PACKET_SERVER_MOVE);
00786 
00787   p->Send_uint32(client_id);
00788   p->Send_uint8(company_id);
00789   this->SendPacket(p);
00790   return NETWORK_RECV_STATUS_OKAY;
00791 }
00792 
00794 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
00795 {
00796   Packet *p = new Packet(PACKET_SERVER_COMPANY_UPDATE);
00797 
00798   p->Send_uint16(_network_company_passworded);
00799   this->SendPacket(p);
00800   return NETWORK_RECV_STATUS_OKAY;
00801 }
00802 
00804 NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
00805 {
00806   Packet *p = new Packet(PACKET_SERVER_CONFIG_UPDATE);
00807 
00808   p->Send_uint8(_settings_client.network.max_companies);
00809   p->Send_uint8(_settings_client.network.max_spectators);
00810   this->SendPacket(p);
00811   return NETWORK_RECV_STATUS_OKAY;
00812 }
00813 
00814 /***********
00815  * Receiving functions
00816  *   DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p
00817  ************/
00818 
00819 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_INFO(Packet *p)
00820 {
00821   return this->SendCompanyInfo();
00822 }
00823 
00824 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet *p)
00825 {
00826   if (this->status != STATUS_NEWGRFS_CHECK) {
00827     /* Illegal call, return error and ignore the packet */
00828     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00829   }
00830 
00831   NetworkClientInfo *ci = this->GetInfo();
00832 
00833   /* We now want a password from the client else we do not allow him in! */
00834   if (!StrEmpty(_settings_client.network.server_password)) {
00835     return this->SendNeedGamePassword();
00836   }
00837 
00838   if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
00839     return this->SendNeedCompanyPassword();
00840   }
00841 
00842   return this->SendWelcome();
00843 }
00844 
00845 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p)
00846 {
00847   if (this->status != STATUS_INACTIVE) {
00848     /* Illegal call, return error and ignore the packet */
00849     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00850   }
00851 
00852   char name[NETWORK_CLIENT_NAME_LENGTH];
00853   CompanyID playas;
00854   NetworkLanguage client_lang;
00855   char client_revision[NETWORK_REVISION_LENGTH];
00856 
00857   p->Recv_string(client_revision, sizeof(client_revision));
00858 
00859   /* Check if the client has revision control enabled */
00860   if (!IsNetworkCompatibleVersion(client_revision)) {
00861     /* Different revisions!! */
00862     return this->SendError(NETWORK_ERROR_WRONG_REVISION);
00863   }
00864 
00865   p->Recv_string(name, sizeof(name));
00866   playas = (Owner)p->Recv_uint8();
00867   client_lang = (NetworkLanguage)p->Recv_uint8();
00868 
00869   if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
00870 
00871   /* join another company does not affect these values */
00872   switch (playas) {
00873     case COMPANY_NEW_COMPANY: // New company
00874       if (Company::GetNumItems() >= _settings_client.network.max_companies) {
00875         return this->SendError(NETWORK_ERROR_FULL);
00876       }
00877       break;
00878     case COMPANY_SPECTATOR: // Spectator
00879       if (NetworkSpectatorCount() >= _settings_client.network.max_spectators) {
00880         return this->SendError(NETWORK_ERROR_FULL);
00881       }
00882       break;
00883     default: // Join another company (companies 1-8 (index 0-7))
00884       if (!Company::IsValidHumanID(playas)) {
00885         return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
00886       }
00887       break;
00888   }
00889 
00890   /* We need a valid name.. make it Player */
00891   if (StrEmpty(name)) strecpy(name, "Player", lastof(name));
00892 
00893   if (!NetworkFindName(name)) { // Change name if duplicate
00894     /* We could not create a name for this client */
00895     return this->SendError(NETWORK_ERROR_NAME_IN_USE);
00896   }
00897 
00898   assert(NetworkClientInfo::CanAllocateItem());
00899   NetworkClientInfo *ci = new NetworkClientInfo(this->client_id);
00900   this->SetInfo(ci);
00901   ci->join_date = _date;
00902   strecpy(ci->client_name, name, lastof(ci->client_name));
00903   ci->client_playas = playas;
00904   ci->client_lang = client_lang;
00905   DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, ci->index);
00906 
00907   /* Make sure companies to which people try to join are not autocleaned */
00908   if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0;
00909 
00910   this->status = STATUS_NEWGRFS_CHECK;
00911 
00912   if (_grfconfig == NULL) {
00913     /* Behave as if we received PACKET_CLIENT_NEWGRFS_CHECKED */
00914     return this->Receive_CLIENT_NEWGRFS_CHECKED(NULL);
00915   }
00916 
00917   return this->SendNewGRFCheck();
00918 }
00919 
00920 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p)
00921 {
00922   if (this->status != STATUS_AUTH_GAME) {
00923     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00924   }
00925 
00926   char password[NETWORK_PASSWORD_LENGTH];
00927   p->Recv_string(password, sizeof(password));
00928 
00929   /* Check game password. Allow joining if we cleared the password meanwhile */
00930   if (!StrEmpty(_settings_client.network.server_password) &&
00931       strcmp(password, _settings_client.network.server_password) != 0) {
00932     /* Password is invalid */
00933     return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
00934   }
00935 
00936   const NetworkClientInfo *ci = this->GetInfo();
00937   if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
00938     return this->SendNeedCompanyPassword();
00939   }
00940 
00941   /* Valid password, allow user */
00942   return this->SendWelcome();
00943 }
00944 
00945 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p)
00946 {
00947   if (this->status != STATUS_AUTH_COMPANY) {
00948     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00949   }
00950 
00951   char password[NETWORK_PASSWORD_LENGTH];
00952   p->Recv_string(password, sizeof(password));
00953 
00954   /* Check company password. Allow joining if we cleared the password meanwhile.
00955    * Also, check the company is still valid - client could be moved to spectators
00956    * in the middle of the authorization process */
00957   CompanyID playas = this->GetInfo()->client_playas;
00958   if (Company::IsValidID(playas) && !StrEmpty(_network_company_states[playas].password) &&
00959       strcmp(password, _network_company_states[playas].password) != 0) {
00960     /* Password is invalid */
00961     return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
00962   }
00963 
00964   return this->SendWelcome();
00965 }
00966 
00967 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p)
00968 {
00969   NetworkClientSocket *new_cs;
00970 
00971   /* Do an extra version match. We told the client our version already,
00972    * lets confirm that the client isn't lieing to us.
00973    * But only do it for stable releases because of those we are sure
00974    * that everybody has the same NewGRF version. For trunk and the
00975    * branches we make tarballs of the OpenTTDs compiled from tarball
00976    * will have the lower bits set to 0. As such they would become
00977    * incompatible, which we would like to prevent by this. */
00978   if (HasBit(_openttd_newgrf_version, 19)) {
00979     if (_openttd_newgrf_version != p->Recv_uint32()) {
00980       /* The version we get from the client differs, it must have the
00981        * wrong version. The client must be wrong. */
00982       return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00983     }
00984   } else if (p->size != 3) {
00985     /* We received a packet from a version that claims to be stable.
00986      * That shouldn't happen. The client must be wrong. */
00987     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00988   }
00989 
00990   /* The client was never joined.. so this is impossible, right?
00991    *  Ignore the packet, give the client a warning, and close his connection */
00992   if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) {
00993     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
00994   }
00995 
00996   /* Check if someone else is receiving the map */
00997   FOR_ALL_CLIENT_SOCKETS(new_cs) {
00998     if (new_cs->status == STATUS_MAP) {
00999       /* Tell the new client to wait */
01000       this->status = STATUS_MAP_WAIT;
01001       return this->SendWait();
01002     }
01003   }
01004 
01005   /* We receive a request to upload the map.. give it to the client! */
01006   return this->SendMap();
01007 }
01008 
01009 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *p)
01010 {
01011   /* Client has the map, now start syncing */
01012   if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
01013     char client_name[NETWORK_CLIENT_NAME_LENGTH];
01014     NetworkClientSocket *new_cs;
01015 
01016     this->GetClientName(client_name, sizeof(client_name));
01017 
01018     NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, NULL, this->client_id);
01019 
01020     /* Mark the client as pre-active, and wait for an ACK
01021      *  so we know he is done loading and in sync with us */
01022     this->status = STATUS_PRE_ACTIVE;
01023     NetworkHandleCommandQueue(this);
01024     this->SendFrame();
01025     this->SendSync();
01026 
01027     /* This is the frame the client receives
01028      *  we need it later on to make sure the client is not too slow */
01029     this->last_frame = _frame_counter;
01030     this->last_frame_server = _frame_counter;
01031 
01032     FOR_ALL_CLIENT_SOCKETS(new_cs) {
01033       if (new_cs->status > STATUS_AUTHORIZED) {
01034         new_cs->SendClientInfo(this->GetInfo());
01035         new_cs->SendJoin(this->client_id);
01036       }
01037     }
01038 
01039     NetworkAdminClientInfo(this, true);
01040 
01041     /* also update the new client with our max values */
01042     this->SendConfigUpdate();
01043 
01044     /* quickly update the syncing client with company details */
01045     return this->SendCompanyUpdate();
01046   }
01047 
01048   /* Wrong status for this packet, give a warning to client, and close connection */
01049   return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01050 }
01051 
01056 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet *p)
01057 {
01058   /* The client was never joined.. so this is impossible, right?
01059    *  Ignore the packet, give the client a warning, and close his connection */
01060   if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01061     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01062   }
01063 
01064   if (this->incoming_queue.Count() >= _settings_client.network.max_commands_in_queue) {
01065     return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
01066   }
01067 
01068   CommandPacket cp;
01069   const char *err = this->ReceiveCommand(p, &cp);
01070 
01071   if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
01072 
01073   NetworkClientInfo *ci = this->GetInfo();
01074 
01075   if (err != NULL) {
01076     IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, this->GetClientIP());
01077     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01078   }
01079 
01080 
01081   if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER) {
01082     IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
01083     return this->SendError(NETWORK_ERROR_KICKED);
01084   }
01085 
01086   if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) {
01087     IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
01088     return this->SendError(NETWORK_ERROR_KICKED);
01089   }
01090 
01096   if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
01097     IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
01098                    ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
01099     return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
01100   }
01101 
01102   if (cp.cmd == CMD_COMPANY_CTRL) {
01103     if (cp.p1 != 0 || cp.company != COMPANY_SPECTATOR) {
01104       return this->SendError(NETWORK_ERROR_CHEATER);
01105     }
01106 
01107     /* 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! */
01108     if (Company::GetNumItems() >= _settings_client.network.max_companies) {
01109       NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
01110       return NETWORK_RECV_STATUS_OKAY;
01111     }
01112   }
01113 
01114   if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) cp.p2 = this->client_id;
01115 
01116   this->incoming_queue.Append(&cp);
01117   return NETWORK_RECV_STATUS_OKAY;
01118 }
01119 
01120 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p)
01121 {
01122   /* This packets means a client noticed an error and is reporting this
01123    *  to us. Display the error and report it to the other clients */
01124   NetworkClientSocket *new_cs;
01125   char str[100];
01126   char client_name[NETWORK_CLIENT_NAME_LENGTH];
01127   NetworkErrorCode errorno = (NetworkErrorCode)p->Recv_uint8();
01128 
01129   /* The client was never joined.. thank the client for the packet, but ignore it */
01130   if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01131     return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01132   }
01133 
01134   this->GetClientName(client_name, sizeof(client_name));
01135 
01136   StringID strid = GetNetworkErrorMsg(errorno);
01137   GetString(str, strid, lastof(str));
01138 
01139   DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
01140 
01141   NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid);
01142 
01143   FOR_ALL_CLIENT_SOCKETS(new_cs) {
01144     if (new_cs->status > STATUS_AUTHORIZED) {
01145       new_cs->SendErrorQuit(this->client_id, errorno);
01146     }
01147   }
01148 
01149   NetworkAdminClientError(this->client_id, errorno);
01150 
01151   return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01152 }
01153 
01154 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p)
01155 {
01156   /* The client wants to leave. Display this and report it to the other
01157    *  clients. */
01158   NetworkClientSocket *new_cs;
01159   char client_name[NETWORK_CLIENT_NAME_LENGTH];
01160 
01161   /* The client was never joined.. thank the client for the packet, but ignore it */
01162   if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01163     return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01164   }
01165 
01166   this->GetClientName(client_name, sizeof(client_name));
01167 
01168   NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING);
01169 
01170   FOR_ALL_CLIENT_SOCKETS(new_cs) {
01171     if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
01172       new_cs->SendQuit(this->client_id);
01173     }
01174   }
01175 
01176   NetworkAdminClientQuit(this->client_id);
01177 
01178   return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01179 }
01180 
01181 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p)
01182 {
01183   if (this->status < STATUS_AUTHORIZED) {
01184     /* Illegal call, return error and ignore the packet */
01185     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
01186   }
01187 
01188   uint32 frame = p->Recv_uint32();
01189 
01190   /* The client is trying to catch up with the server */
01191   if (this->status == STATUS_PRE_ACTIVE) {
01192     /* The client is not yet catched up? */
01193     if (frame + DAY_TICKS < _frame_counter) return NETWORK_RECV_STATUS_OKAY;
01194 
01195     /* Now he is! Unpause the game */
01196     this->status = STATUS_ACTIVE;
01197     this->last_token_frame = _frame_counter;
01198 
01199     /* Execute script for, e.g. MOTD */
01200     IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
01201   }
01202 
01203   /* Get, and validate the token. */
01204   uint8 token = p->Recv_uint8();
01205   if (token == this->last_token) {
01206     /* We differentiate between last_token_frame and last_frame so the lag
01207      * test uses the actual lag of the client instead of the lag for getting
01208      * the token back and forth; after all, the token is only sent every
01209      * time we receive a PACKET_CLIENT_ACK, after which we will send a new
01210      * token to the client. If the lag would be one day, then we would not
01211      * be sending the new token soon enough for the new daily scheduled
01212      * PACKET_CLIENT_ACK. This would then register the lag of the client as
01213      * two days, even when it's only a single day. */
01214     this->last_token_frame = _frame_counter;
01215     /* Request a new token. */
01216     this->last_token = 0;
01217   }
01218 
01219   /* The client received the frame, make note of it */
01220   this->last_frame = frame;
01221   /* With those 2 values we can calculate the lag realtime */
01222   this->last_frame_server = _frame_counter;
01223   return NETWORK_RECV_STATUS_OKAY;
01224 }
01225 
01226 
01237 void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, ClientID from_id, int64 data, bool from_admin)
01238 {
01239   NetworkClientSocket *cs;
01240   const NetworkClientInfo *ci, *ci_own, *ci_to;
01241 
01242   switch (desttype) {
01243     case DESTTYPE_CLIENT:
01244       /* Are we sending to the server? */
01245       if ((ClientID)dest == CLIENT_ID_SERVER) {
01246         ci = NetworkClientInfo::GetByClientID(from_id);
01247         /* Display the text locally, and that is it */
01248         if (ci != NULL) {
01249           NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01250 
01251           if (_settings_client.network.server_admin_chat) {
01252             NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01253           }
01254         }
01255       } else {
01256         /* Else find the client to send the message to */
01257         FOR_ALL_CLIENT_SOCKETS(cs) {
01258           if (cs->client_id == (ClientID)dest) {
01259             cs->SendChat(action, from_id, false, msg, data);
01260             break;
01261           }
01262         }
01263       }
01264 
01265       /* Display the message locally (so you know you have sent it) */
01266       if (from_id != (ClientID)dest) {
01267         if (from_id == CLIENT_ID_SERVER) {
01268           ci = NetworkClientInfo::GetByClientID(from_id);
01269           ci_to = NetworkClientInfo::GetByClientID((ClientID)dest);
01270           if (ci != NULL && ci_to != NULL) {
01271             NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
01272           }
01273         } else {
01274           FOR_ALL_CLIENT_SOCKETS(cs) {
01275             if (cs->client_id == from_id) {
01276               cs->SendChat(action, (ClientID)dest, true, msg, data);
01277               break;
01278             }
01279           }
01280         }
01281       }
01282       break;
01283     case DESTTYPE_TEAM: {
01284       /* If this is false, the message is already displayed on the client who sent it. */
01285       bool show_local = true;
01286       /* Find all clients that belong to this company */
01287       ci_to = NULL;
01288       FOR_ALL_CLIENT_SOCKETS(cs) {
01289         ci = cs->GetInfo();
01290         if (ci != NULL && ci->client_playas == (CompanyID)dest) {
01291           cs->SendChat(action, from_id, false, msg, data);
01292           if (cs->client_id == from_id) show_local = false;
01293           ci_to = ci; // Remember a client that is in the company for company-name
01294         }
01295       }
01296 
01297       /* if the server can read it, let the admin network read it, too. */
01298       if (_local_company == (CompanyID)dest && _settings_client.network.server_admin_chat) {
01299         NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01300       }
01301 
01302       ci = NetworkClientInfo::GetByClientID(from_id);
01303       ci_own = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
01304       if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
01305         NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01306         if (from_id == CLIENT_ID_SERVER) show_local = false;
01307         ci_to = ci_own;
01308       }
01309 
01310       /* There is no such client */
01311       if (ci_to == NULL) break;
01312 
01313       /* Display the message locally (so you know you have sent it) */
01314       if (ci != NULL && show_local) {
01315         if (from_id == CLIENT_ID_SERVER) {
01316           char name[NETWORK_NAME_LENGTH];
01317           StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
01318           SetDParam(0, ci_to->client_playas);
01319           GetString(name, str, lastof(name));
01320           NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
01321         } else {
01322           FOR_ALL_CLIENT_SOCKETS(cs) {
01323             if (cs->client_id == from_id) {
01324               cs->SendChat(action, ci_to->client_id, true, msg, data);
01325             }
01326           }
01327         }
01328       }
01329       break;
01330     }
01331     default:
01332       DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
01333       /* FALL THROUGH */
01334     case DESTTYPE_BROADCAST:
01335       FOR_ALL_CLIENT_SOCKETS(cs) {
01336         cs->SendChat(action, from_id, false, msg, data);
01337       }
01338 
01339       NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01340 
01341       ci = NetworkClientInfo::GetByClientID(from_id);
01342       if (ci != NULL) {
01343         NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01344       }
01345       break;
01346   }
01347 }
01348 
01349 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p)
01350 {
01351   if (this->status < STATUS_AUTHORIZED) {
01352     /* Illegal call, return error and ignore the packet */
01353     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
01354   }
01355 
01356   NetworkAction action = (NetworkAction)p->Recv_uint8();
01357   DestType desttype = (DestType)p->Recv_uint8();
01358   int dest = p->Recv_uint32();
01359   char msg[NETWORK_CHAT_LENGTH];
01360 
01361   p->Recv_string(msg, NETWORK_CHAT_LENGTH);
01362   int64 data = p->Recv_uint64();
01363 
01364   NetworkClientInfo *ci = this->GetInfo();
01365   switch (action) {
01366     case NETWORK_ACTION_GIVE_MONEY:
01367       if (!Company::IsValidID(ci->client_playas)) break;
01368       /* FALL THROUGH */
01369     case NETWORK_ACTION_CHAT:
01370     case NETWORK_ACTION_CHAT_CLIENT:
01371     case NETWORK_ACTION_CHAT_COMPANY:
01372       NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
01373       break;
01374     default:
01375       IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, this->GetClientIP());
01376       return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01377   }
01378   return NETWORK_RECV_STATUS_OKAY;
01379 }
01380 
01381 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet *p)
01382 {
01383   if (this->status != STATUS_ACTIVE) {
01384     /* Illegal call, return error and ignore the packet */
01385     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01386   }
01387 
01388   char password[NETWORK_PASSWORD_LENGTH];
01389   const NetworkClientInfo *ci;
01390 
01391   p->Recv_string(password, sizeof(password));
01392   ci = this->GetInfo();
01393 
01394   NetworkServerSetCompanyPassword(ci->client_playas, password);
01395   return NETWORK_RECV_STATUS_OKAY;
01396 }
01397 
01398 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p)
01399 {
01400   if (this->status != STATUS_ACTIVE) {
01401     /* Illegal call, return error and ignore the packet */
01402     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01403   }
01404 
01405   char client_name[NETWORK_CLIENT_NAME_LENGTH];
01406   NetworkClientInfo *ci;
01407 
01408   p->Recv_string(client_name, sizeof(client_name));
01409   ci = this->GetInfo();
01410 
01411   if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
01412 
01413   if (ci != NULL) {
01414     /* Display change */
01415     if (NetworkFindName(client_name)) {
01416       NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);
01417       strecpy(ci->client_name, client_name, lastof(ci->client_name));
01418       NetworkUpdateClientInfo(ci->client_id);
01419     }
01420   }
01421   return NETWORK_RECV_STATUS_OKAY;
01422 }
01423 
01424 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
01425 {
01426   if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01427 
01428   char pass[NETWORK_PASSWORD_LENGTH];
01429   char command[NETWORK_RCONCOMMAND_LENGTH];
01430 
01431   if (StrEmpty(_settings_client.network.rcon_password)) return NETWORK_RECV_STATUS_OKAY;
01432 
01433   p->Recv_string(pass, sizeof(pass));
01434   p->Recv_string(command, sizeof(command));
01435 
01436   if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
01437     DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
01438     return NETWORK_RECV_STATUS_OKAY;
01439   }
01440 
01441   DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", this->client_id, command);
01442 
01443   _redirect_console_to_client = this->client_id;
01444   IConsoleCmdExec(command);
01445   _redirect_console_to_client = INVALID_CLIENT_ID;
01446   return NETWORK_RECV_STATUS_OKAY;
01447 }
01448 
01449 NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p)
01450 {
01451   if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01452 
01453   CompanyID company_id = (Owner)p->Recv_uint8();
01454 
01455   /* Check if the company is valid, we don't allow moving to AI companies */
01456   if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
01457 
01458   /* Check if we require a password for this company */
01459   if (company_id != COMPANY_SPECTATOR && !StrEmpty(_network_company_states[company_id].password)) {
01460     /* we need a password from the client - should be in this packet */
01461     char password[NETWORK_PASSWORD_LENGTH];
01462     p->Recv_string(password, sizeof(password));
01463 
01464     /* Incorrect password sent, return! */
01465     if (strcmp(password, _network_company_states[company_id].password) != 0) {
01466       DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", this->client_id, company_id + 1);
01467       return NETWORK_RECV_STATUS_OKAY;
01468     }
01469   }
01470 
01471   /* if we get here we can move the client */
01472   NetworkServerDoMove(this->client_id, company_id);
01473   return NETWORK_RECV_STATUS_OKAY;
01474 }
01475 
01483 void NetworkSocketHandler::SendCompanyInformation(Packet *p, const Company *c, const NetworkCompanyStats *stats, uint max_len)
01484 {
01485   /* Grab the company name */
01486   char company_name[NETWORK_COMPANY_NAME_LENGTH];
01487   SetDParam(0, c->index);
01488 
01489   assert(max_len <= lengthof(company_name));
01490   GetString(company_name, STR_COMPANY_NAME, company_name + max_len - 1);
01491 
01492   /* Get the income */
01493   Money income = 0;
01494   if (_cur_year - 1 == c->inaugurated_year) {
01495     /* The company is here just 1 year, so display [2], else display[1] */
01496     for (uint i = 0; i < lengthof(c->yearly_expenses[2]); i++) {
01497       income -= c->yearly_expenses[2][i];
01498     }
01499   } else {
01500     for (uint i = 0; i < lengthof(c->yearly_expenses[1]); i++) {
01501       income -= c->yearly_expenses[1][i];
01502     }
01503   }
01504 
01505   /* Send the information */
01506   p->Send_uint8 (c->index);
01507   p->Send_string(company_name);
01508   p->Send_uint32(c->inaugurated_year);
01509   p->Send_uint64(c->old_economy[0].company_value);
01510   p->Send_uint64(c->money);
01511   p->Send_uint64(income);
01512   p->Send_uint16(c->old_economy[0].performance_history);
01513 
01514   /* Send 1 if there is a passord for the company else send 0 */
01515   p->Send_bool  (!StrEmpty(_network_company_states[c->index].password));
01516 
01517   for (uint i = 0; i < NETWORK_VEH_END; i++) {
01518     p->Send_uint16(stats->num_vehicle[i]);
01519   }
01520 
01521   for (uint i = 0; i < NETWORK_VEH_END; i++) {
01522     p->Send_uint16(stats->num_station[i]);
01523   }
01524 
01525   p->Send_bool(c->is_ai);
01526 }
01527 
01532 void NetworkPopulateCompanyStats(NetworkCompanyStats *stats)
01533 {
01534   const Vehicle *v;
01535   const Station *s;
01536 
01537   memset(stats, 0, sizeof(*stats) * MAX_COMPANIES);
01538 
01539   /* Go through all vehicles and count the type of vehicles */
01540   FOR_ALL_VEHICLES(v) {
01541     if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
01542     byte type = 0;
01543     switch (v->type) {
01544       case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
01545       case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
01546       case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break;
01547       case VEH_SHIP: type = NETWORK_VEH_SHIP; break;
01548       default: continue;
01549     }
01550     stats[v->owner].num_vehicle[type]++;
01551   }
01552 
01553   /* Go through all stations and count the types of stations */
01554   FOR_ALL_STATIONS(s) {
01555     if (Company::IsValidID(s->owner)) {
01556       NetworkCompanyStats *npi = &stats[s->owner];
01557 
01558       if (s->facilities & FACIL_TRAIN)      npi->num_station[NETWORK_VEH_TRAIN]++;
01559       if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[NETWORK_VEH_LORRY]++;
01560       if (s->facilities & FACIL_BUS_STOP)   npi->num_station[NETWORK_VEH_BUS]++;
01561       if (s->facilities & FACIL_AIRPORT)    npi->num_station[NETWORK_VEH_PLANE]++;
01562       if (s->facilities & FACIL_DOCK)       npi->num_station[NETWORK_VEH_SHIP]++;
01563     }
01564   }
01565 }
01566 
01571 void NetworkUpdateClientInfo(ClientID client_id)
01572 {
01573   NetworkClientSocket *cs;
01574   NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
01575 
01576   if (ci == NULL) return;
01577 
01578   DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id);
01579 
01580   FOR_ALL_CLIENT_SOCKETS(cs) {
01581     cs->SendClientInfo(ci);
01582   }
01583 
01584   NetworkAdminClientUpdate(ci);
01585 }
01586 
01588 static void NetworkCheckRestartMap()
01589 {
01590   if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) {
01591     DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year);
01592 
01593     StartNewGameWithoutGUI(GENERATE_NEW_SEED);
01594   }
01595 }
01596 
01603 static void NetworkAutoCleanCompanies()
01604 {
01605   const NetworkClientInfo *ci;
01606   const Company *c;
01607   bool clients_in_company[MAX_COMPANIES];
01608   int vehicles_in_company[MAX_COMPANIES];
01609 
01610   if (!_settings_client.network.autoclean_companies) return;
01611 
01612   memset(clients_in_company, 0, sizeof(clients_in_company));
01613 
01614   /* Detect the active companies */
01615   FOR_ALL_CLIENT_INFOS(ci) {
01616     if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
01617   }
01618 
01619   if (!_network_dedicated) {
01620     ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
01621     if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
01622   }
01623 
01624   if (_settings_client.network.autoclean_novehicles != 0) {
01625     memset(vehicles_in_company, 0, sizeof(vehicles_in_company));
01626 
01627     const Vehicle *v;
01628     FOR_ALL_VEHICLES(v) {
01629       if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
01630       vehicles_in_company[v->owner]++;
01631     }
01632   }
01633 
01634   /* Go through all the comapnies */
01635   FOR_ALL_COMPANIES(c) {
01636     /* Skip the non-active once */
01637     if (c->is_ai) continue;
01638 
01639     if (!clients_in_company[c->index]) {
01640       /* The company is empty for one month more */
01641       _network_company_states[c->index].months_empty++;
01642 
01643       /* Is the company empty for autoclean_unprotected-months, and is there no protection? */
01644       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)) {
01645         /* Shut the company down */
01646         DoCommandP(0, 2 | c->index << 16, 0, CMD_COMPANY_CTRL);
01647         NetworkAdminCompanyRemove(c->index, ADMIN_CRR_AUTOCLEAN);
01648         IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1);
01649       }
01650       /* Is the company empty for autoclean_protected-months, and there is a protection? */
01651       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)) {
01652         /* Unprotect the company */
01653         _network_company_states[c->index].password[0] = '\0';
01654         IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", c->index + 1);
01655         _network_company_states[c->index].months_empty = 0;
01656         NetworkServerUpdateCompanyPassworded(c->index, false);
01657       }
01658       /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
01659       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) {
01660         /* Shut the company down */
01661         DoCommandP(0, 2 | c->index << 16, 0, CMD_COMPANY_CTRL);
01662         NetworkAdminCompanyRemove(c->index, ADMIN_CRR_AUTOCLEAN);
01663         IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1);
01664       }
01665     } else {
01666       /* It is not empty, reset the date */
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   /* We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer */
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         /* Name already in use */
01693         found_name = false;
01694         break;
01695       }
01696     }
01697     /* Check if it is the same as the server-name */
01698     ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
01699     if (ci != NULL) {
01700       if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use
01701     }
01702 
01703     if (!found_name) {
01704       /* Try a new name (<name> #1, <name> #2, and so on) */
01705 
01706       /* Something's really wrong when there're more names than clients */
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   /* Check if the name's already in use */
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   /* Now we are done with the frame, inform the clients that they can
01790    *  do their frame! */
01791   FOR_ALL_CLIENT_SOCKETS(cs) {
01792     /* We allow a number of bytes per frame, but only to the burst amount
01793      * to be available for packet receiving at any particular time. */
01794     cs->receive_limit = min(cs->receive_limit + _settings_client.network.bytes_per_frame,
01795         _settings_client.network.bytes_per_frame_burst);
01796 
01797     /* Check if the speed of the client is what we can expect from a client */
01798     if (cs->status == NetworkClientSocket::STATUS_ACTIVE) {
01799       /* 1 lag-point per day */
01800       uint lag = NetworkCalculateLag(cs) / DAY_TICKS;
01801       if (lag > 0) {
01802         if (lag > 3) {
01803           /* Client did still not report in after 4 game-day, drop him
01804            *  (that is, the 3 of above, + 1 before any lag is counted) */
01805           IConsolePrintF(CC_ERROR, cs->last_packet + 3 * DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick ?
01806               /* A packet was received in the last three game days, so the client is likely lagging behind. */
01807                 "Client #%d is dropped because the client's game state is more than 4 game-days behind" :
01808               /* No packet was received in the last three game days; sounds like a lost connection. */
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         /* Report once per time we detect the lag, and only when we
01816          * received a packet in the last 2000 milliseconds. If we
01817          * did not receive a packet, then the client is not just
01818          * slow, but the connection is likely severed. Mentioning
01819          * frame_freq is not useful in this case. */
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         /* This is a bad client! It didn't send the right token back. */
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       /* Check if we can send command, and if we have anything in the queue */
01851       NetworkHandleCommandQueue(cs);
01852 
01853       /* Send an updated _frame_counter_max to the client */
01854       if (send_frame) cs->SendFrame();
01855 
01856 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
01857       /* Send a sync-check packet */
01858       if (send_sync) cs->SendSync();
01859 #endif
01860     }
01861   }
01862 
01863   /* See if we need to advertise */
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   /* Only allow non-dedicated servers and normal clients to be moved */
01971   if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
01972 
01973   NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
01974 
01975   /* No need to waste network resources if the client is in the company already! */
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     /* When the company isn't authorized we can't move them yet. */
01985     if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
01986     cs->SendMove(client_id, company_id);
01987   }
01988 
01989   /* announce the client's move */
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   /* Add address to ban-list */
02035   if (ban) *_network_ban_list.Append() = strdup(ip);
02036 
02037   uint n = 0;
02038 
02039   /* There can be multiple clients with the same IP, kick them all */
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 /* ENABLE_NETWORK */

Generated on Mon May 9 05:18:55 2011 for OpenTTD by  doxygen 1.6.1