# network_udp.cpp

Go to the documentation of this file.

    00001 /* $Id: network_udp.cpp 13735 2008-07-19 12:23:14Z rubidium $ */
    00002
    00010 #ifdef ENABLE_NETWORK
    00011
    00012 #include "../stdafx.h"
    00013 #include "../debug.h"
    00014 #include "network_data.h"
    00015 #include "../date_func.h"
    00016 #include "../map_func.h"
    00017 #include "network_gamelist.h"
    00018 #include "network_udp.h"
    00019 #include "../variables.h"
    00020 #include "../newgrf_config.h"
    00021 #include "../core/endian_func.hpp"
    00022 #include "../string_func.h"
    00023 #include "../player_base.h"
    00024 #include "../player_func.h"
    00025 #include "../settings_type.h"
    00026
    00027 #include "core/udp.h"
    00028
    00029 enum {
    00030   ADVERTISE_NORMAL_INTERVAL = 30000, // interval between advertising in ticks (15 minutes)
    00031   ADVERTISE_RETRY_INTERVAL  =   300, // readvertise when no response after this many ticks (9 seconds)
    00032   ADVERTISE_RETRY_TIMES     =     3  // give up readvertising after this much failed retries
    00033 };
    00034
    00035 NetworkUDPSocketHandler *_udp_client_socket;
    00036 NetworkUDPSocketHandler *_udp_server_socket;
    00037 NetworkUDPSocketHandler *_udp_master_socket;
    00038
    00040
    00041 class MasterNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
    00042 protected:
    00043   DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER);
    00044 public:
    00045   virtual ~MasterNetworkUDPSocketHandler() {}
    00046 };
    00047
    00048 DEF_UDP_RECEIVE_COMMAND(Master, PACKET_UDP_MASTER_ACK_REGISTER)
    00049 {
    00050   _network_advertise_retries = 0;
    00051   DEBUG(net, 2, "[udp] advertising on master server successful");
    00052
    00053   /* We are advertised, but we don't want to! */
    00054   if (!_network_advertise) NetworkUDPRemoveAdvertise();
    00055 }
    00056
    00058
    00059 class ServerNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
    00060 protected:
    00061   DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER);
    00062   DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO);
    00063   DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS);
    00064 public:
    00065   virtual ~ServerNetworkUDPSocketHandler() {}
    00066 };
    00067
    00068 DEF_UDP_RECEIVE_COMMAND(Server, PACKET_UDP_CLIENT_FIND_SERVER)
    00069 {
    00070   // Just a fail-safe.. should never happen
    00071   if (!_network_udp_server)
    00072     return;
    00073
    00074   Packet packet(PACKET_UDP_SERVER_RESPONSE);
    00075
    00076   // Update some game_info
    00077   _network_game_info.game_date     = _date;
    00078   _network_game_info.map_width     = MapSizeX();
    00079   _network_game_info.map_height    = MapSizeY();
    00080   _network_game_info.map_set       = _opt.landscape;
    00081   _network_game_info.companies_on  = ActivePlayerCount();
    00082   _network_game_info.spectators_on = NetworkSpectatorCount();
    00083   _network_game_info.grfconfig     = _grfconfig;
    00084
    00085   this->Send_NetworkGameInfo(&packet, &_network_game_info);
    00086
    00087   // Let the client know that we are here
    00088   this->SendPacket(&packet, client_addr);
    00089
    00090   DEBUG(net, 2, "[udp] queried from '%s'", inet_ntoa(client_addr->sin_addr));
    00091 }
    00092
    00093 DEF_UDP_RECEIVE_COMMAND(Server, PACKET_UDP_CLIENT_DETAIL_INFO)
    00094 {
    00095   // Just a fail-safe.. should never happen
    00096   if (!_network_udp_server) return;
    00097
    00098   Packet packet(PACKET_UDP_SERVER_DETAIL_INFO);
    00099
    00100   /* Send the amount of active companies */
    00101   packet.Send_uint8 (NETWORK_COMPANY_INFO_VERSION);
    00102   packet.Send_uint8 (ActivePlayerCount());
    00103
    00104   /* Fetch the latest version of everything */
    00105   NetworkPopulateCompanyInfo();
    00106
    00107   Player *player;
    00108   byte current = 0;
    00109   /* Go through all the players */
    00110   FOR_ALL_PLAYERS(player) {
    00111     /* Skip non-active players */
    00112     if (!player->is_active) continue;
    00113
    00114     current++;
    00115
    00116     /* Send the information */
    00117     packet.Send_uint8 (current);
    00118
    00119     packet.Send_string(_network_player_info[player->index].company_name);
    00120     packet.Send_uint32(_network_player_info[player->index].inaugurated_year);
    00121     packet.Send_uint64(_network_player_info[player->index].company_value);
    00122     packet.Send_uint64(_network_player_info[player->index].money);
    00123     packet.Send_uint64(_network_player_info[player->index].income);
    00124     packet.Send_uint16(_network_player_info[player->index].performance);
    00125
    00126     /* Send 1 if there is a passord for the company else send 0 */
    00127     packet.Send_bool  (!StrEmpty(_network_player_info[player->index].password));
    00128
    00129     for (int i = 0; i < NETWORK_VEHICLE_TYPES; i++) {
    00130       packet.Send_uint16(_network_player_info[player->index].num_vehicle[i]);
    00131     }
    00132
    00133     for (int i = 0; i < NETWORK_STATION_TYPES; i++) {
    00134       packet.Send_uint16(_network_player_info[player->index].num_station[i]);
    00135     }
    00136   }
    00137
    00138   this->SendPacket(&packet, client_addr);
    00139 }
    00140
    00154 DEF_UDP_RECEIVE_COMMAND(Server, PACKET_UDP_CLIENT_GET_NEWGRFS)
    00155 {
    00156   uint8 num_grfs;
    00157   uint i;
    00158
    00159   const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT];
    00160   uint8 in_reply_count = 0;
    00161   uint packet_len = 0;
    00162
    00163   DEBUG(net, 6, "[udp] newgrf data request from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
    00164
    00165   num_grfs = p->Recv_uint8 ();
    00166   if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
    00167
    00168   for (i = 0; i < num_grfs; i++) {
    00169     GRFConfig c;
    00170     const GRFConfig *f;
    00171
    00172     this->Recv_GRFIdentifier(p, &c);
    00173
    00174     /* Find the matching GRF file */
    00175     f = FindGRFConfig(c.grfid, c.md5sum);
    00176     if (f == NULL) continue; // The GRF is unknown to this server
    00177
    00178     /* If the reply might exceed the size of the packet, only reply
    00179      * the current list and do not send the other data.
    00180      * The name could be an empty string, if so take the filename. */
    00181     packet_len += sizeof(c.grfid) + sizeof(c.md5sum) +
    00182         min(strlen((f->name != NULL && !StrEmpty(f->name)) ? f->name : f->filename) + 1, (size_t)NETWORK_GRF_NAME_LENGTH);
    00183     if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply
    00184       break;
    00185     }
    00186     in_reply[in_reply_count] = f;
    00187     in_reply_count++;
    00188   }
    00189
    00190   if (in_reply_count == 0) return;
    00191
    00192   Packet packet(PACKET_UDP_SERVER_NEWGRFS);
    00193   packet.Send_uint8(in_reply_count);
    00194   for (i = 0; i < in_reply_count; i++) {
    00195     char name[NETWORK_GRF_NAME_LENGTH];
    00196
    00197     /* The name could be an empty string, if so take the filename */
    00198     ttd_strlcpy(name, (in_reply[i]->name != NULL && !StrEmpty(in_reply[i]->name)) ?
    00199         in_reply[i]->name : in_reply[i]->filename, sizeof(name));
    00200     this->Send_GRFIdentifier(&packet, in_reply[i]);
    00201     packet.Send_string(name);
    00202   }
    00203
    00204   this->SendPacket(&packet, client_addr);
    00205 }
    00206
    00208
    00209 class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
    00210 protected:
    00211   DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE);
    00212   DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST);
    00213   DECLARE_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS);
    00214   virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config);
    00215 public:
    00216   virtual ~ClientNetworkUDPSocketHandler() {}
    00217 };
    00218
    00219 DEF_UDP_RECEIVE_COMMAND(Client, PACKET_UDP_SERVER_RESPONSE)
    00220 {
    00221   NetworkGameList *item;
    00222
    00223   // Just a fail-safe.. should never happen
    00224   if (_network_udp_server) return;
    00225
    00226   DEBUG(net, 4, "[udp] server response from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
    00227
    00228   // Find next item
    00229   item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
    00230
    00231   this->Recv_NetworkGameInfo(p, &item->info);
    00232
    00233   item->info.compatible = true;
    00234   {
    00235     /* Checks whether there needs to be a request for names of GRFs and makes
    00236      * the request if necessary. GRFs that need to be requested are the GRFs
    00237      * that do not exist on the clients system and we do not have the name
    00238      * resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER.
    00239      * The in_request array and in_request_count are used so there is no need
    00240      * to do a second loop over the GRF list, which can be relatively expensive
    00241      * due to the string comparisons. */
    00242     const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT];
    00243     const GRFConfig *c;
    00244     uint in_request_count = 0;
    00245     struct sockaddr_in out_addr;
    00246
    00247     for (c = item->info.grfconfig; c != NULL; c = c->next) {
    00248       if (c->status == GCS_NOT_FOUND) item->info.compatible = false;
    00249       if (c->status != GCS_NOT_FOUND || strcmp(c->name, UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue;
    00250       in_request[in_request_count] = c;
    00251       in_request_count++;
    00252     }
    00253
    00254     if (in_request_count > 0) {
    00255       /* There are 'unknown' GRFs, now send a request for them */
    00256       uint i;
    00257       Packet packet(PACKET_UDP_CLIENT_GET_NEWGRFS);
    00258
    00259       packet.Send_uint8(in_request_count);
    00260       for (i = 0; i < in_request_count; i++) {
    00261         this->Send_GRFIdentifier(&packet, in_request[i]);
    00262       }
    00263
    00264       out_addr.sin_family      = AF_INET;
    00265       out_addr.sin_port        = htons(item->port);
    00266       out_addr.sin_addr.s_addr = item->ip;
    00267       this->SendPacket(&packet, &out_addr);
    00268     }
    00269   }
    00270
    00271   if (item->info.hostname[0] == '\0')
    00272     snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
    00273
    00274   /* Check if we are allowed on this server based on the revision-match */
    00275   item->info.version_compatible = IsNetworkCompatibleVersion(item->info.server_revision);
    00276   item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs
    00277
    00278   item->online = true;
    00279
    00280   UpdateNetworkGameWindow(false);
    00281 }
    00282
    00283 DEF_UDP_RECEIVE_COMMAND(Client, PACKET_UDP_MASTER_RESPONSE_LIST)
    00284 {
    00285   int i;
    00286   struct in_addr ip;
    00287   uint16 port;
    00288   uint8 ver;
    00289
    00290   /* packet begins with the protocol version (uint8)
    00291    * then an uint16 which indicates how many
    00292    * ip:port pairs are in this packet, after that
    00293    * an uint32 (ip) and an uint16 (port) for each pair
    00294    */
    00295
    00296   ver = p->Recv_uint8();
    00297
    00298   if (ver == 1) {
    00299     for (i = p->Recv_uint16(); i != 0 ; i--) {
    00300       ip.s_addr = TO_LE32(p->Recv_uint32());
    00301       port = p->Recv_uint16();
    00302
    00303       /* Somehow we reached the end of the packet */
    00304       if (this->HasClientQuit()) return;
    00305       NetworkUDPQueryServer(inet_ntoa(ip), port);
    00306     }
    00307   }
    00308 }
    00309
    00311 DEF_UDP_RECEIVE_COMMAND(Client, PACKET_UDP_SERVER_NEWGRFS)
    00312 {
    00313   uint8 num_grfs;
    00314   uint i;
    00315
    00316   DEBUG(net, 6, "[udp] newgrf data reply from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
    00317
    00318   num_grfs = p->Recv_uint8 ();
    00319   if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
    00320
    00321   for (i = 0; i < num_grfs; i++) {
    00322     char *unknown_name;
    00323     char name[NETWORK_GRF_NAME_LENGTH];
    00324     GRFConfig c;
    00325
    00326     this->Recv_GRFIdentifier(p, &c);
    00327     p->Recv_string(name, sizeof(name));
    00328
    00329     /* An empty name is not possible under normal circumstances
    00330      * and causes problems when showing the NewGRF list. */
    00331     if (StrEmpty(name)) continue;
    00332
    00333     /* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple.
    00334      * If it exists and not resolved yet, then name of the fake GRF is
    00335      * overwritten with the name from the reply. */
    00336     unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false);
    00337     if (unknown_name != NULL && strcmp(unknown_name, UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) {
    00338       ttd_strlcpy(unknown_name, name, NETWORK_GRF_NAME_LENGTH);
    00339     }
    00340   }
    00341 }
    00342
    00343 void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
    00344 {
    00345   /* Find the matching GRF file */
    00346   const GRFConfig *f = FindGRFConfig(config->grfid, config->md5sum);
    00347   if (f == NULL) {
    00348     /* Don't know the GRF, so mark game incompatible and the (possibly)
    00349      * already resolved name for this GRF (another server has sent the
    00350      * name of the GRF already */
    00351     config->name   = FindUnknownGRFName(config->grfid, config->md5sum, true);
    00352     config->status = GCS_NOT_FOUND;
    00353   } else {
    00354     config->filename  = f->filename;
    00355     config->name      = f->name;
    00356     config->info      = f->info;
    00357   }
    00358   SetBit(config->flags, GCF_COPY);
    00359 }
    00360
    00361 // Close UDP connection
    00362 void NetworkUDPCloseAll()
    00363 {
    00364   DEBUG(net, 1, "[udp] closed listeners");
    00365
    00366   _udp_server_socket->Close();
    00367   _udp_master_socket->Close();
    00368   _udp_client_socket->Close();
    00369
    00370   _network_udp_server = false;
    00371   _network_udp_broadcast = 0;
    00372 }
    00373
    00374 // Broadcast to all ips
    00375 static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket)
    00376 {
    00377   uint i;
    00378
    00379   for (i = 0; _broadcast_list[i] != 0; i++) {
    00380     Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
    00381     struct sockaddr_in out_addr;
    00382
    00383     out_addr.sin_family = AF_INET;
    00384     out_addr.sin_port = htons(_network_server_port);
    00385     out_addr.sin_addr.s_addr = _broadcast_list[i];
    00386
    00387     DEBUG(net, 4, "[udp] broadcasting to %s", inet_ntoa(out_addr.sin_addr));
    00388
    00389     socket->SendPacket(&p, &out_addr);
    00390   }
    00391 }
    00392
    00393
    00394 // Request the the server-list from the master server
    00395 void NetworkUDPQueryMasterServer()
    00396 {
    00397   struct sockaddr_in out_addr;
    00398
    00399   if (!_udp_client_socket->IsConnected()) {
    00400     if (!_udp_client_socket->Listen(0, 0, true)) return;
    00401   }
    00402
    00403   Packet p(PACKET_UDP_CLIENT_GET_LIST);
    00404
    00405   out_addr.sin_family = AF_INET;
    00406   out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
    00407   out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
    00408
    00409   // packet only contains protocol version
    00410   p.Send_uint8(NETWORK_MASTER_SERVER_VERSION);
    00411
    00412   _udp_client_socket->SendPacket(&p, &out_addr);
    00413
    00414   DEBUG(net, 2, "[udp] master server queried at %s:%d", inet_ntoa(out_addr.sin_addr), ntohs(out_addr.sin_port));
    00415 }
    00416
    00417 // Find all servers
    00418 void NetworkUDPSearchGame()
    00419 {
    00420   // We are still searching..
    00421   if (_network_udp_broadcast > 0) return;
    00422
    00423   // No UDP-socket yet..
    00424   if (!_udp_client_socket->IsConnected()) {
    00425     if (!_udp_client_socket->Listen(0, 0, true)) return;
    00426   }
    00427
    00428   DEBUG(net, 0, "[udp] searching server");
    00429
    00430   NetworkUDPBroadCast(_udp_client_socket);
    00431   _network_udp_broadcast = 300; // Stay searching for 300 ticks
    00432 }
    00433
    00434 void NetworkUDPQueryServer(const char* host, unsigned short port, bool manually)
    00435 {
    00436   struct sockaddr_in out_addr;
    00437   NetworkGameList *item;
    00438
    00439   // No UDP-socket yet..
    00440   if (!_udp_client_socket->IsConnected()) {
    00441     if (!_udp_client_socket->Listen(0, 0, true)) return;
    00442   }
    00443
    00444   out_addr.sin_family = AF_INET;
    00445   out_addr.sin_port = htons(port);
    00446   out_addr.sin_addr.s_addr = NetworkResolveHost(host);
    00447
    00448   // Clear item in gamelist
    00449   item = NetworkGameListAddItem(inet_addr(inet_ntoa(out_addr.sin_addr)), ntohs(out_addr.sin_port));
    00450   if (StrEmpty(item->info.server_name)) {
    00451     memset(&item->info, 0, sizeof(item->info));
    00452     ttd_strlcpy(item->info.server_name, host, lengthof(item->info.server_name));
    00453     ttd_strlcpy(item->info.hostname, host, lengthof(item->info.hostname));
    00454     item->online = false;
    00455   }
    00456   item->manually = manually;
    00457
    00458   // Init the packet
    00459   Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
    00460   _udp_client_socket->SendPacket(&p, &out_addr);
    00461
    00462   UpdateNetworkGameWindow(false);
    00463 }
    00464
    00465 /* Remove our advertise from the master-server */
    00466 void NetworkUDPRemoveAdvertise()
    00467 {
    00468   struct sockaddr_in out_addr;
    00469
    00470   /* Check if we are advertising */
    00471   if (!_networking || !_network_server || !_network_udp_server) return;
    00472
    00473   /* check for socket */
    00474   if (!_udp_master_socket->IsConnected()) {
    00475     if (!_udp_master_socket->Listen(_network_server_bind_ip, 0, false)) return;
    00476   }
    00477
    00478   DEBUG(net, 1, "[udp] removing advertise from master server");
    00479
    00480   /* Find somewhere to send */
    00481   out_addr.sin_family = AF_INET;
    00482   out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
    00483   out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
    00484
    00485   /* Send the packet */
    00486   Packet p(PACKET_UDP_SERVER_UNREGISTER);
    00487   /* Packet is: Version, server_port */
    00488   p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION);
    00489   p.Send_uint16(_network_server_port);
    00490   _udp_master_socket->SendPacket(&p, &out_addr);
    00491 }
    00492
    00493 /* Register us to the master server
    00494      This function checks if it needs to send an advertise */
    00495 void NetworkUDPAdvertise()
    00496 {
    00497   struct sockaddr_in out_addr;
    00498
    00499   /* Check if we should send an advertise */
    00500   if (!_networking || !_network_server || !_network_udp_server || !_network_advertise)
    00501     return;
    00502
    00503   /* check for socket */
    00504   if (!_udp_master_socket->IsConnected()) {
    00505     if (!_udp_master_socket->Listen(_network_server_bind_ip, 0, false)) return;
    00506   }
    00507
    00508   if (_network_need_advertise) {
    00509     _network_need_advertise = false;
    00510     _network_advertise_retries = ADVERTISE_RETRY_TIMES;
    00511   } else {
    00512     /* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */
    00513     if (_network_advertise_retries == 0) {
    00514       if ((_network_last_advertise_frame + ADVERTISE_NORMAL_INTERVAL) > _frame_counter)
    00515         return;
    00516       _network_advertise_retries = ADVERTISE_RETRY_TIMES;
    00517     }
    00518
    00519     if ((_network_last_advertise_frame + ADVERTISE_RETRY_INTERVAL) > _frame_counter)
    00520       return;
    00521   }
    00522
    00523   _network_advertise_retries--;
    00524   _network_last_advertise_frame = _frame_counter;
    00525
    00526   /* Find somewhere to send */
    00527   out_addr.sin_family = AF_INET;
    00528   out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
    00529   out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
    00530
    00531   DEBUG(net, 1, "[udp] advertising to master server");
    00532
    00533   /* Send the packet */
    00534   Packet p(PACKET_UDP_SERVER_REGISTER);
    00535   /* Packet is: WELCOME_MESSAGE, Version, server_port */
    00536   p.Send_string(NETWORK_MASTER_SERVER_WELCOME_MESSAGE);
    00537   p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION);
    00538   p.Send_uint16(_network_server_port);
    00539   _udp_master_socket->SendPacket(&p, &out_addr);
    00540 }
    00541
    00542 void NetworkUDPInitialize()
    00543 {
    00544   _udp_client_socket = new ClientNetworkUDPSocketHandler();
    00545   _udp_server_socket = new ServerNetworkUDPSocketHandler();
    00546   _udp_master_socket = new MasterNetworkUDPSocketHandler();
    00547
    00548   _network_udp_server = false;
    00549   _network_udp_broadcast = 0;
    00550 }
    00551
    00552 void NetworkUDPShutdown()
    00553 {
    00554   NetworkUDPCloseAll();
    00555
    00556   delete _udp_client_socket;
    00557   delete _udp_server_socket;
    00558   delete _udp_master_socket;
    00559 }
    00560
    00561 #endif /* ENABLE_NETWORK */