network.cpp

Go to the documentation of this file.
00001 /* $Id: network.cpp 21184 2010-11-14 12:42:29Z rubidium $ */
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 #include "../stdafx.h"
00013 
00014 #ifdef ENABLE_NETWORK
00015 
00016 #include "../strings_func.h"
00017 #include "../command_func.h"
00018 #include "../date_func.h"
00019 #include "network_client.h"
00020 #include "network_server.h"
00021 #include "network_content.h"
00022 #include "network_udp.h"
00023 #include "network_gamelist.h"
00024 #include "network_base.h"
00025 #include "core/udp.h"
00026 #include "core/host.h"
00027 #include "network_gui.h"
00028 #include "../console_func.h"
00029 #include "../3rdparty/md5/md5.h"
00030 #include "../core/random_func.hpp"
00031 #include "../window_func.h"
00032 #include "../company_func.h"
00033 #include "../company_base.h"
00034 #include "../landscape_type.h"
00035 #include "../rev.h"
00036 #include "../core/pool_func.hpp"
00037 #include "../gfx_func.h"
00038 #include "table/strings.h"
00039 
00040 #ifdef DEBUG_DUMP_COMMANDS
00041 #include "../fileio_func.h"
00043 bool _ddc_fastforward = true;
00044 #endif /* DEBUG_DUMP_COMMANDS */
00045 
00046 DECLARE_POSTFIX_INCREMENT(ClientID);
00047 
00048 assert_compile(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE);
00049 
00050 NetworkClientInfoPool _networkclientinfo_pool("NetworkClientInfo");
00051 INSTANTIATE_POOL_METHODS(NetworkClientInfo)
00052 
00053 bool _networking;         
00054 bool _network_server;     
00055 bool _network_available;  
00056 bool _network_dedicated;  
00057 bool _is_network_server;  
00058 NetworkServerGameInfo _network_game_info;
00059 NetworkCompanyState *_network_company_states = NULL;
00060 ClientID _network_own_client_id;
00061 ClientID _redirect_console_to_client;
00062 bool _network_need_advertise;
00063 uint32 _network_last_advertise_frame;
00064 uint8 _network_reconnect;
00065 StringList _network_bind_list;
00066 StringList _network_host_list;
00067 StringList _network_ban_list;
00068 uint32 _frame_counter_server; // The frame_counter of the server, if in network-mode
00069 uint32 _frame_counter_max; // To where we may go with our clients
00070 uint32 _frame_counter;
00071 uint32 _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients.
00072 NetworkAddressList _broadcast_list;
00073 uint32 _sync_seed_1;
00074 #ifdef NETWORK_SEND_DOUBLE_SEED
00075 uint32 _sync_seed_2;
00076 #endif
00077 uint32 _sync_frame;
00078 bool _network_first_time;
00079 bool _network_udp_server;
00080 uint16 _network_udp_broadcast;
00081 uint8 _network_advertise_retries;
00082 CompanyMask _network_company_passworded; 
00083 
00084 /* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */
00085 assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE);
00086 assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_BYTES);
00087 
00088 extern NetworkUDPSocketHandler *_udp_client_socket; 
00089 extern NetworkUDPSocketHandler *_udp_server_socket; 
00090 extern NetworkUDPSocketHandler *_udp_master_socket; 
00091 
00092 /* The listen socket for the server */
00093 static SocketList _listensockets;
00094 
00095 /* The amount of clients connected */
00096 static byte _network_clients_connected = 0;
00097 /* The identifier counter for new clients (is never decreased) */
00098 static ClientID _network_client_id = CLIENT_ID_FIRST;
00099 
00100 /* Some externs / forwards */
00101 extern void StateGameLoop();
00102 
00106 NetworkClientInfo::~NetworkClientInfo()
00107 {
00108   /* Delete the chat window, if you were chatting with this client. */
00109   InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_CLIENT, this->client_id);
00110 }
00111 
00117 NetworkClientInfo *NetworkFindClientInfoFromIndex(ClientIndex index)
00118 {
00119   return NetworkClientInfo::GetIfValid(index);
00120 }
00121 
00127 NetworkClientInfo *NetworkFindClientInfoFromClientID(ClientID client_id)
00128 {
00129   NetworkClientInfo *ci;
00130 
00131   FOR_ALL_CLIENT_INFOS(ci) {
00132     if (ci->client_id == client_id) return ci;
00133   }
00134 
00135   return NULL;
00136 }
00137 
00143 NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip)
00144 {
00145   NetworkClientInfo *ci;
00146   NetworkAddress address(ip);
00147 
00148   if (address.GetAddressLength() == 0) return NULL;
00149 
00150   FOR_ALL_CLIENT_INFOS(ci) {
00151     if (ci->client_address == address) return ci;
00152   }
00153 
00154   return NULL;
00155 }
00156 
00162 NetworkClientSocket *NetworkFindClientStateFromClientID(ClientID client_id)
00163 {
00164   NetworkClientSocket *cs;
00165 
00166   FOR_ALL_CLIENT_SOCKETS(cs) {
00167     if (cs->client_id == client_id) return cs;
00168   }
00169 
00170   return NULL;
00171 }
00172 
00173 /* NetworkGetClientName is a server-safe function to get the name of the client
00174  *  if the user did not send it yet, Client #<no> is used. */
00175 void NetworkGetClientName(char *client_name, size_t size, const NetworkClientSocket *cs)
00176 {
00177   const NetworkClientInfo *ci = cs->GetInfo();
00178 
00179   if (StrEmpty(ci->client_name)) {
00180     snprintf(client_name, size, "Client #%4d", cs->client_id);
00181   } else {
00182     ttd_strlcpy(client_name, ci->client_name, size);
00183   }
00184 }
00185 
00186 byte NetworkSpectatorCount()
00187 {
00188   const NetworkClientInfo *ci;
00189   byte count = 0;
00190 
00191   FOR_ALL_CLIENT_INFOS(ci) {
00192     if (ci->client_playas == COMPANY_SPECTATOR) count++;
00193   }
00194 
00195   /* Don't count a dedicated server as spectator */
00196   if (_network_dedicated) count--;
00197 
00198   return count;
00199 }
00200 
00206 bool NetworkCompanyIsPassworded(CompanyID company_id)
00207 {
00208   return HasBit(_network_company_passworded, company_id);
00209 }
00210 
00211 /* This puts a text-message to the console, or in the future, the chat-box,
00212  *  (to keep it all a bit more general)
00213  * If 'self_send' is true, this is the client who is sending the message */
00214 void NetworkTextMessage(NetworkAction action, ConsoleColour colour, bool self_send, const char *name, const char *str, int64 data)
00215 {
00216   const int duration = 10; // Game days the messages stay visible
00217 
00218   StringID strid;
00219   switch (action) {
00220     case NETWORK_ACTION_SERVER_MESSAGE:
00221       /* Ignore invalid messages */
00222       strid = STR_NETWORK_SERVER_MESSAGE;
00223       colour = CC_DEFAULT;
00224       break;
00225     case NETWORK_ACTION_COMPANY_SPECTATOR:
00226       colour = CC_DEFAULT;
00227       strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE;
00228       break;
00229     case NETWORK_ACTION_COMPANY_JOIN:
00230       colour = CC_DEFAULT;
00231       strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN;
00232       break;
00233     case NETWORK_ACTION_COMPANY_NEW:
00234       colour = CC_DEFAULT;
00235       strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW;
00236       break;
00237     case NETWORK_ACTION_JOIN:
00238       /* Show the Client ID for the server but not for the client. */
00239       strid = _network_server ? STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :  STR_NETWORK_MESSAGE_CLIENT_JOINED;
00240       break;
00241     case NETWORK_ACTION_LEAVE:          strid = STR_NETWORK_MESSAGE_CLIENT_LEFT; break;
00242     case NETWORK_ACTION_NAME_CHANGE:    strid = STR_NETWORK_MESSAGE_NAME_CHANGE; break;
00243     case NETWORK_ACTION_GIVE_MONEY:     strid = self_send ? STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY : STR_NETWORK_MESSAGE_GIVE_MONEY;   break;
00244     case NETWORK_ACTION_CHAT_COMPANY:   strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; break;
00245     case NETWORK_ACTION_CHAT_CLIENT:    strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT  : STR_NETWORK_CHAT_CLIENT;  break;
00246     default:                            strid = STR_NETWORK_CHAT_ALL; break;
00247   }
00248 
00249   char message[1024];
00250   SetDParamStr(0, name);
00251   SetDParamStr(1, str);
00252   SetDParam(2, data);
00253 
00254   /* All of these strings start with "***". These characters are interpreted as both left-to-right and
00255    * right-to-left characters depending on the context. As the next text might be an user's name, the
00256    * user name's characters will influence the direction of the "***" instead of the language setting
00257    * of the game. Manually set the direction of the "***" by inserting a text-direction marker. */
00258   char *msg_ptr = message + Utf8Encode(message, _dynlang.text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM);
00259   GetString(msg_ptr, strid, lastof(message));
00260 
00261   DEBUG(desync, 1, "msg: %08x; %02x; %s", _date, _date_fract, message);
00262   IConsolePrintF(colour, "%s", message);
00263   NetworkAddChatMessage((TextColour)colour, duration, "%s", message);
00264 }
00265 
00266 /* Calculate the frame-lag of a client */
00267 uint NetworkCalculateLag(const NetworkClientSocket *cs)
00268 {
00269   int lag = cs->last_frame_server - cs->last_frame;
00270   /* This client has missed his ACK packet after 1 DAY_TICKS..
00271    *  so we increase his lag for every frame that passes!
00272    * The packet can be out by a max of _net_frame_freq */
00273   if (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq < _frame_counter)
00274     lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq);
00275 
00276   return lag;
00277 }
00278 
00279 
00280 /* There was a non-recoverable error, drop back to the main menu with a nice
00281  *  error */
00282 static void NetworkError(StringID error_string)
00283 {
00284   _switch_mode = SM_MENU;
00285   extern StringID _switch_mode_errorstr;
00286   _switch_mode_errorstr = error_string;
00287 }
00288 
00289 static void ServerStartError(const char *error)
00290 {
00291   DEBUG(net, 0, "[server] could not start network: %s",error);
00292   NetworkError(STR_NETWORK_ERROR_SERVER_START);
00293 }
00294 
00295 static void NetworkClientError(NetworkRecvStatus res, NetworkClientSocket *cs)
00296 {
00297   /* First, send a CLIENT_ERROR to the server, so he knows we are
00298    *  disconnection (and why!) */
00299   NetworkErrorCode errorno;
00300 
00301   /* We just want to close the connection.. */
00302   if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
00303     cs->NetworkSocketHandler::CloseConnection();
00304     NetworkCloseClient(cs, res);
00305     _networking = false;
00306 
00307     DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00308     return;
00309   }
00310 
00311   switch (res) {
00312     case NETWORK_RECV_STATUS_DESYNC:          errorno = NETWORK_ERROR_DESYNC; break;
00313     case NETWORK_RECV_STATUS_SAVEGAME:        errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
00314     case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break;
00315     default:                                  errorno = NETWORK_ERROR_GENERAL; break;
00316   }
00317 
00318   /* This means we fucked up and the server closed the connection */
00319   if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL &&
00320       res != NETWORK_RECV_STATUS_SERVER_BANNED) {
00321     SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
00322   }
00323 
00324   _switch_mode = SM_MENU;
00325   NetworkCloseClient(cs, res);
00326   _networking = false;
00327 }
00328 
00334 StringID GetNetworkErrorMsg(NetworkErrorCode err)
00335 {
00336   /* List of possible network errors, used by
00337    * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */
00338   static const StringID network_error_strings[] = {
00339     STR_NETWORK_ERROR_CLIENT_GENERAL,
00340     STR_NETWORK_ERROR_CLIENT_DESYNC,
00341     STR_NETWORK_ERROR_CLIENT_SAVEGAME,
00342     STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST,
00343     STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR,
00344     STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH,
00345     STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED,
00346     STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED,
00347     STR_NETWORK_ERROR_CLIENT_WRONG_REVISION,
00348     STR_NETWORK_ERROR_CLIENT_NAME_IN_USE,
00349     STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD,
00350     STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH,
00351     STR_NETWORK_ERROR_CLIENT_KICKED,
00352     STR_NETWORK_ERROR_CLIENT_CHEATER,
00353     STR_NETWORK_ERROR_CLIENT_SERVER_FULL
00354   };
00355 
00356   if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL;
00357 
00358   return network_error_strings[err];
00359 }
00360 
00366 void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode)
00367 {
00368   if (!_networking) return;
00369 
00370   switch (changed_mode) {
00371     case PM_PAUSED_NORMAL:
00372     case PM_PAUSED_JOIN:
00373     case PM_PAUSED_ACTIVE_CLIENTS: {
00374       bool changed = ((_pause_mode == PM_UNPAUSED) != (prev_mode == PM_UNPAUSED));
00375       bool paused = (_pause_mode != PM_UNPAUSED);
00376       if (!paused && !changed) return;
00377 
00378       StringID str;
00379       if (!changed) {
00380         int i = -1;
00381         if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED)         SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL);
00382         if ((_pause_mode & PM_PAUSED_JOIN) != PM_UNPAUSED)           SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS);
00383         if ((_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS);
00384         str = STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + i;
00385       } else {
00386         switch (changed_mode) {
00387           case PM_PAUSED_NORMAL:         SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL); break;
00388           case PM_PAUSED_JOIN:           SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS); break;
00389           case PM_PAUSED_ACTIVE_CLIENTS: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS); break;
00390           default: NOT_REACHED();
00391         }
00392         str = paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED;
00393       }
00394 
00395       char buffer[DRAW_STRING_BUFFER];
00396       GetString(buffer, str, lastof(buffer));
00397       NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, NULL, buffer);
00398     } break;
00399 
00400     default:
00401       return;
00402   }
00403 }
00404 
00405 
00414 static void CheckPauseHelper(bool pause, PauseMode pm)
00415 {
00416   if (pause == ((_pause_mode & pm) != PM_UNPAUSED)) return;
00417 
00418   DoCommandP(0, pm, pause ? 1 : 0, CMD_PAUSE);
00419 }
00420 
00426 static uint NetworkCountActiveClients()
00427 {
00428   const NetworkClientSocket *cs;
00429   uint count = 0;
00430 
00431   FOR_ALL_CLIENT_SOCKETS(cs) {
00432     if (cs->status != STATUS_ACTIVE) continue;
00433     if (!Company::IsValidID(cs->GetInfo()->client_playas)) continue;
00434     count++;
00435   }
00436 
00437   return count;
00438 }
00439 
00443 static void CheckMinActiveClients()
00444 {
00445   if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED ||
00446       !_network_dedicated ||
00447       (_settings_client.network.min_active_clients == 0 && (_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) == PM_UNPAUSED)) {
00448     return;
00449   }
00450   CheckPauseHelper(NetworkCountActiveClients() < _settings_client.network.min_active_clients, PM_PAUSED_ACTIVE_CLIENTS);
00451 }
00452 
00457 static bool NetworkHasJoiningClient()
00458 {
00459   const NetworkClientSocket *cs;
00460   FOR_ALL_CLIENT_SOCKETS(cs) {
00461     if (cs->status >= STATUS_AUTHORIZED && cs->status < STATUS_ACTIVE) return true;
00462   }
00463 
00464   return false;
00465 }
00466 
00470 static void CheckPauseOnJoin()
00471 {
00472   if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED ||
00473       (!_settings_client.network.pause_on_join && (_pause_mode & PM_PAUSED_JOIN) == PM_UNPAUSED)) {
00474     return;
00475   }
00476   CheckPauseHelper(NetworkHasJoiningClient(), PM_PAUSED_JOIN);
00477 }
00478 
00485 void ParseConnectionString(const char **company, const char **port, char *connection_string)
00486 {
00487   bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':'));
00488   char *p;
00489   for (p = connection_string; *p != '\0'; p++) {
00490     switch (*p) {
00491       case '[':
00492         ipv6 = true;
00493         break;
00494 
00495       case ']':
00496         ipv6 = false;
00497         break;
00498 
00499       case '#':
00500         *company = p + 1;
00501         *p = '\0';
00502         break;
00503 
00504       case ':':
00505         if (ipv6) break;
00506         *port = p + 1;
00507         *p = '\0';
00508         break;
00509     }
00510   }
00511 }
00512 
00513 /* Creates a new client from a socket
00514  *   Used both by the server and the client */
00515 static NetworkClientSocket *NetworkAllocClient(SOCKET s)
00516 {
00517   if (_network_server) {
00518     /* Can we handle a new client? */
00519     if (_network_clients_connected >= MAX_CLIENTS) return NULL;
00520     if (_network_game_info.clients_on >= _settings_client.network.max_clients) return NULL;
00521 
00522     /* Register the login */
00523     _network_clients_connected++;
00524   }
00525 
00526   NetworkClientSocket *cs = new NetworkClientSocket(INVALID_CLIENT_ID);
00527   cs->sock = s;
00528   cs->last_frame = _frame_counter;
00529   cs->last_frame_server = _frame_counter;
00530 
00531   if (_network_server) {
00532     cs->client_id = _network_client_id++;
00533     NetworkClientInfo *ci = new NetworkClientInfo(cs->client_id);
00534     cs->SetInfo(ci);
00535     ci->client_playas = COMPANY_INACTIVE_CLIENT;
00536     ci->join_date = _date;
00537 
00538     SetWindowDirty(WC_CLIENT_LIST, 0);
00539   }
00540 
00541   return cs;
00542 }
00543 
00544 /* Close a connection */
00545 NetworkRecvStatus NetworkCloseClient(NetworkClientSocket *cs, NetworkRecvStatus status)
00546 {
00547   assert(status != NETWORK_RECV_STATUS_OKAY);
00548   /*
00549    * Sending a message just before leaving the game calls cs->Send_Packets.
00550    * This might invoke this function, which means that when we close the
00551    * connection after cs->Send_Packets we will close an already closed
00552    * connection. This handles that case gracefully without having to make
00553    * that code any more complex or more aware of the validity of the socket.
00554    */
00555   if (cs->sock == INVALID_SOCKET) return status;
00556 
00557   if (status != NETWORK_RECV_STATUS_CONN_LOST && !cs->HasClientQuit() && _network_server && cs->status >= STATUS_AUTHORIZED) {
00558     /* We did not receive a leave message from this client... */
00559     char client_name[NETWORK_CLIENT_NAME_LENGTH];
00560     NetworkClientSocket *new_cs;
00561 
00562     NetworkGetClientName(client_name, sizeof(client_name), cs);
00563 
00564     NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
00565 
00566     /* Inform other clients of this... strange leaving ;) */
00567     FOR_ALL_CLIENT_SOCKETS(new_cs) {
00568       if (new_cs->status > STATUS_AUTHORIZED && cs != new_cs) {
00569         SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->client_id, NETWORK_ERROR_CONNECTION_LOST);
00570       }
00571     }
00572   }
00573 
00574   DEBUG(net, 1, "Closed client connection %d", cs->client_id);
00575 
00576   if (_network_server) {
00577     /* We just lost one client :( */
00578     if (cs->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--;
00579     _network_clients_connected--;
00580 
00581     SetWindowDirty(WC_CLIENT_LIST, 0);
00582   }
00583 
00584   cs->Send_Packets(true);
00585 
00586   delete cs->GetInfo();
00587   delete cs;
00588 
00589   return status;
00590 }
00591 
00592 /* For the server, to accept new clients */
00593 static void NetworkAcceptClients(SOCKET ls)
00594 {
00595   for (;;) {
00596     struct sockaddr_storage sin;
00597     memset(&sin, 0, sizeof(sin));
00598     socklen_t sin_len = sizeof(sin);
00599     SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
00600     if (s == INVALID_SOCKET) return;
00601 
00602     SetNonBlocking(s); // XXX error handling?
00603 
00604     NetworkAddress address(sin, sin_len);
00605     DEBUG(net, 1, "Client connected from %s on frame %d", address.GetHostname(), _frame_counter);
00606 
00607     SetNoDelay(s); // XXX error handling?
00608 
00609     /* Check if the client is banned */
00610     bool banned = false;
00611     for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) {
00612       banned = address.IsInNetmask(*iter);
00613       if (banned) {
00614         Packet p(PACKET_SERVER_BANNED);
00615         p.PrepareToSend();
00616 
00617         DEBUG(net, 1, "Banned ip tried to join (%s), refused", *iter);
00618 
00619         send(s, (const char*)p.buffer, p.size, 0);
00620         closesocket(s);
00621         break;
00622       }
00623     }
00624     /* If this client is banned, continue with next client */
00625     if (banned) continue;
00626 
00627     NetworkClientSocket *cs = NetworkAllocClient(s);
00628     if (cs == NULL) {
00629       /* no more clients allowed?
00630        * Send to the client that we are full! */
00631       Packet p(PACKET_SERVER_FULL);
00632       p.PrepareToSend();
00633 
00634       send(s, (const char*)p.buffer, p.size, 0);
00635       closesocket(s);
00636 
00637       continue;
00638     }
00639 
00640     /* a new client has connected. We set him at inactive for now
00641      *  maybe he is only requesting server-info. Till he has sent a PACKET_CLIENT_MAP_OK
00642      *  the client stays inactive */
00643     cs->status = STATUS_INACTIVE;
00644 
00645     cs->GetInfo()->client_address = address; // Save the IP of the client
00646   }
00647 }
00648 
00649 /* Set up the listen socket for the server */
00650 static bool NetworkListen()
00651 {
00652   assert(_listensockets.Length() == 0);
00653 
00654   NetworkAddressList addresses;
00655   GetBindAddresses(&addresses, _settings_client.network.server_port);
00656 
00657   for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) {
00658     address->Listen(SOCK_STREAM, &_listensockets);
00659   }
00660 
00661   if (_listensockets.Length() == 0) {
00662     ServerStartError("Could not create listening socket");
00663     return false;
00664   }
00665 
00666   return true;
00667 }
00668 
00670 static void InitializeNetworkPools()
00671 {
00672   _networkclientsocket_pool.CleanPool();
00673   _networkclientinfo_pool.CleanPool();
00674 }
00675 
00676 /* Close all current connections */
00677 static void NetworkClose()
00678 {
00679   NetworkClientSocket *cs;
00680 
00681   FOR_ALL_CLIENT_SOCKETS(cs) {
00682     if (!_network_server) {
00683       SEND_COMMAND(PACKET_CLIENT_QUIT)();
00684       cs->Send_Packets(true);
00685     }
00686     NetworkCloseClient(cs, NETWORK_RECV_STATUS_CONN_LOST);
00687   }
00688 
00689   if (_network_server) {
00690     /* We are a server, also close the listensocket */
00691     for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00692       closesocket(s->second);
00693     }
00694     _listensockets.Clear();
00695     DEBUG(net, 1, "[tcp] closed listeners");
00696   }
00697 
00698   TCPConnecter::KillAll();
00699 
00700   _networking = false;
00701   _network_server = false;
00702 
00703   NetworkFreeLocalCommandQueue();
00704 
00705   free(_network_company_states);
00706   _network_company_states = NULL;
00707 
00708   InitializeNetworkPools();
00709 }
00710 
00711 /* Inits the network (cleans sockets and stuff) */
00712 static void NetworkInitialize()
00713 {
00714   InitializeNetworkPools();
00715   NetworkUDPInitialize();
00716 
00717   _sync_frame = 0;
00718   _network_first_time = true;
00719 
00720   _network_reconnect = 0;
00721 }
00722 
00724 class TCPQueryConnecter : TCPConnecter {
00725 public:
00726   TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00727 
00728   virtual void OnFailure()
00729   {
00730     NetworkDisconnect();
00731   }
00732 
00733   virtual void OnConnect(SOCKET s)
00734   {
00735     _networking = true;
00736     NetworkAllocClient(s);
00737     SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
00738   }
00739 };
00740 
00741 /* Query a server to fetch his game-info
00742  *  If game_info is true, only the gameinfo is fetched,
00743  *   else only the client_info is fetched */
00744 void NetworkTCPQueryServer(NetworkAddress address)
00745 {
00746   if (!_network_available) return;
00747 
00748   NetworkDisconnect();
00749   NetworkInitialize();
00750 
00751   new TCPQueryConnecter(address);
00752 }
00753 
00754 /* Validates an address entered as a string and adds the server to
00755  * the list. If you use this function, the games will be marked
00756  * as manually added. */
00757 void NetworkAddServer(const char *b)
00758 {
00759   if (*b != '\0') {
00760     const char *port = NULL;
00761     const char *company = NULL;
00762     char host[NETWORK_HOSTNAME_LENGTH];
00763     uint16 rport;
00764 
00765     strecpy(host, b, lastof(host));
00766 
00767     strecpy(_settings_client.network.connect_to_ip, b, lastof(_settings_client.network.connect_to_ip));
00768     rport = NETWORK_DEFAULT_PORT;
00769 
00770     ParseConnectionString(&company, &port, host);
00771     if (port != NULL) rport = atoi(port);
00772 
00773     NetworkUDPQueryServer(NetworkAddress(host, rport), true);
00774   }
00775 }
00776 
00782 void GetBindAddresses(NetworkAddressList *addresses, uint16 port)
00783 {
00784   for (char **iter = _network_bind_list.Begin(); iter != _network_bind_list.End(); iter++) {
00785     *addresses->Append() = NetworkAddress(*iter, port);
00786   }
00787 
00788   /* No address, so bind to everything. */
00789   if (addresses->Length() == 0) {
00790     *addresses->Append() = NetworkAddress("", port);
00791   }
00792 }
00793 
00794 /* Generates the list of manually added hosts from NetworkGameList and
00795  * dumps them into the array _network_host_list. This array is needed
00796  * by the function that generates the config file. */
00797 void NetworkRebuildHostList()
00798 {
00799   _network_host_list.Clear();
00800 
00801   for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) {
00802     if (item->manually) *_network_host_list.Append() = strdup(item->address.GetAddressAsString(false));
00803   }
00804 }
00805 
00807 class TCPClientConnecter : TCPConnecter {
00808 public:
00809   TCPClientConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00810 
00811   virtual void OnFailure()
00812   {
00813     NetworkError(STR_NETWORK_ERROR_NOCONNECTION);
00814   }
00815 
00816   virtual void OnConnect(SOCKET s)
00817   {
00818     _networking = true;
00819     NetworkAllocClient(s);
00820     IConsoleCmdExec("exec scripts/on_client.scr 0");
00821     NetworkClient_Connected();
00822   }
00823 };
00824 
00825 
00826 /* Used by clients, to connect to a server */
00827 void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password, const char *join_company_password)
00828 {
00829   if (!_network_available) return;
00830 
00831   if (address.GetPort() == 0) return;
00832 
00833   strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host));
00834   _settings_client.network.last_port = address.GetPort();
00835   _network_join_as = join_as;
00836   _network_join_server_password = join_server_password;
00837   _network_join_company_password = join_company_password;
00838 
00839   NetworkDisconnect();
00840   NetworkInitialize();
00841 
00842   _network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
00843   ShowJoinStatusWindow();
00844 
00845   new TCPClientConnecter(address);
00846 }
00847 
00848 static void NetworkInitGameInfo()
00849 {
00850   if (StrEmpty(_settings_client.network.server_name)) {
00851     snprintf(_settings_client.network.server_name, sizeof(_settings_client.network.server_name), "Unnamed Server");
00852   }
00853 
00854   /* The server is a client too */
00855   _network_game_info.clients_on = _network_dedicated ? 0 : 1;
00856 
00857   NetworkClientInfo *ci = new NetworkClientInfo(CLIENT_ID_SERVER);
00858   ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : _local_company;
00859   /* Give the server a valid IP; banning it is pointless anyways */
00860   sockaddr_in sock;
00861   memset(&sock, 0, sizeof(sock));
00862   sock.sin_family = AF_INET;
00863   ci->client_address = NetworkAddress((sockaddr*)&sock, sizeof(sock));
00864 
00865   strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name));
00866 }
00867 
00868 bool NetworkServerStart()
00869 {
00870   if (!_network_available) return false;
00871 
00872   /* Call the pre-scripts */
00873   IConsoleCmdExec("exec scripts/pre_server.scr 0");
00874   if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
00875 
00876   NetworkDisconnect();
00877   NetworkInitialize();
00878   if (!NetworkListen()) return false;
00879 
00880   /* Try to start UDP-server */
00881   _network_udp_server = _udp_server_socket->Listen();
00882 
00883   _network_company_states = CallocT<NetworkCompanyState>(MAX_COMPANIES);
00884   _network_server = true;
00885   _networking = true;
00886   _frame_counter = 0;
00887   _frame_counter_server = 0;
00888   _frame_counter_max = 0;
00889   _last_sync_frame = 0;
00890   _network_own_client_id = CLIENT_ID_SERVER;
00891 
00892   _network_clients_connected = 0;
00893   _network_company_passworded = 0;
00894 
00895   NetworkInitGameInfo();
00896 
00897   /* execute server initialization script */
00898   IConsoleCmdExec("exec scripts/on_server.scr 0");
00899   /* if the server is dedicated ... add some other script */
00900   if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
00901 
00902   /* Try to register us to the master server */
00903   _network_last_advertise_frame = 0;
00904   _network_need_advertise = true;
00905   NetworkUDPAdvertise();
00906   return true;
00907 }
00908 
00909 /* The server is rebooting...
00910  * The only difference with NetworkDisconnect, is the packets that is sent */
00911 void NetworkReboot()
00912 {
00913   if (_network_server) {
00914     NetworkClientSocket *cs;
00915     FOR_ALL_CLIENT_SOCKETS(cs) {
00916       SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs);
00917       cs->Send_Packets();
00918     }
00919   }
00920 
00921   NetworkClose();
00922 }
00923 
00928 void NetworkDisconnect(bool blocking)
00929 {
00930   if (_network_server) {
00931     NetworkClientSocket *cs;
00932     FOR_ALL_CLIENT_SOCKETS(cs) {
00933       SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs);
00934       cs->Send_Packets();
00935     }
00936   }
00937 
00938   if (_settings_client.network.server_advertise) NetworkUDPRemoveAdvertise(blocking);
00939 
00940   DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00941 
00942   NetworkClose();
00943 
00944   /* Reinitialize the UDP stack, i.e. close all existing connections. */
00945   NetworkUDPInitialize();
00946 }
00947 
00952 static bool NetworkReceive()
00953 {
00954   NetworkClientSocket *cs;
00955   fd_set read_fd, write_fd;
00956   struct timeval tv;
00957 
00958   FD_ZERO(&read_fd);
00959   FD_ZERO(&write_fd);
00960 
00961   FOR_ALL_CLIENT_SOCKETS(cs) {
00962     FD_SET(cs->sock, &read_fd);
00963     FD_SET(cs->sock, &write_fd);
00964   }
00965 
00966   /* take care of listener port */
00967   for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00968     FD_SET(s->second, &read_fd);
00969   }
00970 
00971   tv.tv_sec = tv.tv_usec = 0; // don't block at all.
00972 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00973   int n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
00974 #else
00975   int n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
00976 #endif
00977   if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERROR_LOSTCONNECTION);
00978 
00979   /* accept clients.. */
00980   for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00981     if (FD_ISSET(s->second, &read_fd)) NetworkAcceptClients(s->second);
00982   }
00983 
00984   /* read stuff from clients */
00985   FOR_ALL_CLIENT_SOCKETS(cs) {
00986     cs->writable = !!FD_ISSET(cs->sock, &write_fd);
00987     if (FD_ISSET(cs->sock, &read_fd)) {
00988       if (_network_server) {
00989         NetworkServer_ReadPackets(cs);
00990       } else {
00991         NetworkRecvStatus res;
00992 
00993         /* The client already was quiting! */
00994         if (cs->HasClientQuit()) return false;
00995 
00996         res = NetworkClient_ReadPackets(cs);
00997         if (res != NETWORK_RECV_STATUS_OKAY) {
00998           /* The client made an error of which we can not recover
00999            *   close the client and drop back to main menu */
01000           NetworkClientError(res, cs);
01001           return false;
01002         }
01003       }
01004     }
01005   }
01006   return _networking;
01007 }
01008 
01009 /* This sends all buffered commands (if possible) */
01010 static void NetworkSend()
01011 {
01012   NetworkClientSocket *cs;
01013   FOR_ALL_CLIENT_SOCKETS(cs) {
01014     if (cs->writable) {
01015       if (cs->Send_Packets() && cs->status == STATUS_MAP) {
01016         /* This client is in the middle of a map-send, call the function for that */
01017         SEND_COMMAND(PACKET_SERVER_MAP)(cs);
01018       }
01019     }
01020   }
01021 }
01022 
01023 static bool NetworkDoClientLoop()
01024 {
01025   _frame_counter++;
01026 
01027   NetworkExecuteLocalCommandQueue();
01028 
01029   StateGameLoop();
01030 
01031   /* Check if we are in sync! */
01032   if (_sync_frame != 0) {
01033     if (_sync_frame == _frame_counter) {
01034 #ifdef NETWORK_SEND_DOUBLE_SEED
01035       if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
01036 #else
01037       if (_sync_seed_1 != _random.state[0]) {
01038 #endif
01039         NetworkError(STR_NETWORK_ERROR_DESYNC);
01040         DEBUG(desync, 1, "sync_err: %08x; %02x", _date, _date_fract);
01041         DEBUG(net, 0, "Sync error detected!");
01042         NetworkClientError(NETWORK_RECV_STATUS_DESYNC, NetworkClientSocket::Get(0));
01043         return false;
01044       }
01045 
01046       /* If this is the first time we have a sync-frame, we
01047        *   need to let the server know that we are ready and at the same
01048        *   frame as he is.. so we can start playing! */
01049       if (_network_first_time) {
01050         _network_first_time = false;
01051         SEND_COMMAND(PACKET_CLIENT_ACK)();
01052       }
01053 
01054       _sync_frame = 0;
01055     } else if (_sync_frame < _frame_counter) {
01056       DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
01057       _sync_frame = 0;
01058     }
01059   }
01060 
01061   return true;
01062 }
01063 
01064 /* We have to do some UDP checking */
01065 void NetworkUDPGameLoop()
01066 {
01067   _network_content_client.SendReceive();
01068   TCPConnecter::CheckCallbacks();
01069   NetworkHTTPSocketHandler::HTTPReceive();
01070 
01071   if (_network_udp_server) {
01072     _udp_server_socket->ReceivePackets();
01073     _udp_master_socket->ReceivePackets();
01074   } else {
01075     _udp_client_socket->ReceivePackets();
01076     if (_network_udp_broadcast > 0) _network_udp_broadcast--;
01077     NetworkGameListRequery();
01078   }
01079 }
01080 
01081 /* The main loop called from ttd.c
01082  *  Here we also have to do StateGameLoop if needed! */
01083 void NetworkGameLoop()
01084 {
01085   if (!_networking) return;
01086 
01087   if (!NetworkReceive()) return;
01088 
01089   if (_network_server) {
01090     /* Log the sync state to check for in-syncedness of replays. */
01091     if (_date_fract == 0) {
01092       /* We don't want to log multiple times if paused. */
01093       static Date last_log;
01094       if (last_log != _date) {
01095         DEBUG(desync, 1, "sync: %08x; %02x; %08x; %08x", _date, _date_fract, _random.state[0], _random.state[1]);
01096         last_log = _date;
01097       }
01098     }
01099 
01100 #ifdef DEBUG_DUMP_COMMANDS
01101     /* Loading of the debug commands from -ddesync>=1 */
01102     static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
01103     static Date next_date = 0;
01104     static uint32 next_date_fract;
01105     static CommandPacket *cp = NULL;
01106     static bool check_sync_state = false;
01107     static uint32 sync_state[2];
01108     if (f == NULL && next_date == 0) {
01109       DEBUG(net, 0, "Cannot open commands.log");
01110       next_date = 1;
01111     }
01112 
01113     while (f != NULL && !feof(f)) {
01114       if (_date == next_date && _date_fract == next_date_fract) {
01115         if (cp != NULL) {
01116           NetworkSend_Command(cp->tile, cp->p1, cp->p2, cp->cmd & ~CMD_FLAGS_MASK, NULL, cp->text, cp->company);
01117           DEBUG(net, 0, "injecting: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, cp->tile, cp->p1, cp->p2, cp->cmd, cp->text, GetCommandName(cp->cmd));
01118           free(cp);
01119           cp = NULL;
01120         }
01121         if (check_sync_state) {
01122           if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) {
01123             DEBUG(net, 0, "sync check: %08x; %02x; match", _date, _date_fract);
01124           } else {
01125             DEBUG(net, 0, "sync check: %08x; %02x; mismatch expected {%08x, %08x}, got {%08x, %08x}",
01126                   _date, _date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]);
01127             NOT_REACHED();
01128           }
01129           check_sync_state = false;
01130         }
01131       }
01132 
01133       if (cp != NULL || check_sync_state) break;
01134 
01135       char buff[4096];
01136       if (fgets(buff, lengthof(buff), f) == NULL) break;
01137 
01138       char *p = buff;
01139       /* Ignore the "[date time] " part of the message */
01140       if (*p == '[') {
01141         p = strchr(p, ']');
01142         if (p == NULL) break;
01143         p += 2;
01144       }
01145 
01146       if (strncmp(p, "cmd: ", 5) == 0) {
01147         cp = CallocT<CommandPacket>(1);
01148         int company;
01149         int ret = sscanf(p + 5, "%x; %x; %x; %x; %x; %x; %x; \"%[^\"]\"", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text);
01150         /* There are 8 pieces of data to read, however the last is a
01151          * string that might or might not exist. Ignore it if that
01152          * string misses because in 99% of the time it's not used. */
01153         assert(ret == 8 || ret == 7);
01154         cp->company = (CompanyID)company;
01155       } else if (strncmp(p, "join: ", 6) == 0) {
01156         /* Manually insert a pause when joining; this way the client can join at the exact right time. */
01157         int ret = sscanf(p + 6, "%x; %x", &next_date, &next_date_fract);
01158         assert(ret == 2);
01159         DEBUG(net, 0, "injecting pause for join at %08x:%02x; please join when paused", next_date, next_date_fract);
01160         cp = CallocT<CommandPacket>(1);
01161         cp->company = COMPANY_SPECTATOR;
01162         cp->cmd = CMD_PAUSE;
01163         cp->p1 = PM_PAUSED_NORMAL;
01164         cp->p2 = 1;
01165         _ddc_fastforward = false;
01166       } else if (strncmp(p, "sync: ", 6) == 0) {
01167         int ret = sscanf(p + 6, "%x; %x; %x; %x", &next_date, &next_date_fract, &sync_state[0], &sync_state[1]);
01168         assert(ret == 4);
01169         check_sync_state = true;
01170       } else if (strncmp(p, "msg: ", 5) == 0 || strncmp(p, "client: ", 8) == 0 ||
01171             strncmp(p, "load: ", 6) == 0 || strncmp(p, "save: ", 6) == 0) {
01172         /* A message that is not very important to the log playback, but part of the log. */
01173       } else {
01174         /* Can't parse a line; what's wrong here? */
01175         DEBUG(net, 0, "trying to parse: %s", p);
01176         NOT_REACHED();
01177       }
01178     }
01179     if (f != NULL && feof(f)) {
01180       DEBUG(net, 0, "End of commands.log");
01181       fclose(f);
01182       f = NULL;
01183     }
01184 #endif /* DEBUG_DUMP_COMMANDS */
01185     if (_frame_counter >= _frame_counter_max) {
01186       /* Only check for active clients just before we're going to send out
01187        * the commands so we don't send multiple pause/unpause commands when
01188        * the frame_freq is more than 1 tick. */
01189       CheckPauseOnJoin();
01190       CheckMinActiveClients();
01191     }
01192 
01193     bool send_frame = false;
01194 
01195     /* We first increase the _frame_counter */
01196     _frame_counter++;
01197     /* Update max-frame-counter */
01198     if (_frame_counter > _frame_counter_max) {
01199       _frame_counter_max = _frame_counter + _settings_client.network.frame_freq;
01200       send_frame = true;
01201     }
01202 
01203     NetworkExecuteLocalCommandQueue();
01204 
01205     /* Then we make the frame */
01206     StateGameLoop();
01207 
01208     _sync_seed_1 = _random.state[0];
01209 #ifdef NETWORK_SEND_DOUBLE_SEED
01210     _sync_seed_2 = _random.state[1];
01211 #endif
01212 
01213     NetworkServer_Tick(send_frame);
01214   } else {
01215     /* Client */
01216 
01217     /* Make sure we are at the frame were the server is (quick-frames) */
01218     if (_frame_counter_server > _frame_counter) {
01219       while (_frame_counter_server > _frame_counter) {
01220         if (!NetworkDoClientLoop()) break;
01221       }
01222     } else {
01223       /* Else, keep on going till _frame_counter_max */
01224       if (_frame_counter_max > _frame_counter) NetworkDoClientLoop();
01225     }
01226   }
01227 
01228   NetworkSend();
01229 }
01230 
01231 static void NetworkGenerateServerId()
01232 {
01233   Md5 checksum;
01234   uint8 digest[16];
01235   char hex_output[16 * 2 + 1];
01236   char coding_string[NETWORK_NAME_LENGTH];
01237   int di;
01238 
01239   snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Server ID");
01240 
01241   /* Generate the MD5 hash */
01242   checksum.Append((const uint8*)coding_string, strlen(coding_string));
01243   checksum.Finish(digest);
01244 
01245   for (di = 0; di < 16; ++di) {
01246     sprintf(hex_output + di * 2, "%02x", digest[di]);
01247   }
01248 
01249   /* _settings_client.network.network_id is our id */
01250   snprintf(_settings_client.network.network_id, sizeof(_settings_client.network.network_id), "%s", hex_output);
01251 }
01252 
01253 void NetworkStartDebugLog(NetworkAddress address)
01254 {
01255   extern SOCKET _debug_socket;  // Comes from debug.c
01256 
01257   DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort());
01258 
01259   SOCKET s = address.Connect();
01260   if (s == INVALID_SOCKET) {
01261     DEBUG(net, 0, "Failed to open socket for redirection DEBUG()");
01262     return;
01263   }
01264 
01265   _debug_socket = s;
01266 
01267   DEBUG(net, 0, "DEBUG() is now redirected");
01268 }
01269 
01271 void NetworkStartUp()
01272 {
01273   DEBUG(net, 3, "[core] starting network...");
01274 
01275   /* Network is available */
01276   _network_available = NetworkCoreInitialize();
01277   _network_dedicated = false;
01278   _network_last_advertise_frame = 0;
01279   _network_need_advertise = true;
01280   _network_advertise_retries = 0;
01281 
01282   /* Generate an server id when there is none yet */
01283   if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateServerId();
01284 
01285   memset(&_network_game_info, 0, sizeof(_network_game_info));
01286 
01287   NetworkInitialize();
01288   DEBUG(net, 3, "[core] network online, multiplayer available");
01289   NetworkFindBroadcastIPs(&_broadcast_list);
01290 }
01291 
01293 void NetworkShutDown()
01294 {
01295   NetworkDisconnect(true);
01296   NetworkUDPClose();
01297 
01298   DEBUG(net, 3, "[core] shutting down network");
01299 
01300   _network_available = false;
01301 
01302   NetworkCoreShutdown();
01303 }
01304 
01309 bool IsNetworkCompatibleVersion(const char *other)
01310 {
01311   return strncmp(_openttd_revision, other, NETWORK_REVISION_LENGTH - 1) == 0;
01312 }
01313 
01314 #endif /* ENABLE_NETWORK */

Generated on Sat Nov 20 20:59:04 2010 for OpenTTD by  doxygen 1.6.1