network_udp.cpp

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

Generated on Mon Feb 16 23:12:08 2009 for openttd by  doxygen 1.5.6