# network_udp.cpp

Go to the documentation of this file.

    00001 /* $Id: network_udp.cpp 16060 2009-04-14 21:13:07Z rubidium $ */
    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(false);
    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
    00504 void NetworkUDPRemoveAdvertise(bool blocking)
    00505 {
    00506   /* Check if we are advertising */
    00507   if (!_networking || !_network_server || !_network_udp_server) return;
    00508
    00509   /* check for socket */
    00510   if (!_udp_master_socket->IsConnected()) {
    00511     if (!_udp_master_socket->Listen(_network_server_bind_ip, 0, false)) return;
    00512   }
    00513
    00514   if (blocking || !ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL)) {
    00515     NetworkUDPRemoveAdvertiseThread(NULL);
    00516   }
    00517 }
    00518
    00519 void NetworkUDPAdvertiseThread(void *pntr)
    00520 {
    00521   /* Find somewhere to send */
    00522   struct sockaddr_in out_addr;
    00523   out_addr.sin_family = AF_INET;
    00524   out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
    00525   out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
    00526
    00527   DEBUG(net, 1, "[udp] advertising to master server");
    00528
    00529   /* Send the packet */
    00530   Packet p(PACKET_UDP_SERVER_REGISTER);
    00531   /* Packet is: WELCOME_MESSAGE, Version, server_port */
    00532   p.Send_string(NETWORK_MASTER_SERVER_WELCOME_MESSAGE);
    00533   p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION);
    00534   p.Send_uint16(_settings_client.network.server_port);
    00535
    00536   _network_udp_mutex->BeginCritical();
    00537   if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr);
    00538   _network_udp_mutex->EndCritical();
    00539 }
    00540
    00541 /* Register us to the master server
    00542      This function checks if it needs to send an advertise */
    00543 void NetworkUDPAdvertise()
    00544 {
    00545   /* Check if we should send an advertise */
    00546   if (!_networking || !_network_server || !_network_udp_server || !_settings_client.network.server_advertise)
    00547     return;
    00548
    00549   /* check for socket */
    00550   if (!_udp_master_socket->IsConnected()) {
    00551     if (!_udp_master_socket->Listen(_network_server_bind_ip, 0, false)) return;
    00552   }
    00553
    00554   if (_network_need_advertise) {
    00555     _network_need_advertise = false;
    00556     _network_advertise_retries = ADVERTISE_RETRY_TIMES;
    00557   } else {
    00558     /* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */
    00559     if (_network_advertise_retries == 0) {
    00560       if ((_network_last_advertise_frame + ADVERTISE_NORMAL_INTERVAL) > _frame_counter)
    00561         return;
    00562       _network_advertise_retries = ADVERTISE_RETRY_TIMES;
    00563     }
    00564
    00565     if ((_network_last_advertise_frame + ADVERTISE_RETRY_INTERVAL) > _frame_counter)
    00566       return;
    00567   }
    00568
    00569   _network_advertise_retries--;
    00570   _network_last_advertise_frame = _frame_counter;
    00571
    00572   if (!ThreadObject::New(NetworkUDPAdvertiseThread, NULL)) {
    00573     NetworkUDPAdvertiseThread(NULL);
    00574   }
    00575 }
    00576
    00577 void NetworkUDPInitialize()
    00578 {
    00579   assert(_udp_client_socket == NULL && _udp_server_socket == NULL && _udp_master_socket == NULL);
    00580
    00581   _network_udp_mutex->BeginCritical();
    00582   _udp_client_socket = new ClientNetworkUDPSocketHandler();
    00583   _udp_server_socket = new ServerNetworkUDPSocketHandler();
    00584   _udp_master_socket = new MasterNetworkUDPSocketHandler();
    00585
    00586   _network_udp_server = false;
    00587   _network_udp_broadcast = 0;
    00588   _network_udp_mutex->EndCritical();
    00589 }
    00590
    00591 void NetworkUDPShutdown()
    00592 {
    00593   NetworkUDPCloseAll();
    00594
    00595   _network_udp_mutex->BeginCritical();
    00596   delete _udp_client_socket;
    00597   delete _udp_server_socket;
    00598   delete _udp_master_socket;
    00599   _udp_client_socket = NULL;
    00600   _udp_server_socket = NULL;
    00601   _udp_master_socket = NULL;
    00602   _network_udp_mutex->EndCritical();
    00603 }
    00604
    00605 #endif /* ENABLE_NETWORK */