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 */

Generated on Wed Oct 1 17:03:21 2008 for openttd by  doxygen 1.5.6