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);
00046 assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS);
00047 
00048 NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket");
00049 INSTANTIATE_POOL_METHODS(NetworkClientSocket)
00050 
00052 template SocketList TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED>::sockets;
00053 
00055 struct PacketWriter : SaveFilter {
00056   ServerNetworkGameSocketHandler *cs; 
00057   Packet *current;                    
00058   size_t total_size;                  
00059 
00064   PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0)
00065   {
00066     this->cs->savegame_mutex = ThreadMutex::New();
00067   }
00068 
00070   ~PacketWriter()
00071   {
00072     /* Prevent double frees. */
00073     if (this->cs != NULL) {
00074       if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->BeginCritical();
00075       this->cs->savegame = NULL;
00076       if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->EndCritical();
00077 
00078       delete this->cs->savegame_mutex;
00079       this->cs->savegame_mutex = NULL;
00080     }
00081 
00082     delete this->current;
00083   }
00084 
00086   void AppendQueue()
00087   {
00088     if (this->current == NULL) return;
00089 
00090     Packet **p = &this->cs->savegame_packets;
00091     while (*p != NULL) {
00092       p = &(*p)->next;
00093     }
00094     *p = this->current;
00095 
00096     this->current = NULL;
00097   }
00098 
00099   /* virtual */ void Write(byte *buf, size_t size)
00100   {
00101     /* We want to abort the saving when the socket is closed. */
00102     if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
00103 
00104     if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA);
00105 
00106     if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->BeginCritical();
00107 
00108     byte *bufe = buf + size;
00109     while (buf != bufe) {
00110       size_t to_write = min(SEND_MTU - this->current->size, bufe - buf);
00111       memcpy(this->current->buffer + this->current->size, buf, to_write);
00112       this->current->size += (PacketSize)to_write;
00113       buf += to_write;
00114 
00115       if (this->current->size == SEND_MTU) {
00116         this->AppendQueue();
00117         if (buf != bufe) this->current = new Packet(PACKET_SERVER_MAP_DATA);
00118       }
00119     }
00120 
00121     if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->EndCritical();
00122 
00123     this->total_size += size;
00124   }
00125 
00126   /* virtual */ void Finish()
00127   {
00128     /* We want to abort the saving when the socket is closed. */
00129     if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
00130 
00131     if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->BeginCritical();
00132 
00133     /* Make sure the last packet is flushed. */
00134     this->AppendQueue();
00135 
00136     /* Add a packet stating that this is the end to the queue. */
00137     this->current = new Packet(PACKET_SERVER_MAP_DONE);
00138     this->AppendQueue();
00139 
00140     /* Fast-track the size to the client. */
00141     Packet *p = new Packet(PACKET_SERVER_MAP_SIZE);
00142     p->Send_uint32((uint32)this->total_size);
00143     this->cs->NetworkTCPSocketHandler::SendPacket(p);
00144 
00145     if (this->cs->savegame_mutex != NULL) this->cs->savegame_mutex->EndCritical();
00146   }
00147 };
00148 
00149 
00154 ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s)
00155 {
00156   this->status = STATUS_INACTIVE;
00157   this->client_id = _network_client_id++;
00158   this->receive_limit = _settings_client.network.bytes_per_frame_burst;
00159 
00160   /* The Socket and Info pools need to be the same in size. After all,
00161    * each Socket will be associated with at most one Info object. As
00162    * such if the Socket was allocated the Info object can as well. */
00163   assert_compile(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE);
00164   assert(NetworkClientInfo::CanAllocateItem());
00165 
00166   NetworkClientInfo *ci = new NetworkClientInfo(this->client_id);
00167   this->SetInfo(ci);
00168   ci->client_playas = COMPANY_INACTIVE_CLIENT;
00169   ci->join_date = _date;
00170 }
00171 
00175 ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler()
00176 {
00177   if (_redirect_console_to_client == this->client_id) _redirect_console_to_client = INVALID_CLIENT_ID;
00178   OrderBackup::ResetUser(this->client_id);
00179 
00180   if (this->savegame_mutex != NULL) this->savegame_mutex->BeginCritical();
00181   if (this->savegame != NULL) this->savegame->cs = NULL;
00182   if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
00183 
00184   /* Make sure the saving is completely cancelled.
00185    * Yes, we need to handle the save finish as well
00186    * as the next connection in this "loop" might
00187    * just be requesting the map and such. */
00188   WaitTillSaved();
00189   ProcessAsyncSaveFinish();
00190 
00191   while (this->savegame_packets != NULL) {
00192     Packet *p = this->savegame_packets->next;
00193     delete this->savegame_packets;
00194     this->savegame_packets = p;
00195   }
00196 
00197   delete this->savegame_mutex;
00198 }
00199 
00200 Packet *ServerNetworkGameSocketHandler::ReceivePacket()
00201 {
00202   /* Only allow receiving when we have some buffer free; this value
00203    * can go negative, but eventually it will become positive again. */
00204   if (this->receive_limit <= 0) return NULL;
00205 
00206   /* We can receive a packet, so try that and if needed account for
00207    * the amount of received data. */
00208   Packet *p = this->NetworkTCPSocketHandler::ReceivePacket();
00209   if (p != NULL) this->receive_limit -= p->size;
00210   return p;
00211 }
00212 
00213 void ServerNetworkGameSocketHandler::SendPacket(Packet *packet)
00214 {
00215   if (this->savegame_mutex != NULL) this->savegame_mutex->BeginCritical();
00216   this->NetworkTCPSocketHandler::SendPacket(packet);
00217   if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
00218 }
00219 
00220 NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
00221 {
00222   assert(status != NETWORK_RECV_STATUS_OKAY);
00223   /*
00224    * Sending a message just before leaving the game calls cs->SendPackets.
00225    * This might invoke this function, which means that when we close the
00226    * connection after cs->SendPackets we will close an already closed
00227    * connection. This handles that case gracefully without having to make
00228    * that code any more complex or more aware of the validity of the socket.
00229    */
00230   if (this->sock == INVALID_SOCKET) return status;
00231 
00232   if (status != NETWORK_RECV_STATUS_CONN_LOST && !this->HasClientQuit() && this->status >= STATUS_AUTHORIZED) {
00233     /* We did not receive a leave message from this client... */
00234     char client_name[NETWORK_CLIENT_NAME_LENGTH];
00235     NetworkClientSocket *new_cs;
00236 
00237     this->GetClientName(client_name, sizeof(client_name));
00238 
00239     NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
00240 
00241     /* Inform other clients of this... strange leaving ;) */
00242     FOR_ALL_CLIENT_SOCKETS(new_cs) {
00243       if (new_cs->status > STATUS_AUTHORIZED && this != new_cs) {
00244         new_cs->SendErrorQuit(this->client_id, NETWORK_ERROR_CONNECTION_LOST);
00245       }
00246     }
00247   }
00248 
00249   DEBUG(net, 1, "Closed client connection %d", this->client_id);
00250 
00251   /* We just lost one client :( */
00252   if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
00253   extern byte _network_clients_connected;
00254   _network_clients_connected--;
00255 
00256   SetWindowDirty(WC_CLIENT_LIST, 0);
00257 
00258   this->SendPackets(true);
00259 
00260   delete this->GetInfo();
00261   delete this;
00262 
00263   return status;
00264 }
00265 
00270 /* static */ bool ServerNetworkGameSocketHandler::AllowConnection()
00271 {
00272   extern byte _network_clients_connected;
00273   bool accept = _network_clients_connected < MAX_CLIENTS && _network_game_info.clients_on < _settings_client.network.max_clients;
00274 
00275   /* We can't go over the MAX_CLIENTS limit here. However, the
00276    * pool must have place for all clients and ourself. */
00277   assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1);
00278   assert(ServerNetworkGameSocketHandler::CanAllocateItem());
00279   return accept;
00280 }
00281 
00283 /* static */ void ServerNetworkGameSocketHandler::Send()
00284 {
00285   NetworkClientSocket *cs;
00286   FOR_ALL_CLIENT_SOCKETS(cs) {
00287     if (cs->writable) {
00288       if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) {
00289         /* This client is in the middle of a map-send, call the function for that */
00290         cs->SendMap();
00291       }
00292     }
00293   }
00294 }
00295 
00296 static void NetworkHandleCommandQueue(NetworkClientSocket *cs);
00297 
00298 /***********
00299  * Sending functions
00300  *   DEF_SERVER_SEND_COMMAND has parameter: NetworkClientSocket *cs
00301  ************/
00302 
00303 NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientInfo *ci)
00304 {
00305   if (ci->client_id != INVALID_CLIENT_ID) {
00306     Packet *p = new Packet(PACKET_SERVER_CLIENT_INFO);
00307     p->Send_uint32(ci->client_id);
00308     p->Send_uint8 (ci->client_playas);
00309     p->Send_string(ci->client_name);
00310 
00311     this->SendPacket(p);
00312   }
00313   return NETWORK_RECV_STATUS_OKAY;
00314 }
00315 
00316 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo()
00317 {
00318   /* Fetch the latest version of the stats */
00319   NetworkCompanyStats company_stats[MAX_COMPANIES];
00320   NetworkPopulateCompanyStats(company_stats);
00321 
00322   /* Make a list of all clients per company */
00323   char clients[MAX_COMPANIES][NETWORK_CLIENTS_LENGTH];
00324   NetworkClientSocket *csi;
00325   memset(clients, 0, sizeof(clients));
00326 
00327   /* Add the local player (if not dedicated) */
00328   const NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
00329   if (ci != NULL && Company::IsValidID(ci->client_playas)) {
00330     strecpy(clients[ci->client_playas], ci->client_name, lastof(clients[ci->client_playas]));
00331   }
00332 
00333   FOR_ALL_CLIENT_SOCKETS(csi) {
00334     char client_name[NETWORK_CLIENT_NAME_LENGTH];
00335 
00336     ((ServerNetworkGameSocketHandler*)csi)->GetClientName(client_name, sizeof(client_name));
00337 
00338     ci = csi->GetInfo();
00339     if (ci != NULL && Company::IsValidID(ci->client_playas)) {
00340       if (!StrEmpty(clients[ci->client_playas])) {
00341         strecat(clients[ci->client_playas], ", ", lastof(clients[ci->client_playas]));
00342       }
00343 
00344       strecat(clients[ci->client_playas], client_name, lastof(clients[ci->client_playas]));
00345     }
00346   }
00347 
00348   /* Now send the data */
00349 
00350   Company *company;
00351   Packet *p;
00352 
00353   FOR_ALL_COMPANIES(company) {
00354     p = new Packet(PACKET_SERVER_COMPANY_INFO);
00355 
00356     p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
00357     p->Send_bool  (true);
00358     this->SendCompanyInformation(p, company, &company_stats[company->index]);
00359 
00360     if (StrEmpty(clients[company->index])) {
00361       p->Send_string("<none>");
00362     } else {
00363       p->Send_string(clients[company->index]);
00364     }
00365 
00366     this->SendPacket(p);
00367   }
00368 
00369   p = new Packet(PACKET_SERVER_COMPANY_INFO);
00370 
00371   p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
00372   p->Send_bool  (false);
00373 
00374   this->SendPacket(p);
00375   return NETWORK_RECV_STATUS_OKAY;
00376 }
00377 
00378 NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error)
00379 {
00380   char str[100];
00381   Packet *p = new Packet(PACKET_SERVER_ERROR);
00382 
00383   p->Send_uint8(error);
00384   this->SendPacket(p);
00385 
00386   StringID strid = GetNetworkErrorMsg(error);
00387   GetString(str, strid, lastof(str));
00388 
00389   /* Only send when the current client was in game */
00390   if (this->status > STATUS_AUTHORIZED) {
00391     NetworkClientSocket *new_cs;
00392     char client_name[NETWORK_CLIENT_NAME_LENGTH];
00393 
00394     this->GetClientName(client_name, sizeof(client_name));
00395 
00396     DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
00397 
00398     NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid);
00399 
00400     FOR_ALL_CLIENT_SOCKETS(new_cs) {
00401       if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
00402         /* Some errors we filter to a more general error. Clients don't have to know the real
00403          *  reason a joining failed. */
00404         if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) {
00405           error = NETWORK_ERROR_ILLEGAL_PACKET;
00406         }
00407         new_cs->SendErrorQuit(this->client_id, error);
00408       }
00409     }
00410 
00411     NetworkAdminClientError(this->client_id, error);
00412   } else {
00413     DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", this->client_id, str);
00414   }
00415 
00416   /* The client made a mistake, so drop his connection now! */
00417   return this->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
00418 }
00419 
00420 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
00421 {
00422   Packet *p = new Packet(PACKET_SERVER_CHECK_NEWGRFS);
00423   const GRFConfig *c;
00424   uint grf_count = 0;
00425 
00426   for (c = _grfconfig; c != NULL; c = c->next) {
00427     if (!HasBit(c->flags, GCF_STATIC)) grf_count++;
00428   }
00429 
00430   p->Send_uint8 (grf_count);
00431   for (c = _grfconfig; c != NULL; c = c->next) {
00432     if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
00433   }
00434 
00435   this->SendPacket(p);
00436   return NETWORK_RECV_STATUS_OKAY;
00437 }
00438 
00439 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
00440 {
00441   /* Invalid packet when status is STATUS_AUTH_GAME or higher */
00442   if (this->status >= STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
00443 
00444   this->status = STATUS_AUTH_GAME;
00445 
00446   Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
00447   this->SendPacket(p);
00448   return NETWORK_RECV_STATUS_OKAY;
00449 }
00450 
00451 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
00452 {
00453   /* Invalid packet when status is STATUS_AUTH_COMPANY or higher */
00454   if (this->status >= STATUS_AUTH_COMPANY) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
00455 
00456   this->status = STATUS_AUTH_COMPANY;
00457 
00458   Packet *p = new Packet(PACKET_SERVER_NEED_COMPANY_PASSWORD);
00459   p->Send_uint32(_settings_game.game_creation.generation_seed);
00460   p->Send_string(_settings_client.network.network_id);
00461   this->SendPacket(p);
00462   return NETWORK_RECV_STATUS_OKAY;
00463 }
00464 
00465 NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
00466 {
00467   Packet *p;
00468   NetworkClientSocket *new_cs;
00469 
00470   /* Invalid packet when status is AUTH or higher */
00471   if (this->status >= STATUS_AUTHORIZED) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
00472 
00473   this->status = STATUS_AUTHORIZED;
00474   _network_game_info.clients_on++;
00475 
00476   p = new Packet(PACKET_SERVER_WELCOME);
00477   p->Send_uint32(this->client_id);
00478   p->Send_uint32(_settings_game.game_creation.generation_seed);
00479   p->Send_string(_settings_client.network.network_id);
00480   this->SendPacket(p);
00481 
00482   /* Transmit info about all the active clients */
00483   FOR_ALL_CLIENT_SOCKETS(new_cs) {
00484     if (new_cs != this && new_cs->status > STATUS_AUTHORIZED) {
00485       this->SendClientInfo(new_cs->GetInfo());
00486     }
00487   }
00488   /* Also send the info of the server */
00489   return this->SendClientInfo(NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER));
00490 }
00491 
00492 NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait()
00493 {
00494   int waiting = 0;
00495   NetworkClientSocket *new_cs;
00496   Packet *p;
00497 
00498   /* Count how many clients are waiting in the queue */
00499   FOR_ALL_CLIENT_SOCKETS(new_cs) {
00500     if (new_cs->status == STATUS_MAP_WAIT) waiting++;
00501   }
00502 
00503   p = new Packet(PACKET_SERVER_WAIT);
00504   p->Send_uint8(waiting);
00505   this->SendPacket(p);
00506   return NETWORK_RECV_STATUS_OKAY;
00507 }
00508 
00509 /* This sends the map to the client */
00510 NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
00511 {
00512   static uint sent_packets; // How many packets we did send succecfully last time
00513 
00514   if (this->status < STATUS_AUTHORIZED) {
00515     /* Illegal call, return error and ignore the packet */
00516     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
00517   }
00518 
00519   if (this->status == STATUS_AUTHORIZED) {
00520     this->savegame = new PacketWriter(this);
00521 
00522     /* Now send the _frame_counter and how many packets are coming */
00523     Packet *p = new Packet(PACKET_SERVER_MAP_BEGIN);
00524     p->Send_uint32(_frame_counter);
00525     this->SendPacket(p);
00526 
00527     NetworkSyncCommandQueue(this);
00528     this->status = STATUS_MAP;
00529     /* Mark the start of download */
00530     this->last_frame = _frame_counter;
00531     this->last_frame_server = _frame_counter;
00532 
00533     sent_packets = 4; // We start with trying 4 packets
00534 
00535     /* Make a dump of the current game */
00536     if (SaveWithFilter(this->savegame, true) != SL_OK) usererror("network savedump failed");
00537   }
00538 
00539   if (this->status == STATUS_MAP) {
00540     if (this->savegame_mutex != NULL) this->savegame_mutex->BeginCritical();
00541 
00542     for (uint i = 0; i < sent_packets && this->savegame_packets != NULL; i++) {
00543       Packet *p = this->savegame_packets;
00544       bool last_packet = p->buffer[2] == PACKET_SERVER_MAP_DONE;
00545 
00546       /* Remove the packet from the savegame queue and put it in the real queue. */
00547       this->savegame_packets = p->next;
00548       p->next = NULL;
00549       this->NetworkTCPSocketHandler::SendPacket(p);
00550 
00551       if (last_packet) {
00552         /* Done reading! */
00553 
00554         /* Set the status to DONE_MAP, no we will wait for the client
00555          *  to send it is ready (maybe that happens like never ;)) */
00556         this->status = STATUS_DONE_MAP;
00557 
00558         NetworkClientSocket *new_cs;
00559         bool new_map_client = false;
00560         /* Check if there is a client waiting for receiving the map
00561          *  and start sending him the map */
00562         FOR_ALL_CLIENT_SOCKETS(new_cs) {
00563           if (new_cs->status == STATUS_MAP_WAIT) {
00564             /* Check if we already have a new client to send the map to */
00565             if (!new_map_client) {
00566               /* If not, this client will get the map */
00567               new_cs->status = STATUS_AUTHORIZED;
00568               new_map_client = true;
00569               new_cs->SendMap();
00570             } else {
00571               /* Else, send the other clients how many clients are in front of them */
00572               new_cs->SendWait();
00573             }
00574           }
00575         }
00576 
00577         /* There is no more data, so break the for */
00578         break;
00579       }
00580     }
00581 
00582     if (this->savegame_mutex != NULL) this->savegame_mutex->EndCritical();
00583 
00584     switch (this->SendPackets()) {
00585       case SPS_CLOSED:
00586         return NETWORK_RECV_STATUS_CONN_LOST;
00587 
00588       case SPS_ALL_SENT:
00589         /* All are sent, increase the sent_packets */
00590         if (this->savegame_packets != NULL) sent_packets *= 2;
00591         break;
00592 
00593       case SPS_PARTLY_SENT:
00594         /* Only a part is sent; leave the transmission state. */
00595         break;
00596 
00597       case SPS_NONE_SENT:
00598         /* Not everything is sent, decrease the sent_packets */
00599         if (sent_packets > 1) sent_packets /= 2;
00600         break;
00601     }
00602   }
00603   return NETWORK_RECV_STATUS_OKAY;
00604 }
00605 
00606 NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id)
00607 {
00608   Packet *p = new Packet(PACKET_SERVER_JOIN);
00609 
00610   p->Send_uint32(client_id);
00611 
00612   this->SendPacket(p);
00613   return NETWORK_RECV_STATUS_OKAY;
00614 }
00615 
00616 
00617 NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame()
00618 {
00619   Packet *p = new Packet(PACKET_SERVER_FRAME);
00620   p->Send_uint32(_frame_counter);
00621   p->Send_uint32(_frame_counter_max);
00622 #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
00623   p->Send_uint32(_sync_seed_1);
00624 #ifdef NETWORK_SEND_DOUBLE_SEED
00625   p->Send_uint32(_sync_seed_2);
00626 #endif
00627 #endif
00628 
00629   /* If token equals 0, we need to make a new token and send that. */
00630   if (this->last_token == 0) {
00631     this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1;
00632     p->Send_uint8(this->last_token);
00633   }
00634 
00635   this->SendPacket(p);
00636   return NETWORK_RECV_STATUS_OKAY;
00637 }
00638 
00639 NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync()
00640 {
00641   Packet *p = new Packet(PACKET_SERVER_SYNC);
00642   p->Send_uint32(_frame_counter);
00643   p->Send_uint32(_sync_seed_1);
00644 
00645 #ifdef NETWORK_SEND_DOUBLE_SEED
00646   p->Send_uint32(_sync_seed_2);
00647 #endif
00648   this->SendPacket(p);
00649   return NETWORK_RECV_STATUS_OKAY;
00650 }
00651 
00652 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCommand(const CommandPacket *cp)
00653 {
00654   Packet *p = new Packet(PACKET_SERVER_COMMAND);
00655 
00656   this->NetworkGameSocketHandler::SendCommand(p, cp);
00657   p->Send_uint32(cp->frame);
00658   p->Send_bool  (cp->my_cmd);
00659 
00660   this->SendPacket(p);
00661   return NETWORK_RECV_STATUS_OKAY;
00662 }
00663 
00664 NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, int64 data)
00665 {
00666   Packet *p = new Packet(PACKET_SERVER_CHAT);
00667 
00668   p->Send_uint8 (action);
00669   p->Send_uint32(client_id);
00670   p->Send_bool  (self_send);
00671   p->Send_string(msg);
00672   p->Send_uint64(data);
00673 
00674   this->SendPacket(p);
00675   return NETWORK_RECV_STATUS_OKAY;
00676 }
00677 
00678 NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_id, NetworkErrorCode errorno)
00679 {
00680   Packet *p = new Packet(PACKET_SERVER_ERROR_QUIT);
00681 
00682   p->Send_uint32(client_id);
00683   p->Send_uint8 (errorno);
00684 
00685   this->SendPacket(p);
00686   return NETWORK_RECV_STATUS_OKAY;
00687 }
00688 
00689 NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id)
00690 {
00691   Packet *p = new Packet(PACKET_SERVER_QUIT);
00692 
00693   p->Send_uint32(client_id);
00694 
00695   this->SendPacket(p);
00696   return NETWORK_RECV_STATUS_OKAY;
00697 }
00698 
00699 NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown()
00700 {
00701   Packet *p = new Packet(PACKET_SERVER_SHUTDOWN);
00702   this->SendPacket(p);
00703   return NETWORK_RECV_STATUS_OKAY;
00704 }
00705 
00706 NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame()
00707 {
00708   Packet *p = new Packet(PACKET_SERVER_NEWGAME);
00709   this->SendPacket(p);
00710   return NETWORK_RECV_STATUS_OKAY;
00711 }
00712 
00713 NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16 colour, const char *command)
00714 {
00715   Packet *p = new Packet(PACKET_SERVER_RCON);
00716 
00717   p->Send_uint16(colour);
00718   p->Send_string(command);
00719   this->SendPacket(p);
00720   return NETWORK_RECV_STATUS_OKAY;
00721 }
00722 
00723 NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, CompanyID company_id)
00724 {
00725   Packet *p = new Packet(PACKET_SERVER_MOVE);
00726 
00727   p->Send_uint32(client_id);
00728   p->Send_uint8(company_id);
00729   this->SendPacket(p);
00730   return NETWORK_RECV_STATUS_OKAY;
00731 }
00732 
00733 NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate()
00734 {
00735   Packet *p = new Packet(PACKET_SERVER_COMPANY_UPDATE);
00736 
00737   p->Send_uint16(_network_company_passworded);
00738   this->SendPacket(p);
00739   return NETWORK_RECV_STATUS_OKAY;
00740 }
00741 
00742 NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate()
00743 {
00744   Packet *p = new Packet(PACKET_SERVER_CONFIG_UPDATE);
00745 
00746   p->Send_uint8(_settings_client.network.max_companies);
00747   p->Send_uint8(_settings_client.network.max_spectators);
00748   this->SendPacket(p);
00749   return NETWORK_RECV_STATUS_OKAY;
00750 }
00751 
00752 /***********
00753  * Receiving functions
00754  *   DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p
00755  ************/
00756 
00757 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_COMPANY_INFO)
00758 {
00759   return this->SendCompanyInfo();
00760 }
00761 
00762 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_NEWGRFS_CHECKED)
00763 {
00764   if (this->status != STATUS_NEWGRFS_CHECK) {
00765     /* Illegal call, return error and ignore the packet */
00766     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00767   }
00768 
00769   NetworkClientInfo *ci = this->GetInfo();
00770 
00771   /* We now want a password from the client else we do not allow him in! */
00772   if (!StrEmpty(_settings_client.network.server_password)) {
00773     return this->SendNeedGamePassword();
00774   }
00775 
00776   if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
00777     return this->SendNeedCompanyPassword();
00778   }
00779 
00780   return this->SendWelcome();
00781 }
00782 
00783 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_JOIN)
00784 {
00785   if (this->status != STATUS_INACTIVE) {
00786     /* Illegal call, return error and ignore the packet */
00787     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00788   }
00789 
00790   char name[NETWORK_CLIENT_NAME_LENGTH];
00791   NetworkClientInfo *ci;
00792   CompanyID playas;
00793   NetworkLanguage client_lang;
00794   char client_revision[NETWORK_REVISION_LENGTH];
00795 
00796   p->Recv_string(client_revision, sizeof(client_revision));
00797 
00798   /* Check if the client has revision control enabled */
00799   if (!IsNetworkCompatibleVersion(client_revision)) {
00800     /* Different revisions!! */
00801     return this->SendError(NETWORK_ERROR_WRONG_REVISION);
00802   }
00803 
00804   p->Recv_string(name, sizeof(name));
00805   playas = (Owner)p->Recv_uint8();
00806   client_lang = (NetworkLanguage)p->Recv_uint8();
00807 
00808   if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
00809 
00810   /* join another company does not affect these values */
00811   switch (playas) {
00812     case COMPANY_NEW_COMPANY: // New company
00813       if (Company::GetNumItems() >= _settings_client.network.max_companies) {
00814         return this->SendError(NETWORK_ERROR_FULL);
00815       }
00816       break;
00817     case COMPANY_SPECTATOR: // Spectator
00818       if (NetworkSpectatorCount() >= _settings_client.network.max_spectators) {
00819         return this->SendError(NETWORK_ERROR_FULL);
00820       }
00821       break;
00822     default: // Join another company (companies 1-8 (index 0-7))
00823       if (!Company::IsValidHumanID(playas)) {
00824         return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
00825       }
00826       break;
00827   }
00828 
00829   /* We need a valid name.. make it Player */
00830   if (StrEmpty(name)) strecpy(name, "Player", lastof(name));
00831 
00832   if (!NetworkFindName(name)) { // Change name if duplicate
00833     /* We could not create a name for this client */
00834     return this->SendError(NETWORK_ERROR_NAME_IN_USE);
00835   }
00836 
00837   ci = this->GetInfo();
00838 
00839   strecpy(ci->client_name, name, lastof(ci->client_name));
00840   ci->client_playas = playas;
00841   ci->client_lang = client_lang;
00842   DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, ci->index);
00843 
00844   /* Make sure companies to which people try to join are not autocleaned */
00845   if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0;
00846 
00847   this->status = STATUS_NEWGRFS_CHECK;
00848 
00849   if (_grfconfig == NULL) {
00850     /* Behave as if we received PACKET_CLIENT_NEWGRFS_CHECKED */
00851     return this->NetworkPacketReceive_PACKET_CLIENT_NEWGRFS_CHECKED_command(NULL);
00852   }
00853 
00854   return this->SendNewGRFCheck();
00855 }
00856 
00857 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_GAME_PASSWORD)
00858 {
00859   if (this->status != STATUS_AUTH_GAME) {
00860     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00861   }
00862 
00863   char password[NETWORK_PASSWORD_LENGTH];
00864   p->Recv_string(password, sizeof(password));
00865 
00866   /* Check game password. Allow joining if we cleared the password meanwhile */
00867   if (!StrEmpty(_settings_client.network.server_password) &&
00868       strcmp(password, _settings_client.network.server_password) != 0) {
00869     /* Password is invalid */
00870     return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
00871   }
00872 
00873   const NetworkClientInfo *ci = this->GetInfo();
00874   if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) {
00875     return this->SendNeedCompanyPassword();
00876   }
00877 
00878   /* Valid password, allow user */
00879   return this->SendWelcome();
00880 }
00881 
00882 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_COMPANY_PASSWORD)
00883 {
00884   if (this->status != STATUS_AUTH_COMPANY) {
00885     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00886   }
00887 
00888   char password[NETWORK_PASSWORD_LENGTH];
00889   p->Recv_string(password, sizeof(password));
00890 
00891   /* Check company password. Allow joining if we cleared the password meanwhile.
00892    * Also, check the company is still valid - client could be moved to spectators
00893    * in the middle of the authorization process */
00894   CompanyID playas = this->GetInfo()->client_playas;
00895   if (Company::IsValidID(playas) && !StrEmpty(_network_company_states[playas].password) &&
00896       strcmp(password, _network_company_states[playas].password) != 0) {
00897     /* Password is invalid */
00898     return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
00899   }
00900 
00901   return this->SendWelcome();
00902 }
00903 
00904 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_GETMAP)
00905 {
00906   NetworkClientSocket *new_cs;
00907 
00908   /* Do an extra version match. We told the client our version already,
00909    * lets confirm that the client isn't lieing to us.
00910    * But only do it for stable releases because of those we are sure
00911    * that everybody has the same NewGRF version. For trunk and the
00912    * branches we make tarballs of the OpenTTDs compiled from tarball
00913    * will have the lower bits set to 0. As such they would become
00914    * incompatible, which we would like to prevent by this. */
00915   if (HasBit(_openttd_newgrf_version, 19)) {
00916     if (_openttd_newgrf_version != p->Recv_uint32()) {
00917       /* The version we get from the client differs, it must have the
00918        * wrong version. The client must be wrong. */
00919       return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00920     }
00921   } else if (p->size != 3) {
00922     /* We received a packet from a version that claims to be stable.
00923      * That shouldn't happen. The client must be wrong. */
00924     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00925   }
00926 
00927   /* The client was never joined.. so this is impossible, right?
00928    *  Ignore the packet, give the client a warning, and close his connection */
00929   if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) {
00930     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
00931   }
00932 
00933   /* Check if someone else is receiving the map */
00934   FOR_ALL_CLIENT_SOCKETS(new_cs) {
00935     if (new_cs->status == STATUS_MAP) {
00936       /* Tell the new client to wait */
00937       this->status = STATUS_MAP_WAIT;
00938       return this->SendWait();
00939     }
00940   }
00941 
00942   /* We receive a request to upload the map.. give it to the client! */
00943   return this->SendMap();
00944 }
00945 
00946 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_MAP_OK)
00947 {
00948   /* Client has the map, now start syncing */
00949   if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) {
00950     char client_name[NETWORK_CLIENT_NAME_LENGTH];
00951     NetworkClientSocket *new_cs;
00952 
00953     this->GetClientName(client_name, sizeof(client_name));
00954 
00955     NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, NULL, this->client_id);
00956 
00957     /* Mark the client as pre-active, and wait for an ACK
00958      *  so we know he is done loading and in sync with us */
00959     this->status = STATUS_PRE_ACTIVE;
00960     NetworkHandleCommandQueue(this);
00961     this->SendFrame();
00962     this->SendSync();
00963 
00964     /* This is the frame the client receives
00965      *  we need it later on to make sure the client is not too slow */
00966     this->last_frame = _frame_counter;
00967     this->last_frame_server = _frame_counter;
00968 
00969     FOR_ALL_CLIENT_SOCKETS(new_cs) {
00970       if (new_cs->status > STATUS_AUTHORIZED) {
00971         new_cs->SendClientInfo(this->GetInfo());
00972         new_cs->SendJoin(this->client_id);
00973       }
00974     }
00975 
00976     NetworkAdminClientInfo(this->GetInfo(), true);
00977 
00978     /* also update the new client with our max values */
00979     this->SendConfigUpdate();
00980 
00981     /* quickly update the syncing client with company details */
00982     return this->SendCompanyUpdate();
00983   }
00984 
00985   /* Wrong status for this packet, give a warning to client, and close connection */
00986   return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00987 }
00988 
00993 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_COMMAND)
00994 {
00995   /* The client was never joined.. so this is impossible, right?
00996    *  Ignore the packet, give the client a warning, and close his connection */
00997   if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
00998     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
00999   }
01000 
01001   if (this->incoming_queue.Count() >= _settings_client.network.max_commands_in_queue) {
01002     return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
01003   }
01004 
01005   CommandPacket cp;
01006   const char *err = this->ReceiveCommand(p, &cp);
01007 
01008   if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
01009 
01010   NetworkClientInfo *ci = this->GetInfo();
01011 
01012   if (err != NULL) {
01013     IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, GetClientIP(ci));
01014     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01015   }
01016 
01017 
01018   if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER) {
01019     IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, GetClientIP(ci));
01020     return this->SendError(NETWORK_ERROR_KICKED);
01021   }
01022 
01023   if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) {
01024     IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_id, GetClientIP(ci));
01025     return this->SendError(NETWORK_ERROR_KICKED);
01026   }
01027 
01033   if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
01034     IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
01035                    ci->client_playas + 1, GetClientIP(ci), cp.company + 1);
01036     return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
01037   }
01038 
01039   if (cp.cmd == CMD_COMPANY_CTRL) {
01040     if (cp.p1 != 0 || cp.company != COMPANY_SPECTATOR) {
01041       return this->SendError(NETWORK_ERROR_CHEATER);
01042     }
01043 
01044     /* 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! */
01045     if (Company::GetNumItems() >= _settings_client.network.max_companies) {
01046       NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
01047       return NETWORK_RECV_STATUS_OKAY;
01048     }
01049   }
01050 
01051   if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) cp.p2 = this->client_id;
01052 
01053   this->incoming_queue.Append(&cp);
01054   return NETWORK_RECV_STATUS_OKAY;
01055 }
01056 
01057 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_ERROR)
01058 {
01059   /* This packets means a client noticed an error and is reporting this
01060    *  to us. Display the error and report it to the other clients */
01061   NetworkClientSocket *new_cs;
01062   char str[100];
01063   char client_name[NETWORK_CLIENT_NAME_LENGTH];
01064   NetworkErrorCode errorno = (NetworkErrorCode)p->Recv_uint8();
01065 
01066   /* The client was never joined.. thank the client for the packet, but ignore it */
01067   if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01068     return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01069   }
01070 
01071   this->GetClientName(client_name, sizeof(client_name));
01072 
01073   StringID strid = GetNetworkErrorMsg(errorno);
01074   GetString(str, strid, lastof(str));
01075 
01076   DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
01077 
01078   NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid);
01079 
01080   FOR_ALL_CLIENT_SOCKETS(new_cs) {
01081     if (new_cs->status > STATUS_AUTHORIZED) {
01082       new_cs->SendErrorQuit(this->client_id, errorno);
01083     }
01084   }
01085 
01086   NetworkAdminClientError(this->client_id, errorno);
01087 
01088   return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01089 }
01090 
01091 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_QUIT)
01092 {
01093   /* The client wants to leave. Display this and report it to the other
01094    *  clients. */
01095   NetworkClientSocket *new_cs;
01096   char client_name[NETWORK_CLIENT_NAME_LENGTH];
01097 
01098   /* The client was never joined.. thank the client for the packet, but ignore it */
01099   if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
01100     return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01101   }
01102 
01103   this->GetClientName(client_name, sizeof(client_name));
01104 
01105   NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING);
01106 
01107   FOR_ALL_CLIENT_SOCKETS(new_cs) {
01108     if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
01109       new_cs->SendQuit(this->client_id);
01110     }
01111   }
01112 
01113   NetworkAdminClientQuit(this->client_id);
01114 
01115   return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST);
01116 }
01117 
01118 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_ACK)
01119 {
01120   if (this->status < STATUS_AUTHORIZED) {
01121     /* Illegal call, return error and ignore the packet */
01122     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
01123   }
01124 
01125   uint32 frame = p->Recv_uint32();
01126 
01127   /* The client is trying to catch up with the server */
01128   if (this->status == STATUS_PRE_ACTIVE) {
01129     /* The client is not yet catched up? */
01130     if (frame + DAY_TICKS < _frame_counter) return NETWORK_RECV_STATUS_OKAY;
01131 
01132     /* Now he is! Unpause the game */
01133     this->status = STATUS_ACTIVE;
01134     this->last_token_frame = _frame_counter;
01135 
01136     /* Execute script for, e.g. MOTD */
01137     IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
01138   }
01139 
01140   /* Get, and validate the token. */
01141   uint8 token = p->Recv_uint8();
01142   if (token == this->last_token) {
01143     /* We differentiate between last_token_frame and last_frame so the lag
01144      * test uses the actual lag of the client instead of the lag for getting
01145      * the token back and forth; after all, the token is only sent every
01146      * time we receive a PACKET_CLIENT_ACK, after which we will send a new
01147      * token to the client. If the lag would be one day, then we would not
01148      * be sending the new token soon enough for the new daily scheduled
01149      * PACKET_CLIENT_ACK. This would then register the lag of the client as
01150      * two days, even when it's only a single day. */
01151     this->last_token_frame = _frame_counter;
01152     /* Request a new token. */
01153     this->last_token = 0;
01154   }
01155 
01156   /* The client received the frame, make note of it */
01157   this->last_frame = frame;
01158   /* With those 2 values we can calculate the lag realtime */
01159   this->last_frame_server = _frame_counter;
01160   return NETWORK_RECV_STATUS_OKAY;
01161 }
01162 
01163 
01164 
01165 void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, ClientID from_id, int64 data, bool from_admin)
01166 {
01167   NetworkClientSocket *cs;
01168   const NetworkClientInfo *ci, *ci_own, *ci_to;
01169 
01170   switch (desttype) {
01171     case DESTTYPE_CLIENT:
01172       /* Are we sending to the server? */
01173       if ((ClientID)dest == CLIENT_ID_SERVER) {
01174         ci = NetworkFindClientInfoFromClientID(from_id);
01175         /* Display the text locally, and that is it */
01176         if (ci != NULL) {
01177           NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01178 
01179           if (_settings_client.network.server_admin_chat) {
01180             NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01181           }
01182         }
01183       } else {
01184         /* Else find the client to send the message to */
01185         FOR_ALL_CLIENT_SOCKETS(cs) {
01186           if (cs->client_id == (ClientID)dest) {
01187             cs->SendChat(action, from_id, false, msg, data);
01188             break;
01189           }
01190         }
01191       }
01192 
01193       /* Display the message locally (so you know you have sent it) */
01194       if (from_id != (ClientID)dest) {
01195         if (from_id == CLIENT_ID_SERVER) {
01196           ci = NetworkFindClientInfoFromClientID(from_id);
01197           ci_to = NetworkFindClientInfoFromClientID((ClientID)dest);
01198           if (ci != NULL && ci_to != NULL) {
01199             NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
01200           }
01201         } else {
01202           FOR_ALL_CLIENT_SOCKETS(cs) {
01203             if (cs->client_id == from_id) {
01204               cs->SendChat(action, (ClientID)dest, true, msg, data);
01205               break;
01206             }
01207           }
01208         }
01209       }
01210       break;
01211     case DESTTYPE_TEAM: {
01212       /* If this is false, the message is already displayed on the client who sent it. */
01213       bool show_local = true;
01214       /* Find all clients that belong to this company */
01215       ci_to = NULL;
01216       FOR_ALL_CLIENT_SOCKETS(cs) {
01217         ci = cs->GetInfo();
01218         if (ci->client_playas == (CompanyID)dest) {
01219           cs->SendChat(action, from_id, false, msg, data);
01220           if (cs->client_id == from_id) show_local = false;
01221           ci_to = ci; // Remember a client that is in the company for company-name
01222         }
01223       }
01224 
01225       /* if the server can read it, let the admin network read it, too. */
01226       if (_local_company == (CompanyID)dest && _settings_client.network.server_admin_chat) {
01227         NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01228       }
01229 
01230       ci = NetworkFindClientInfoFromClientID(from_id);
01231       ci_own = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
01232       if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
01233         NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01234         if (from_id == CLIENT_ID_SERVER) show_local = false;
01235         ci_to = ci_own;
01236       }
01237 
01238       /* There is no such client */
01239       if (ci_to == NULL) break;
01240 
01241       /* Display the message locally (so you know you have sent it) */
01242       if (ci != NULL && show_local) {
01243         if (from_id == CLIENT_ID_SERVER) {
01244           char name[NETWORK_NAME_LENGTH];
01245           StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
01246           SetDParam(0, ci_to->client_playas);
01247           GetString(name, str, lastof(name));
01248           NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data);
01249         } else {
01250           FOR_ALL_CLIENT_SOCKETS(cs) {
01251             if (cs->client_id == from_id) {
01252               cs->SendChat(action, ci_to->client_id, true, msg, data);
01253             }
01254           }
01255         }
01256       }
01257       break;
01258     }
01259     default:
01260       DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
01261       /* FALL THROUGH */
01262     case DESTTYPE_BROADCAST:
01263       FOR_ALL_CLIENT_SOCKETS(cs) {
01264         cs->SendChat(action, from_id, false, msg, data);
01265       }
01266 
01267       NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
01268 
01269       ci = NetworkFindClientInfoFromClientID(from_id);
01270       if (ci != NULL) {
01271         NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
01272       }
01273       break;
01274   }
01275 }
01276 
01277 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_CHAT)
01278 {
01279   if (this->status < STATUS_AUTHORIZED) {
01280     /* Illegal call, return error and ignore the packet */
01281     return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED);
01282   }
01283 
01284   NetworkAction action = (NetworkAction)p->Recv_uint8();
01285   DestType desttype = (DestType)p->Recv_uint8();
01286   int dest = p->Recv_uint32();
01287   char msg[NETWORK_CHAT_LENGTH];
01288 
01289   p->Recv_string(msg, NETWORK_CHAT_LENGTH);
01290   int64 data = p->Recv_uint64();
01291 
01292   NetworkClientInfo *ci = this->GetInfo();
01293   switch (action) {
01294     case NETWORK_ACTION_GIVE_MONEY:
01295       if (!Company::IsValidID(ci->client_playas)) break;
01296       /* FALL THROUGH */
01297     case NETWORK_ACTION_CHAT:
01298     case NETWORK_ACTION_CHAT_CLIENT:
01299     case NETWORK_ACTION_CHAT_COMPANY:
01300       NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
01301       break;
01302     default:
01303       IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, GetClientIP(ci));
01304       return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01305   }
01306   return NETWORK_RECV_STATUS_OKAY;
01307 }
01308 
01309 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_SET_PASSWORD)
01310 {
01311   if (this->status != STATUS_ACTIVE) {
01312     /* Illegal call, return error and ignore the packet */
01313     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01314   }
01315 
01316   char password[NETWORK_PASSWORD_LENGTH];
01317   const NetworkClientInfo *ci;
01318 
01319   p->Recv_string(password, sizeof(password));
01320   ci = this->GetInfo();
01321 
01322   NetworkServerSetCompanyPassword(ci->client_playas, password);
01323   return NETWORK_RECV_STATUS_OKAY;
01324 }
01325 
01326 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_SET_NAME)
01327 {
01328   if (this->status != STATUS_ACTIVE) {
01329     /* Illegal call, return error and ignore the packet */
01330     return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01331   }
01332 
01333   char client_name[NETWORK_CLIENT_NAME_LENGTH];
01334   NetworkClientInfo *ci;
01335 
01336   p->Recv_string(client_name, sizeof(client_name));
01337   ci = this->GetInfo();
01338 
01339   if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
01340 
01341   if (ci != NULL) {
01342     /* Display change */
01343     if (NetworkFindName(client_name)) {
01344       NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);
01345       strecpy(ci->client_name, client_name, lastof(ci->client_name));
01346       NetworkUpdateClientInfo(ci->client_id);
01347     }
01348   }
01349   return NETWORK_RECV_STATUS_OKAY;
01350 }
01351 
01352 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_RCON)
01353 {
01354   if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01355 
01356   char pass[NETWORK_PASSWORD_LENGTH];
01357   char command[NETWORK_RCONCOMMAND_LENGTH];
01358 
01359   if (StrEmpty(_settings_client.network.rcon_password)) return NETWORK_RECV_STATUS_OKAY;
01360 
01361   p->Recv_string(pass, sizeof(pass));
01362   p->Recv_string(command, sizeof(command));
01363 
01364   if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
01365     DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
01366     return NETWORK_RECV_STATUS_OKAY;
01367   }
01368 
01369   DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", this->client_id, command);
01370 
01371   _redirect_console_to_client = this->client_id;
01372   IConsoleCmdExec(command);
01373   _redirect_console_to_client = INVALID_CLIENT_ID;
01374   return NETWORK_RECV_STATUS_OKAY;
01375 }
01376 
01377 DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_MOVE)
01378 {
01379   if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
01380 
01381   CompanyID company_id = (Owner)p->Recv_uint8();
01382 
01383   /* Check if the company is valid, we don't allow moving to AI companies */
01384   if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY;
01385 
01386   /* Check if we require a password for this company */
01387   if (company_id != COMPANY_SPECTATOR && !StrEmpty(_network_company_states[company_id].password)) {
01388     /* we need a password from the client - should be in this packet */
01389     char password[NETWORK_PASSWORD_LENGTH];
01390     p->Recv_string(password, sizeof(password));
01391 
01392     /* Incorrect password sent, return! */
01393     if (strcmp(password, _network_company_states[company_id].password) != 0) {
01394       DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", this->client_id, company_id + 1);
01395       return NETWORK_RECV_STATUS_OKAY;
01396     }
01397   }
01398 
01399   /* if we get here we can move the client */
01400   NetworkServerDoMove(this->client_id, company_id);
01401   return NETWORK_RECV_STATUS_OKAY;
01402 }
01403 
01411 void NetworkSocketHandler::SendCompanyInformation(Packet *p, const Company *c, const NetworkCompanyStats *stats, uint max_len)
01412 {
01413   /* Grab the company name */
01414   char company_name[NETWORK_COMPANY_NAME_LENGTH];
01415   SetDParam(0, c->index);
01416 
01417   assert(max_len <= lengthof(company_name));
01418   GetString(company_name, STR_COMPANY_NAME, company_name + max_len - 1);
01419 
01420   /* Get the income */
01421   Money income = 0;
01422   if (_cur_year - 1 == c->inaugurated_year) {
01423     /* The company is here just 1 year, so display [2], else display[1] */
01424     for (uint i = 0; i < lengthof(c->yearly_expenses[2]); i++) {
01425       income -= c->yearly_expenses[2][i];
01426     }
01427   } else {
01428     for (uint i = 0; i < lengthof(c->yearly_expenses[1]); i++) {
01429       income -= c->yearly_expenses[1][i];
01430     }
01431   }
01432 
01433   /* Send the information */
01434   p->Send_uint8 (c->index);
01435   p->Send_string(company_name);
01436   p->Send_uint32(c->inaugurated_year);
01437   p->Send_uint64(c->old_economy[0].company_value);
01438   p->Send_uint64(c->money);
01439   p->Send_uint64(income);
01440   p->Send_uint16(c->old_economy[0].performance_history);
01441 
01442   /* Send 1 if there is a passord for the company else send 0 */
01443   p->Send_bool  (!StrEmpty(_network_company_states[c->index].password));
01444 
01445   for (uint i = 0; i < NETWORK_VEH_END; i++) {
01446     p->Send_uint16(stats->num_vehicle[i]);
01447   }
01448 
01449   for (uint i = 0; i < NETWORK_VEH_END; i++) {
01450     p->Send_uint16(stats->num_station[i]);
01451   }
01452 
01453   p->Send_bool(c->is_ai);
01454 }
01455 
01460 void NetworkPopulateCompanyStats(NetworkCompanyStats *stats)
01461 {
01462   const Vehicle *v;
01463   const Station *s;
01464 
01465   memset(stats, 0, sizeof(*stats) * MAX_COMPANIES);
01466 
01467   /* Go through all vehicles and count the type of vehicles */
01468   FOR_ALL_VEHICLES(v) {
01469     if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
01470     byte type = 0;
01471     switch (v->type) {
01472       case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break;
01473       case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break;
01474       case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break;
01475       case VEH_SHIP: type = NETWORK_VEH_SHIP; break;
01476       default: continue;
01477     }
01478     stats[v->owner].num_vehicle[type]++;
01479   }
01480 
01481   /* Go through all stations and count the types of stations */
01482   FOR_ALL_STATIONS(s) {
01483     if (Company::IsValidID(s->owner)) {
01484       NetworkCompanyStats *npi = &stats[s->owner];
01485 
01486       if (s->facilities & FACIL_TRAIN)      npi->num_station[NETWORK_VEH_TRAIN]++;
01487       if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[NETWORK_VEH_LORRY]++;
01488       if (s->facilities & FACIL_BUS_STOP)   npi->num_station[NETWORK_VEH_BUS]++;
01489       if (s->facilities & FACIL_AIRPORT)    npi->num_station[NETWORK_VEH_PLANE]++;
01490       if (s->facilities & FACIL_DOCK)       npi->num_station[NETWORK_VEH_SHIP]++;
01491     }
01492   }
01493 }
01494 
01495 /* Send a packet to all clients with updated info about this client_id */
01496 void NetworkUpdateClientInfo(ClientID client_id)
01497 {
01498   NetworkClientSocket *cs;
01499   NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
01500 
01501   if (ci == NULL) return;
01502 
01503   DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id);
01504 
01505   FOR_ALL_CLIENT_SOCKETS(cs) {
01506     cs->SendClientInfo(ci);
01507   }
01508 
01509   NetworkAdminClientUpdate(ci);
01510 }
01511 
01512 /* Check if we want to restart the map */
01513 static void NetworkCheckRestartMap()
01514 {
01515   if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) {
01516     DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year);
01517 
01518     StartNewGameWithoutGUI(GENERATE_NEW_SEED);
01519   }
01520 }
01521 
01522 /* Check if the server has autoclean_companies activated
01523     Two things happen:
01524       1) If a company is not protected, it is closed after 1 year (for example)
01525       2) If a company is protected, protection is disabled after 3 years (for example)
01526            (and item 1. happens a year later) */
01527 static void NetworkAutoCleanCompanies()
01528 {
01529   const NetworkClientInfo *ci;
01530   const Company *c;
01531   bool clients_in_company[MAX_COMPANIES];
01532   int vehicles_in_company[MAX_COMPANIES];
01533 
01534   if (!_settings_client.network.autoclean_companies) return;
01535 
01536   memset(clients_in_company, 0, sizeof(clients_in_company));
01537 
01538   /* Detect the active companies */
01539   FOR_ALL_CLIENT_INFOS(ci) {
01540     if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
01541   }
01542 
01543   if (!_network_dedicated) {
01544     ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
01545     if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
01546   }
01547 
01548   if (_settings_client.network.autoclean_novehicles != 0) {
01549     memset(vehicles_in_company, 0, sizeof(vehicles_in_company));
01550 
01551     const Vehicle *v;
01552     FOR_ALL_VEHICLES(v) {
01553       if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue;
01554       vehicles_in_company[v->owner]++;
01555     }
01556   }
01557 
01558   /* Go through all the comapnies */
01559   FOR_ALL_COMPANIES(c) {
01560     /* Skip the non-active once */
01561     if (c->is_ai) continue;
01562 
01563     if (!clients_in_company[c->index]) {
01564       /* The company is empty for one month more */
01565       _network_company_states[c->index].months_empty++;
01566 
01567       /* Is the company empty for autoclean_unprotected-months, and is there no protection? */
01568       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)) {
01569         /* Shut the company down */
01570         DoCommandP(0, 2 | c->index << 16, 0, CMD_COMPANY_CTRL);
01571         NetworkAdminCompanyRemove(c->index, ADMIN_CRR_AUTOCLEAN);
01572         IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1);
01573       }
01574       /* Is the company empty for autoclean_protected-months, and there is a protection? */
01575       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)) {
01576         /* Unprotect the company */
01577         _network_company_states[c->index].password[0] = '\0';
01578         IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", c->index + 1);
01579         _network_company_states[c->index].months_empty = 0;
01580         NetworkServerUpdateCompanyPassworded(c->index, false);
01581       }
01582       /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
01583       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) {
01584         /* Shut the company down */
01585         DoCommandP(0, 2 | c->index << 16, 0, CMD_COMPANY_CTRL);
01586         NetworkAdminCompanyRemove(c->index, ADMIN_CRR_AUTOCLEAN);
01587         IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1);
01588       }
01589     } else {
01590       /* It is not empty, reset the date */
01591       _network_company_states[c->index].months_empty = 0;
01592     }
01593   }
01594 }
01595 
01596 /* This function changes new_name to a name that is unique (by adding #1 ...)
01597  *  and it returns true if that succeeded. */
01598 bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH])
01599 {
01600   bool found_name = false;
01601   uint number = 0;
01602   char original_name[NETWORK_CLIENT_NAME_LENGTH];
01603 
01604   /* We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer */
01605   ttd_strlcpy(original_name, new_name, NETWORK_CLIENT_NAME_LENGTH);
01606 
01607   while (!found_name) {
01608     const NetworkClientInfo *ci;
01609 
01610     found_name = true;
01611     FOR_ALL_CLIENT_INFOS(ci) {
01612       if (strcmp(ci->client_name, new_name) == 0) {
01613         /* Name already in use */
01614         found_name = false;
01615         break;
01616       }
01617     }
01618     /* Check if it is the same as the server-name */
01619     ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
01620     if (ci != NULL) {
01621       if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use
01622     }
01623 
01624     if (!found_name) {
01625       /* Try a new name (<name> #1, <name> #2, and so on) */
01626 
01627       /* Something's really wrong when there're more names than clients */
01628       if (number++ > MAX_CLIENTS) break;
01629       snprintf(new_name, NETWORK_CLIENT_NAME_LENGTH, "%s #%d", original_name, number);
01630     }
01631   }
01632 
01633   return found_name;
01634 }
01635 
01642 bool NetworkServerChangeClientName(ClientID client_id, const char *new_name)
01643 {
01644   NetworkClientInfo *ci;
01645   /* Check if the name's already in use */
01646   FOR_ALL_CLIENT_INFOS(ci) {
01647     if (strcmp(ci->client_name, new_name) == 0) return false;
01648   }
01649 
01650   ci = NetworkFindClientInfoFromClientID(client_id);
01651   if (ci == NULL) return false;
01652 
01653   NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name);
01654 
01655   strecpy(ci->client_name, new_name, lastof(ci->client_name));
01656 
01657   NetworkUpdateClientInfo(client_id);
01658   return true;
01659 }
01660 
01667 void NetworkServerSetCompanyPassword(CompanyID company_id, const char *password, bool already_hashed)
01668 {
01669   if (!Company::IsValidHumanID(company_id)) return;
01670 
01671   if (!already_hashed) {
01672     password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed);
01673   }
01674 
01675   strecpy(_network_company_states[company_id].password, password, lastof(_network_company_states[company_id].password));
01676   NetworkServerUpdateCompanyPassworded(company_id, !StrEmpty(_network_company_states[company_id].password));
01677 }
01678 
01679 /* Handle the local command-queue */
01680 static void NetworkHandleCommandQueue(NetworkClientSocket *cs)
01681 {
01682   CommandPacket *cp;
01683   while ((cp = cs->outgoing_queue.Pop()) != NULL) {
01684     cs->SendCommand(cp);
01685     free(cp);
01686   }
01687 }
01688 
01689 /* This is called every tick if this is a _network_server */
01690 void NetworkServer_Tick(bool send_frame)
01691 {
01692   NetworkClientSocket *cs;
01693 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
01694   bool send_sync = false;
01695 #endif
01696 
01697 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
01698   if (_frame_counter >= _last_sync_frame + _settings_client.network.sync_freq) {
01699     _last_sync_frame = _frame_counter;
01700     send_sync = true;
01701   }
01702 #endif
01703 
01704   /* Now we are done with the frame, inform the clients that they can
01705    *  do their frame! */
01706   FOR_ALL_CLIENT_SOCKETS(cs) {
01707     /* We allow a number of bytes per frame, but only to the burst amount
01708      * to be available for packet receiving at any particular time. */
01709     cs->receive_limit = min(cs->receive_limit + _settings_client.network.bytes_per_frame,
01710         _settings_client.network.bytes_per_frame_burst);
01711 
01712     /* Check if the speed of the client is what we can expect from a client */
01713     if (cs->status == NetworkClientSocket::STATUS_ACTIVE) {
01714       /* 1 lag-point per day */
01715       uint lag = NetworkCalculateLag(cs) / DAY_TICKS;
01716       if (lag > 0) {
01717         if (lag > 3) {
01718           /* Client did still not report in after 4 game-day, drop him
01719            *  (that is, the 3 of above, + 1 before any lag is counted) */
01720           IConsolePrintF(CC_ERROR, cs->last_packet + 3 * DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick ?
01721               /* A packet was received in the last three game days, so the client is likely lagging behind. */
01722                 "Client #%d is dropped because the client's game state is more than 4 game-days behind" :
01723               /* No packet was received in the last three game days; sounds like a lost connection. */
01724                 "Client #%d is dropped because the client did not respond for more than 4 game-days",
01725               cs->client_id);
01726           cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01727           continue;
01728         }
01729 
01730         /* Report once per time we detect the lag, and only when we
01731          * received a packet in the last 2000 milliseconds. If we
01732          * did not receive a packet, then the client is not just
01733          * slow, but the connection is likely severed. Mentioning
01734          * frame_freq is not useful in this case. */
01735         if (cs->lag_test == 0 && cs->last_packet + DAY_TICKS * MILLISECONDS_PER_TICK > _realtime_tick) {
01736           IConsolePrintF(CC_WARNING,"[%d] Client #%d is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id);
01737           cs->lag_test = 1;
01738         }
01739       } else {
01740         cs->lag_test = 0;
01741       }
01742       if (cs->last_frame_server - cs->last_token_frame >= 5 * DAY_TICKS) {
01743         /* This is a bad client! It didn't send the right token back. */
01744         IConsolePrintF(CC_ERROR, "Client #%d is dropped because it fails to send valid acks", cs->client_id);
01745         cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01746         continue;
01747       }
01748     } else if (cs->status == NetworkClientSocket::STATUS_PRE_ACTIVE) {
01749       uint lag = NetworkCalculateLag(cs);
01750       if (lag > _settings_client.network.max_join_time) {
01751         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);
01752         cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01753         continue;
01754       }
01755     } else if (cs->status == NetworkClientSocket::STATUS_INACTIVE) {
01756       uint lag = NetworkCalculateLag(cs);
01757       if (lag > 4 * DAY_TICKS) {
01758         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);
01759         cs->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR);
01760         continue;
01761       }
01762     }
01763 
01764     if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) {
01765       /* Check if we can send command, and if we have anything in the queue */
01766       NetworkHandleCommandQueue(cs);
01767 
01768       /* Send an updated _frame_counter_max to the client */
01769       if (send_frame) cs->SendFrame();
01770 
01771 #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
01772       /* Send a sync-check packet */
01773       if (send_sync) cs->SendSync();
01774 #endif
01775     }
01776   }
01777 
01778   /* See if we need to advertise */
01779   NetworkUDPAdvertise();
01780 }
01781 
01783 void NetworkServerYearlyLoop()
01784 {
01785   NetworkCheckRestartMap();
01786   NetworkAdminUpdate(ADMIN_FREQUENCY_ANUALLY);
01787 }
01788 
01790 void NetworkServerMonthlyLoop()
01791 {
01792   NetworkAutoCleanCompanies();
01793   NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY);
01794   if ((_cur_month % 3) == 0) NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY);
01795 }
01796 
01798 void NetworkServerDailyLoop()
01799 {
01800   NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY);
01801   if ((_date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);
01802 }
01803 
01804 const char *GetClientIP(NetworkClientInfo *ci)
01805 {
01806   return ci->client_address.GetHostname();
01807 }
01808 
01809 void NetworkServerShowStatusToConsole()
01810 {
01811   static const char * const stat_str[] = {
01812     "inactive",
01813     "checking NewGRFs",
01814     "authorizing (server password)",
01815     "authorizing (company password)",
01816     "authorized",
01817     "waiting",
01818     "loading map",
01819     "map done",
01820     "ready",
01821     "active"
01822   };
01823   assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
01824 
01825   NetworkClientSocket *cs;
01826   FOR_ALL_CLIENT_SOCKETS(cs) {
01827     uint lag = NetworkCalculateLag(cs);
01828     NetworkClientInfo *ci = cs->GetInfo();
01829     const char *status;
01830 
01831     status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
01832     IConsolePrintF(CC_INFO, "Client #%1d  name: '%s'  status: '%s'  frame-lag: %3d  company: %1d  IP: %s",
01833       cs->client_id, ci->client_name, status, lag,
01834       ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
01835       GetClientIP(ci));
01836   }
01837 }
01838 
01842 void NetworkServerSendConfigUpdate()
01843 {
01844   NetworkClientSocket *cs;
01845 
01846   FOR_ALL_CLIENT_SOCKETS(cs) {
01847     if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate();
01848   }
01849 }
01850 
01851 void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded)
01852 {
01853   if (NetworkCompanyIsPassworded(company_id) == passworded) return;
01854 
01855   SB(_network_company_passworded, company_id, 1, !!passworded);
01856   SetWindowClassesDirty(WC_COMPANY);
01857 
01858   NetworkClientSocket *cs;
01859   FOR_ALL_CLIENT_SOCKETS(cs) {
01860     if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendCompanyUpdate();
01861   }
01862 
01863   NetworkAdminCompanyUpdate(Company::GetIfValid(company_id));
01864 }
01865 
01872 void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
01873 {
01874   /* Only allow non-dedicated servers and normal clients to be moved */
01875   if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
01876 
01877   NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
01878 
01879   /* No need to waste network resources if the client is in the company already! */
01880   if (ci->client_playas == company_id) return;
01881 
01882   ci->client_playas = company_id;
01883 
01884   if (client_id == CLIENT_ID_SERVER) {
01885     SetLocalCompany(company_id);
01886   } else {
01887     NetworkClientSocket *cs = NetworkFindClientStateFromClientID(client_id);
01888     /* When the company isn't authorized we can't move them yet. */
01889     if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
01890     cs->SendMove(client_id, company_id);
01891   }
01892 
01893   /* announce the client's move */
01894   NetworkUpdateClientInfo(client_id);
01895 
01896   NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN;
01897   NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
01898 }
01899 
01900 void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string)
01901 {
01902   NetworkFindClientStateFromClientID(client_id)->SendRConResult(colour_code, string);
01903 }
01904 
01905 static void NetworkServerSendError(ClientID client_id, NetworkErrorCode error)
01906 {
01907   NetworkFindClientStateFromClientID(client_id)->SendError(error);
01908 }
01909 
01910 void NetworkServerKickClient(ClientID client_id)
01911 {
01912   if (client_id == CLIENT_ID_SERVER) return;
01913   NetworkServerSendError(client_id, NETWORK_ERROR_KICKED);
01914 }
01915 
01916 uint NetworkServerKickOrBanIP(const char *ip, bool ban)
01917 {
01918   /* Add address to ban-list */
01919   if (ban) *_network_ban_list.Append() = strdup(ip);
01920 
01921   uint n = 0;
01922 
01923   /* There can be multiple clients with the same IP, kick them all */
01924   NetworkClientInfo *ci;
01925   FOR_ALL_CLIENT_INFOS(ci) {
01926     if (ci->client_id == CLIENT_ID_SERVER) continue;
01927     if (ci->client_address.IsInNetmask(const_cast<char *>(ip))) {
01928       NetworkServerKickClient(ci->client_id);
01929       n++;
01930     }
01931   }
01932 
01933   return n;
01934 }
01935 
01936 bool NetworkCompanyHasClients(CompanyID company)
01937 {
01938   const NetworkClientInfo *ci;
01939   FOR_ALL_CLIENT_INFOS(ci) {
01940     if (ci->client_playas == company) return true;
01941   }
01942   return false;
01943 }
01944 
01945 
01951 void ServerNetworkGameSocketHandler::GetClientName(char *client_name, size_t size) const
01952 {
01953   const NetworkClientInfo *ci = this->GetInfo();
01954 
01955   if (StrEmpty(ci->client_name)) {
01956     snprintf(client_name, size, "Client #%4d", this->client_id);
01957   } else {
01958     ttd_strlcpy(client_name, ci->client_name, size);
01959   }
01960 }
01961 
01962 #endif /* ENABLE_NETWORK */

Generated on Wed Apr 13 00:47:49 2011 for OpenTTD by  doxygen 1.6.1