network.cpp

00001 /* $Id: network.cpp 13735 2008-07-19 12:23:14Z rubidium $ */
00002 
00003 #include "../stdafx.h"
00004 #include "network_data.h"
00005 
00006 #ifdef ENABLE_NETWORK
00007 
00008 #include "../openttd.h"
00009 #include "../debug.h"
00010 #include "../strings_func.h"
00011 #include "../map_func.h"
00012 #include "../command_func.h"
00013 #include "../variables.h"
00014 #include "../date_func.h"
00015 #include "../newgrf_config.h"
00016 #include "network_client.h"
00017 #include "network_server.h"
00018 #include "network_udp.h"
00019 #include "network_gamelist.h"
00020 #include "core/udp.h"
00021 #include "core/tcp.h"
00022 #include "core/core.h"
00023 #include "network_gui.h"
00024 #include "../console.h" /* IConsoleCmdExec */
00025 #include <stdarg.h> /* va_list */
00026 #include "../md5.h"
00027 #include "../fileio.h"
00028 #include "../texteff.hpp"
00029 #include "../core/random_func.hpp"
00030 #include "../window_func.h"
00031 #include "../string_func.h"
00032 #include "../player_func.h"
00033 #include "../settings_type.h"
00034 #ifdef DEBUG_DUMP_COMMANDS
00035   #include "../core/alloc_func.hpp"
00036 #endif /* DEBUG_DUMP_COMMANDS */
00037 
00038 #include "table/strings.h"
00039 
00040 bool _network_reload_cfg;
00041 bool _network_server;     
00042 bool _network_available;  
00043 bool _network_dedicated;  
00044 bool _network_advertise;  
00045 
00046 /* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */
00047 assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE);
00048 assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME + 1);
00049 
00050 // global variables (declared in network_data.h)
00051 CommandPacket *_local_command_queue;
00052 
00053 extern NetworkUDPSocketHandler *_udp_client_socket; 
00054 extern NetworkUDPSocketHandler *_udp_server_socket; 
00055 extern NetworkUDPSocketHandler *_udp_master_socket; 
00056 
00057 // Here we keep track of the clients
00058 //  (and the client uses [0] for his own communication)
00059 NetworkTCPSocketHandler _clients[MAX_CLIENTS];
00060 
00061 
00062 
00063 // The listen socket for the server
00064 static SOCKET _listensocket;
00065 
00066 // The amount of clients connected
00067 static byte _network_clients_connected = 0;
00068 // The index counter for new clients (is never decreased)
00069 static uint16 _network_client_index = NETWORK_SERVER_INDEX + 1;
00070 
00071 /* Some externs / forwards */
00072 extern void StateGameLoop();
00073 
00074 // Function that looks up the CI for a given client-index
00075 NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index)
00076 {
00077   NetworkClientInfo *ci;
00078 
00079   for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
00080     if (ci->client_index == client_index) return ci;
00081   }
00082 
00083   return NULL;
00084 }
00085 
00089 NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip)
00090 {
00091   NetworkClientInfo *ci;
00092   uint32 ip_number = inet_addr(ip);
00093 
00094   for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
00095     if (ci->client_ip == ip_number) return ci;
00096   }
00097 
00098   return NULL;
00099 }
00100 
00101 // Function that looks up the CS for a given client-index
00102 NetworkTCPSocketHandler *NetworkFindClientStateFromIndex(uint16 client_index)
00103 {
00104   NetworkTCPSocketHandler *cs;
00105 
00106   for (cs = _clients; cs != endof(_clients); cs++) {
00107     if (cs->index == client_index) return cs;
00108   }
00109 
00110   return NULL;
00111 }
00112 
00113 // NetworkGetClientName is a server-safe function to get the name of the client
00114 //  if the user did not send it yet, Client #<no> is used.
00115 void NetworkGetClientName(char *client_name, size_t size, const NetworkTCPSocketHandler *cs)
00116 {
00117   const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
00118 
00119   if (ci->client_name[0] == '\0') {
00120     snprintf(client_name, size, "Client #%4d", cs->index);
00121   } else {
00122     ttd_strlcpy(client_name, ci->client_name, size);
00123   }
00124 }
00125 
00126 byte NetworkSpectatorCount()
00127 {
00128   NetworkTCPSocketHandler *cs;
00129   byte count = 0;
00130 
00131   FOR_ALL_CLIENTS(cs) {
00132     if (DEREF_CLIENT_INFO(cs)->client_playas == PLAYER_SPECTATOR) count++;
00133   }
00134 
00135   return count;
00136 }
00137 
00138 // This puts a text-message to the console, or in the future, the chat-box,
00139 //  (to keep it all a bit more general)
00140 // If 'self_send' is true, this is the client who is sending the message
00141 void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send, const char *name, const char *str, ...)
00142 {
00143   char buf[1024];
00144   va_list va;
00145   const int duration = 10; // Game days the messages stay visible
00146   char message[1024];
00147   char temp[1024];
00148 
00149   va_start(va, str);
00150   vsnprintf(buf, lengthof(buf), str, va);
00151   va_end(va);
00152 
00153   switch (action) {
00154     case NETWORK_ACTION_SERVER_MESSAGE:
00155       color = 1;
00156       snprintf(message, sizeof(message), "*** %s", buf);
00157       break;
00158     case NETWORK_ACTION_JOIN:
00159       color = 1;
00160       GetString(temp, STR_NETWORK_CLIENT_JOINED, lastof(temp));
00161       snprintf(message, sizeof(message), "*** %s %s", name, temp);
00162       break;
00163     case NETWORK_ACTION_LEAVE:
00164       color = 1;
00165       GetString(temp, STR_NETWORK_ERR_LEFT, lastof(temp));
00166       snprintf(message, sizeof(message), "*** %s %s (%s)", name, temp, buf);
00167       break;
00168     case NETWORK_ACTION_GIVE_MONEY:
00169       if (self_send) {
00170         SetDParamStr(0, name);
00171         SetDParam(1, atoi(buf));
00172         GetString(temp, STR_NETWORK_GAVE_MONEY_AWAY, lastof(temp));
00173         snprintf(message, sizeof(message), "*** %s", temp);
00174       } else {
00175         SetDParam(0, atoi(buf));
00176         GetString(temp, STR_NETWORK_GIVE_MONEY, lastof(temp));
00177         snprintf(message, sizeof(message), "*** %s %s", name, temp);
00178       }
00179       break;
00180     case NETWORK_ACTION_NAME_CHANGE:
00181       GetString(temp, STR_NETWORK_NAME_CHANGE, lastof(temp));
00182       snprintf(message, sizeof(message), "*** %s %s %s", name, temp, buf);
00183       break;
00184     case NETWORK_ACTION_CHAT_COMPANY:
00185       SetDParamStr(0, name);
00186       SetDParamStr(1, buf);
00187       GetString(temp, self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY, lastof(temp));
00188       ttd_strlcpy(message, temp, sizeof(message));
00189       break;
00190     case NETWORK_ACTION_CHAT_CLIENT:
00191       SetDParamStr(0, name);
00192       SetDParamStr(1, buf);
00193       GetString(temp, self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT, lastof(temp));
00194       ttd_strlcpy(message, temp, sizeof(message));
00195       break;
00196     default:
00197       SetDParamStr(0, name);
00198       SetDParamStr(1, buf);
00199       GetString(temp, STR_NETWORK_CHAT_ALL, lastof(temp));
00200       ttd_strlcpy(message, temp, sizeof(message));
00201       break;
00202   }
00203 
00204   DebugDumpCommands("ddc:cmsg:%d;%d;%s\n", _date, _date_fract, message);
00205   IConsolePrintF(color, "%s", message);
00206   AddChatMessage(color, duration, "%s", message);
00207 }
00208 
00209 // Calculate the frame-lag of a client
00210 uint NetworkCalculateLag(const NetworkTCPSocketHandler *cs)
00211 {
00212   int lag = cs->last_frame_server - cs->last_frame;
00213   // This client has missed his ACK packet after 1 DAY_TICKS..
00214   //  so we increase his lag for every frame that passes!
00215   // The packet can be out by a max of _net_frame_freq
00216   if (cs->last_frame_server + DAY_TICKS + _network_frame_freq < _frame_counter)
00217     lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _network_frame_freq);
00218 
00219   return lag;
00220 }
00221 
00222 
00223 // There was a non-recoverable error, drop back to the main menu with a nice
00224 //  error
00225 static void NetworkError(StringID error_string)
00226 {
00227   _switch_mode = SM_MENU;
00228   _switch_mode_errorstr = error_string;
00229 }
00230 
00231 static void ClientStartError(const char *error)
00232 {
00233   DEBUG(net, 0, "[client] could not start network: %s",error);
00234   NetworkError(STR_NETWORK_ERR_CLIENT_START);
00235 }
00236 
00237 static void ServerStartError(const char *error)
00238 {
00239   DEBUG(net, 0, "[server] could not start network: %s",error);
00240   NetworkError(STR_NETWORK_ERR_SERVER_START);
00241 }
00242 
00243 static void NetworkClientError(NetworkRecvStatus res, NetworkTCPSocketHandler* cs)
00244 {
00245   // First, send a CLIENT_ERROR to the server, so he knows we are
00246   //  disconnection (and why!)
00247   NetworkErrorCode errorno;
00248 
00249   // We just want to close the connection..
00250   if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
00251     cs->has_quit = true;
00252     NetworkCloseClient(cs);
00253     _networking = false;
00254 
00255     DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00256     return;
00257   }
00258 
00259   switch (res) {
00260     case NETWORK_RECV_STATUS_DESYNC:          errorno = NETWORK_ERROR_DESYNC; break;
00261     case NETWORK_RECV_STATUS_SAVEGAME:        errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
00262     case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break;
00263     default:                                  errorno = NETWORK_ERROR_GENERAL; break;
00264   }
00265   // This means we fucked up and the server closed the connection
00266   if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL &&
00267       res != NETWORK_RECV_STATUS_SERVER_BANNED) {
00268     SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
00269 
00270     // Dequeue all commands before closing the socket
00271     DEREF_CLIENT(0)->Send_Packets();
00272   }
00273 
00274   _switch_mode = SM_MENU;
00275   NetworkCloseClient(cs);
00276   _networking = false;
00277 }
00278 
00283 char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last)
00284 {
00285   /* List of possible network errors, used by
00286    * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */
00287   static const StringID network_error_strings[] = {
00288     STR_NETWORK_ERR_CLIENT_GENERAL,
00289     STR_NETWORK_ERR_CLIENT_DESYNC,
00290     STR_NETWORK_ERR_CLIENT_SAVEGAME,
00291     STR_NETWORK_ERR_CLIENT_CONNECTION_LOST,
00292     STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR,
00293     STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH,
00294     STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED,
00295     STR_NETWORK_ERR_CLIENT_NOT_EXPECTED,
00296     STR_NETWORK_ERR_CLIENT_WRONG_REVISION,
00297     STR_NETWORK_ERR_CLIENT_NAME_IN_USE,
00298     STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD,
00299     STR_NETWORK_ERR_CLIENT_PLAYER_MISMATCH,
00300     STR_NETWORK_ERR_CLIENT_KICKED,
00301     STR_NETWORK_ERR_CLIENT_CHEATER,
00302     STR_NETWORK_ERR_CLIENT_SERVER_FULL
00303   };
00304 
00305   if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL;
00306 
00307   return GetString(buf, network_error_strings[err], last);
00308 }
00309 
00310 /* Count the number of active clients connected */
00311 static uint NetworkCountPlayers()
00312 {
00313   NetworkTCPSocketHandler *cs;
00314   uint count = 0;
00315 
00316   FOR_ALL_CLIENTS(cs) {
00317     const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
00318     if (IsValidPlayer(ci->client_playas)) count++;
00319   }
00320 
00321   return count;
00322 }
00323 
00324 static bool _min_players_paused = false;
00325 
00326 /* Check if the minimum number of players has been reached and pause or unpause the game as appropriate */
00327 void CheckMinPlayers()
00328 {
00329   if (!_network_dedicated) return;
00330 
00331   if (NetworkCountPlayers() < _network_min_players) {
00332     if (_min_players_paused) return;
00333 
00334     _min_players_paused = true;
00335     DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
00336     NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (not enough players)", NETWORK_SERVER_INDEX);
00337   } else {
00338     if (!_min_players_paused) return;
00339 
00340     _min_players_paused = false;
00341     DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
00342     NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (enough players)", NETWORK_SERVER_INDEX);
00343   }
00344 }
00345 
00346 // Find all IP-aliases for this host
00347 static void NetworkFindIPs()
00348 {
00349 #if !defined(PSP)
00350   int i;
00351 
00352 #if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */
00353   /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
00354   int _netstat(int fd, char **output, int verbose);
00355 
00356   int seek_past_header(char **pos, const char *header) {
00357     char *new_pos = strstr(*pos, header);
00358     if (new_pos == 0) {
00359       return B_ERROR;
00360     }
00361     *pos += strlen(header) + new_pos - *pos + 1;
00362     return B_OK;
00363   }
00364 
00365   int output_length;
00366   char *output_pointer = NULL;
00367   char **output;
00368   int sock = socket(AF_INET, SOCK_DGRAM, 0);
00369   i = 0;
00370 
00371   // If something fails, make sure the list is empty
00372   _broadcast_list[0] = 0;
00373 
00374   if (sock < 0) {
00375     DEBUG(net, 0, "[core] error creating socket");
00376     return;
00377   }
00378 
00379   output_length = _netstat(sock, &output_pointer, 1);
00380   if (output_length < 0) {
00381     DEBUG(net, 0, "[core] error running _netstat");
00382     return;
00383   }
00384 
00385   output = &output_pointer;
00386   if (seek_past_header(output, "IP Interfaces:") == B_OK) {
00387     for (;;) {
00388       uint32 n, fields, read;
00389       uint8 i1, i2, i3, i4, j1, j2, j3, j4;
00390       struct in_addr inaddr;
00391       uint32 ip;
00392       uint32 netmask;
00393 
00394       fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n",
00395                         &n, &i1,&i2,&i3,&i4, &j1,&j2,&j3,&j4, &read);
00396       read += 1;
00397       if (fields != 9) {
00398         break;
00399       }
00400 
00401       ip      = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4;
00402       netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4;
00403 
00404       if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) {
00405         inaddr.s_addr = htonl(ip | ~netmask);
00406         _broadcast_list[i] = inaddr.s_addr;
00407         i++;
00408         if (i == MAX_INTERFACES) break;
00409       }
00410       if (read < 0) {
00411         break;
00412       }
00413       *output += read;
00414     }
00415     /* XXX - Using either one of these crashes openttd heavily? - wber */
00416     /*free(output_pointer);*/
00417     /*free(output);*/
00418     closesocket(sock);
00419   }
00420 #elif defined(HAVE_GETIFADDRS)
00421   struct ifaddrs *ifap, *ifa;
00422 
00423   // If something fails, make sure the list is empty
00424   _broadcast_list[0] = 0;
00425 
00426   if (getifaddrs(&ifap) != 0)
00427     return;
00428 
00429   i = 0;
00430   for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
00431     if (!(ifa->ifa_flags & IFF_BROADCAST)) continue;
00432     if (ifa->ifa_broadaddr == NULL) continue;
00433     if (ifa->ifa_broadaddr->sa_family != AF_INET) continue;
00434     _broadcast_list[i] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr;
00435     i++;
00436     if (i == MAX_INTERFACES) break;
00437   }
00438   freeifaddrs(ifap);
00439 
00440 #else /* not HAVE_GETIFADDRS */
00441   SOCKET sock;
00442 #ifdef WIN32
00443   DWORD len = 0;
00444   INTERFACE_INFO ifo[MAX_INTERFACES];
00445   uint j;
00446 #else
00447   char buf[4 * 1024]; // Arbitrary buffer size
00448   struct ifconf ifconf;
00449   const char* buf_end;
00450   const char* p;
00451 #endif
00452 
00453   // If something fails, make sure the list is empty
00454   _broadcast_list[0] = 0;
00455 
00456   sock = socket(AF_INET, SOCK_DGRAM, 0);
00457   if (sock == INVALID_SOCKET) return;
00458 
00459 #ifdef WIN32
00460   memset(&ifo[0], 0, sizeof(ifo));
00461   if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], sizeof(ifo), &len, NULL, NULL)) != 0) {
00462     closesocket(sock);
00463     return;
00464   }
00465 
00466   i = 0;
00467   for (j = 0; j < len / sizeof(*ifo); j++) {
00468     if (ifo[j].iiFlags & IFF_LOOPBACK) continue;
00469     if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue;
00470     /* iiBroadcast is unusable, because it always seems to be set to
00471      * 255.255.255.255.
00472      */
00473     _broadcast_list[i++] =
00474        ifo[j].iiAddress.AddressIn.sin_addr.s_addr |
00475       ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr;
00476     if (i == MAX_INTERFACES) break;
00477   }
00478 #else
00479   ifconf.ifc_len = sizeof(buf);
00480   ifconf.ifc_buf = buf;
00481   if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) {
00482     closesocket(sock);
00483     return;
00484   }
00485 
00486   i = 0;
00487   buf_end = buf + ifconf.ifc_len;
00488   for (p = buf; p < buf_end;) {
00489     const struct ifreq* req = (const struct ifreq*)p;
00490 
00491     if (req->ifr_addr.sa_family == AF_INET) {
00492       struct ifreq r;
00493 
00494       strncpy(r.ifr_name, req->ifr_name, lengthof(r.ifr_name));
00495       if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 &&
00496           r.ifr_flags & IFF_BROADCAST &&
00497           ioctl(sock, SIOCGIFBRDADDR, &r) != -1) {
00498         _broadcast_list[i++] =
00499           ((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr;
00500         if (i == MAX_INTERFACES) break;
00501       }
00502     }
00503 
00504     p += sizeof(struct ifreq);
00505 #if defined(AF_LINK) && !defined(SUNOS)
00506     p += req->ifr_addr.sa_len - sizeof(struct sockaddr);
00507 #endif
00508   }
00509 #endif
00510 
00511   closesocket(sock);
00512 #endif /* not HAVE_GETIFADDRS */
00513 
00514   _broadcast_list[i] = 0;
00515 
00516   DEBUG(net, 3, "Detected broadcast addresses:");
00517   // Now display to the debug all the detected ips
00518   for (i = 0; _broadcast_list[i] != 0; i++) {
00519     DEBUG(net, 3, "%d) %s", i, inet_ntoa(*(struct in_addr *)&_broadcast_list[i]));//inet_ntoa(inaddr));
00520   }
00521 #endif /* PSP */
00522 }
00523 
00524 // Resolve a hostname to a inet_addr
00525 unsigned long NetworkResolveHost(const char *hostname)
00526 {
00527   in_addr_t ip;
00528 
00529   // First try: is it an ip address?
00530   ip = inet_addr(hostname);
00531 
00532   // If not try to resolve the name
00533   if (ip == INADDR_NONE) {
00534     struct in_addr addr;
00535 #if !defined(PSP)
00536     struct hostent *he = gethostbyname(hostname);
00537     if (he == NULL) {
00538       DEBUG(net, 0, "Cannot resolve '%s'", hostname);
00539       return ip;
00540     }
00541     addr = *(struct in_addr *)he->h_addr_list[0];
00542 #else
00543     int rid = -1;
00544     char buf[1024];
00545 
00546     /* Create a resolver */
00547     if (sceNetResolverCreate(&rid, buf, sizeof(buf)) < 0) {
00548       DEBUG(net, 0, "[NET] Error connecting resolver");
00549       return ip;
00550     }
00551 
00552     /* Try to resolve the name */
00553     if (sceNetResolverStartNtoA(rid, hostname, &addr, 2, 3) < 0) {
00554       DEBUG(net, 0, "[NET] Cannot resolve %s", hostname);
00555       sceNetResolverDelete(rid);
00556       return ip;
00557     }
00558     sceNetResolverDelete(rid);
00559 #endif /* PSP */
00560 
00561     DEBUG(net, 1, "[NET] Resolved %s to %s", hostname, inet_ntoa(addr));
00562     ip = addr.s_addr;
00563   }
00564   return ip;
00565 }
00566 
00573 void ParseConnectionString(const char **player, const char **port, char *connection_string)
00574 {
00575   char *p;
00576   for (p = connection_string; *p != '\0'; p++) {
00577     switch (*p) {
00578       case '#':
00579         *player = p + 1;
00580         *p = '\0';
00581         break;
00582       case ':':
00583         *port = p + 1;
00584         *p = '\0';
00585         break;
00586     }
00587   }
00588 }
00589 
00590 // Creates a new client from a socket
00591 //   Used both by the server and the client
00592 static NetworkTCPSocketHandler *NetworkAllocClient(SOCKET s)
00593 {
00594   NetworkTCPSocketHandler *cs;
00595   byte client_no = 0;
00596 
00597   if (_network_server) {
00598     // Can we handle a new client?
00599     if (_network_clients_connected >= MAX_CLIENTS) return NULL;
00600     if (_network_game_info.clients_on >= _network_game_info.clients_max) return NULL;
00601 
00602     // Register the login
00603     client_no = _network_clients_connected++;
00604   }
00605 
00606   cs = DEREF_CLIENT(client_no);
00607   cs->Initialize();
00608   cs->sock = s;
00609   cs->last_frame = _frame_counter;
00610   cs->last_frame_server = _frame_counter;
00611 
00612   if (_network_server) {
00613     NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
00614     memset(ci, 0, sizeof(*ci));
00615 
00616     cs->index = _network_client_index++;
00617     ci->client_index = cs->index;
00618     ci->client_playas = PLAYER_INACTIVE_CLIENT;
00619     ci->join_date = _date;
00620 
00621     InvalidateWindow(WC_CLIENT_LIST, 0);
00622   }
00623 
00624   return cs;
00625 }
00626 
00627 // Close a connection
00628 void NetworkCloseClient(NetworkTCPSocketHandler *cs)
00629 {
00630   NetworkClientInfo *ci;
00631   // Socket is already dead
00632   if (cs->sock == INVALID_SOCKET) {
00633     cs->has_quit = true;
00634     return;
00635   }
00636 
00637   DEBUG(net, 1, "Closed client connection %d", cs->index);
00638 
00639   if (!cs->has_quit && _network_server && cs->status > STATUS_INACTIVE) {
00640     // We did not receive a leave message from this client...
00641     NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST;
00642     char str[100];
00643     char client_name[NETWORK_CLIENT_NAME_LENGTH];
00644     NetworkTCPSocketHandler *new_cs;
00645 
00646     NetworkGetClientName(client_name, sizeof(client_name), cs);
00647 
00648     GetNetworkErrorMsg(str, errorno, lastof(str));
00649 
00650     NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);
00651 
00652     // Inform other clients of this... strange leaving ;)
00653     FOR_ALL_CLIENTS(new_cs) {
00654       if (new_cs->status > STATUS_AUTH && cs != new_cs) {
00655         SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
00656       }
00657     }
00658   }
00659 
00660   /* When the client was PRE_ACTIVE, the server was in pause mode, so unpause */
00661   if (cs->status == STATUS_PRE_ACTIVE && _network_pause_on_join) {
00662     DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
00663     NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX);
00664   }
00665 
00666   cs->Destroy();
00667 
00668   // Close the gap in the client-list
00669   ci = DEREF_CLIENT_INFO(cs);
00670 
00671   if (_network_server) {
00672     // We just lost one client :(
00673     if (cs->status >= STATUS_AUTH) _network_game_info.clients_on--;
00674     _network_clients_connected--;
00675 
00676     while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->sock != INVALID_SOCKET) {
00677       *cs = *(cs + 1);
00678       *ci = *(ci + 1);
00679       cs++;
00680       ci++;
00681     }
00682 
00683     InvalidateWindow(WC_CLIENT_LIST, 0);
00684   }
00685 
00686   // Reset the status of the last socket
00687   cs->sock = INVALID_SOCKET;
00688   cs->status = STATUS_INACTIVE;
00689   cs->index = NETWORK_EMPTY_INDEX;
00690   ci->client_index = NETWORK_EMPTY_INDEX;
00691 
00692   CheckMinPlayers();
00693 }
00694 
00695 // A client wants to connect to a server
00696 static bool NetworkConnect(const char *hostname, int port)
00697 {
00698   SOCKET s;
00699   struct sockaddr_in sin;
00700 
00701   DEBUG(net, 1, "Connecting to %s %d", hostname, port);
00702 
00703   s = socket(AF_INET, SOCK_STREAM, 0);
00704   if (s == INVALID_SOCKET) {
00705     ClientStartError("socket() failed");
00706     return false;
00707   }
00708 
00709   if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed");
00710 
00711   sin.sin_family = AF_INET;
00712   sin.sin_addr.s_addr = NetworkResolveHost(hostname);
00713   sin.sin_port = htons(port);
00714   _network_last_host_ip = sin.sin_addr.s_addr;
00715 
00716   /* We failed to connect for which reason what so ever */
00717   if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) return false;
00718 
00719   if (!SetNonBlocking(s)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error?
00720 
00721   // in client mode, only the first client field is used. it's pointing to the server.
00722   NetworkAllocClient(s);
00723 
00724   _network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
00725   ShowJoinStatusWindow();
00726 
00727   return true;
00728 }
00729 
00730 // For the server, to accept new clients
00731 static void NetworkAcceptClients()
00732 {
00733   struct sockaddr_in sin;
00734   NetworkTCPSocketHandler *cs;
00735   uint i;
00736   bool banned;
00737 
00738   // Should never ever happen.. is it possible??
00739   assert(_listensocket != INVALID_SOCKET);
00740 
00741   for (;;) {
00742     socklen_t sin_len = sizeof(sin);
00743     SOCKET s = accept(_listensocket, (struct sockaddr*)&sin, &sin_len);
00744     if (s == INVALID_SOCKET) return;
00745 
00746     SetNonBlocking(s); // XXX error handling?
00747 
00748     DEBUG(net, 1, "Client connected from %s on frame %d", inet_ntoa(sin.sin_addr), _frame_counter);
00749 
00750     SetNoDelay(s); // XXX error handling?
00751 
00752     /* Check if the client is banned */
00753     banned = false;
00754     for (i = 0; i < lengthof(_network_ban_list); i++) {
00755       if (_network_ban_list[i] == NULL) continue;
00756 
00757       if (sin.sin_addr.s_addr == inet_addr(_network_ban_list[i])) {
00758         Packet p(PACKET_SERVER_BANNED);
00759         p.PrepareToSend();
00760 
00761         DEBUG(net, 1, "Banned ip tried to join (%s), refused", _network_ban_list[i]);
00762 
00763         send(s, (const char*)p.buffer, p.size, 0);
00764         closesocket(s);
00765 
00766         banned = true;
00767         break;
00768       }
00769     }
00770     /* If this client is banned, continue with next client */
00771     if (banned) continue;
00772 
00773     cs = NetworkAllocClient(s);
00774     if (cs == NULL) {
00775       // no more clients allowed?
00776       // Send to the client that we are full!
00777       Packet p(PACKET_SERVER_FULL);
00778       p.PrepareToSend();
00779 
00780       send(s, (const char*)p.buffer, p.size, 0);
00781       closesocket(s);
00782 
00783       continue;
00784     }
00785 
00786     // a new client has connected. We set him at inactive for now
00787     //  maybe he is only requesting server-info. Till he has sent a PACKET_CLIENT_MAP_OK
00788     //  the client stays inactive
00789     cs->status = STATUS_INACTIVE;
00790 
00791     DEREF_CLIENT_INFO(cs)->client_ip = sin.sin_addr.s_addr; // Save the IP of the client
00792   }
00793 }
00794 
00795 // Set up the listen socket for the server
00796 static bool NetworkListen()
00797 {
00798   SOCKET ls;
00799   struct sockaddr_in sin;
00800 
00801   DEBUG(net, 1, "Listening on %s:%d", _network_server_bind_ip_host, _network_server_port);
00802 
00803   ls = socket(AF_INET, SOCK_STREAM, 0);
00804   if (ls == INVALID_SOCKET) {
00805     ServerStartError("socket() on listen socket failed");
00806     return false;
00807   }
00808 
00809   { // reuse the socket
00810     int reuse = 1;
00811     // The (const char*) cast is needed for windows!!
00812     if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) {
00813       ServerStartError("setsockopt() on listen socket failed");
00814       return false;
00815     }
00816   }
00817 
00818   if (!SetNonBlocking(ls)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error?
00819 
00820   sin.sin_family = AF_INET;
00821   sin.sin_addr.s_addr = _network_server_bind_ip;
00822   sin.sin_port = htons(_network_server_port);
00823 
00824   if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
00825     ServerStartError("bind() failed");
00826     return false;
00827   }
00828 
00829   if (listen(ls, 1) != 0) {
00830     ServerStartError("listen() failed");
00831     return false;
00832   }
00833 
00834   _listensocket = ls;
00835 
00836   return true;
00837 }
00838 
00839 // Close all current connections
00840 static void NetworkClose()
00841 {
00842   NetworkTCPSocketHandler *cs;
00843 
00844   FOR_ALL_CLIENTS(cs) {
00845     if (!_network_server) {
00846       SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving");
00847       cs->Send_Packets();
00848     }
00849     NetworkCloseClient(cs);
00850   }
00851 
00852   if (_network_server) {
00853     // We are a server, also close the listensocket
00854     closesocket(_listensocket);
00855     _listensocket = INVALID_SOCKET;
00856     DEBUG(net, 1, "Closed listener");
00857     NetworkUDPCloseAll();
00858   }
00859 }
00860 
00861 // Inits the network (cleans sockets and stuff)
00862 static void NetworkInitialize()
00863 {
00864   NetworkTCPSocketHandler *cs;
00865 
00866   _local_command_queue = NULL;
00867 
00868   // Clean all client-sockets
00869   for (cs = _clients; cs != &_clients[MAX_CLIENTS]; cs++) {
00870     cs->Initialize();
00871   }
00872 
00873   // Clean the client_info memory
00874   memset(&_network_client_info, 0, sizeof(_network_client_info));
00875   memset(&_network_player_info, 0, sizeof(_network_player_info));
00876 
00877   _sync_frame = 0;
00878   _network_first_time = true;
00879 
00880   _network_reconnect = 0;
00881 
00882   NetworkUDPInitialize();
00883 }
00884 
00885 // Query a server to fetch his game-info
00886 //  If game_info is true, only the gameinfo is fetched,
00887 //   else only the client_info is fetched
00888 void NetworkTCPQueryServer(const char* host, unsigned short port)
00889 {
00890   if (!_network_available) return;
00891 
00892   NetworkDisconnect();
00893 
00894   NetworkInitialize();
00895 
00896   _network_server = false;
00897 
00898   // Try to connect
00899   _networking = NetworkConnect(host, port);
00900 
00901   // We are connected
00902   if (_networking) {
00903     SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
00904   } else { // No networking, close everything down again
00905     NetworkDisconnect();
00906   }
00907 }
00908 
00909 /* Validates an address entered as a string and adds the server to
00910  * the list. If you use this function, the games will be marked
00911  * as manually added. */
00912 void NetworkAddServer(const char *b)
00913 {
00914   if (*b != '\0') {
00915     const char *port = NULL;
00916     const char *player = NULL;
00917     char host[NETWORK_HOSTNAME_LENGTH];
00918     uint16 rport;
00919 
00920     ttd_strlcpy(host, b, lengthof(host));
00921 
00922     ttd_strlcpy(_network_default_ip, b, lengthof(_network_default_ip));
00923     rport = NETWORK_DEFAULT_PORT;
00924 
00925     ParseConnectionString(&player, &port, host);
00926     if (port != NULL) rport = atoi(port);
00927 
00928     NetworkUDPQueryServer(host, rport, true);
00929   }
00930 }
00931 
00932 /* Generates the list of manually added hosts from NetworkGameList and
00933  * dumps them into the array _network_host_list. This array is needed
00934  * by the function that generates the config file. */
00935 void NetworkRebuildHostList()
00936 {
00937   uint i = 0;
00938   const NetworkGameList *item = _network_game_list;
00939   while (item != NULL && i != lengthof(_network_host_list)) {
00940     if (item->manually) {
00941       free(_network_host_list[i]);
00942       _network_host_list[i++] = str_fmt("%s:%i", item->info.hostname, item->port);
00943     }
00944     item = item->next;
00945   }
00946 
00947   for (; i < lengthof(_network_host_list); i++) {
00948     free(_network_host_list[i]);
00949     _network_host_list[i] = NULL;
00950   }
00951 }
00952 
00953 // Used by clients, to connect to a server
00954 bool NetworkClientConnectGame(const char *host, uint16 port)
00955 {
00956   if (!_network_available) return false;
00957 
00958   if (port == 0) return false;
00959 
00960   ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host));
00961   _network_last_port = port;
00962 
00963   NetworkDisconnect();
00964   NetworkUDPCloseAll();
00965   NetworkInitialize();
00966 
00967   // Try to connect
00968   _networking = NetworkConnect(host, port);
00969 
00970   // We are connected
00971   if (_networking) {
00972     IConsoleCmdExec("exec scripts/on_client.scr 0");
00973     NetworkClient_Connected();
00974   } else {
00975     // Connecting failed
00976     NetworkError(STR_NETWORK_ERR_NOCONNECTION);
00977   }
00978 
00979   return _networking;
00980 }
00981 
00982 static void NetworkInitGameInfo()
00983 {
00984   NetworkClientInfo *ci;
00985 
00986   ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name));
00987   ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password));
00988   ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_rcon_password));
00989   if (_network_game_info.server_name[0] == '\0')
00990     snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server");
00991 
00992   ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision));
00993 
00994   // The server is a client too ;)
00995   if (_network_dedicated) {
00996     _network_game_info.clients_on = 0;
00997     _network_game_info.companies_on = 0;
00998     _network_game_info.dedicated = true;
00999   } else {
01000     _network_game_info.clients_on = 1;
01001     _network_game_info.companies_on = 1;
01002     _network_game_info.dedicated = false;
01003   }
01004 
01005   _network_game_info.spectators_on = 0;
01006 
01007   _network_game_info.game_date = _date;
01008   _network_game_info.start_date = ConvertYMDToDate(_patches.starting_year, 0, 1);
01009   _network_game_info.map_width = MapSizeX();
01010   _network_game_info.map_height = MapSizeY();
01011   _network_game_info.map_set = _opt.landscape;
01012 
01013   _network_game_info.use_password = (_network_server_password[0] != '\0');
01014 
01015   // We use _network_client_info[MAX_CLIENT_INFO - 1] to store the server-data in it
01016   //  The index is NETWORK_SERVER_INDEX ( = 1)
01017   ci = &_network_client_info[MAX_CLIENT_INFO - 1];
01018   memset(ci, 0, sizeof(*ci));
01019 
01020   ci->client_index = NETWORK_SERVER_INDEX;
01021   ci->client_playas = _network_dedicated ? PLAYER_SPECTATOR : _local_player;
01022 
01023   ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name));
01024   ttd_strlcpy(ci->unique_id, _network_unique_id, sizeof(ci->unique_id));
01025 }
01026 
01027 bool NetworkServerStart()
01028 {
01029   if (!_network_available) return false;
01030 
01031   /* Call the pre-scripts */
01032   IConsoleCmdExec("exec scripts/pre_server.scr 0");
01033   if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
01034 
01035   NetworkInitialize();
01036   if (!NetworkListen()) return false;
01037 
01038   // Try to start UDP-server
01039   _network_udp_server = true;
01040   _network_udp_server = _udp_server_socket->Listen(_network_server_bind_ip, _network_server_port, false);
01041 
01042   _network_server = true;
01043   _networking = true;
01044   _frame_counter = 0;
01045   _frame_counter_server = 0;
01046   _frame_counter_max = 0;
01047   _last_sync_frame = 0;
01048   _network_own_client_index = NETWORK_SERVER_INDEX;
01049 
01050   /* Non-dedicated server will always be player #1 */
01051   if (!_network_dedicated) _network_playas = PLAYER_FIRST;
01052 
01053   _network_clients_connected = 0;
01054 
01055   NetworkInitGameInfo();
01056 
01057   // execute server initialization script
01058   IConsoleCmdExec("exec scripts/on_server.scr 0");
01059   // if the server is dedicated ... add some other script
01060   if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
01061 
01062   _min_players_paused = false;
01063   CheckMinPlayers();
01064 
01065   /* Try to register us to the master server */
01066   _network_last_advertise_frame = 0;
01067   _network_need_advertise = true;
01068   NetworkUDPAdvertise();
01069   return true;
01070 }
01071 
01072 // The server is rebooting...
01073 // The only difference with NetworkDisconnect, is the packets that is sent
01074 void NetworkReboot()
01075 {
01076   if (_network_server) {
01077     NetworkTCPSocketHandler *cs;
01078     FOR_ALL_CLIENTS(cs) {
01079       SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs);
01080       cs->Send_Packets();
01081     }
01082   }
01083 
01084   NetworkClose();
01085 
01086   // Free all queued commands
01087   while (_local_command_queue != NULL) {
01088     CommandPacket *p = _local_command_queue;
01089     _local_command_queue = _local_command_queue->next;
01090     free(p);
01091   }
01092 
01093   _networking = false;
01094   _network_server = false;
01095 }
01096 
01097 // We want to disconnect from the host/clients
01098 void NetworkDisconnect()
01099 {
01100   if (_network_server) {
01101     NetworkTCPSocketHandler *cs;
01102     FOR_ALL_CLIENTS(cs) {
01103       SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs);
01104       cs->Send_Packets();
01105     }
01106   }
01107 
01108   if (_network_advertise) NetworkUDPRemoveAdvertise();
01109 
01110   DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
01111 
01112   NetworkClose();
01113 
01114   // Free all queued commands
01115   while (_local_command_queue != NULL) {
01116     CommandPacket *p = _local_command_queue;
01117     _local_command_queue = _local_command_queue->next;
01118     free(p);
01119   }
01120 
01121   _networking = false;
01122   _network_server = false;
01123 }
01124 
01125 // Receives something from the network
01126 static bool NetworkReceive()
01127 {
01128   NetworkTCPSocketHandler *cs;
01129   int n;
01130   fd_set read_fd, write_fd;
01131   struct timeval tv;
01132 
01133   FD_ZERO(&read_fd);
01134   FD_ZERO(&write_fd);
01135 
01136   FOR_ALL_CLIENTS(cs) {
01137     FD_SET(cs->sock, &read_fd);
01138     FD_SET(cs->sock, &write_fd);
01139   }
01140 
01141   // take care of listener port
01142   if (_network_server) FD_SET(_listensocket, &read_fd);
01143 
01144   tv.tv_sec = tv.tv_usec = 0; // don't block at all.
01145 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
01146   n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
01147 #else
01148   n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
01149 #endif
01150   if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERR_LOSTCONNECTION);
01151 
01152   // accept clients..
01153   if (_network_server && FD_ISSET(_listensocket, &read_fd)) NetworkAcceptClients();
01154 
01155   // read stuff from clients
01156   FOR_ALL_CLIENTS(cs) {
01157     cs->writable = !!FD_ISSET(cs->sock, &write_fd);
01158     if (FD_ISSET(cs->sock, &read_fd)) {
01159       if (_network_server) {
01160         NetworkServer_ReadPackets(cs);
01161       } else {
01162         NetworkRecvStatus res;
01163 
01164         // The client already was quiting!
01165         if (cs->has_quit) return false;
01166 
01167         res = NetworkClient_ReadPackets(cs);
01168         if (res != NETWORK_RECV_STATUS_OKAY) {
01169           // The client made an error of which we can not recover
01170           //   close the client and drop back to main menu
01171           NetworkClientError(res, cs);
01172           return false;
01173         }
01174       }
01175     }
01176   }
01177   return true;
01178 }
01179 
01180 // This sends all buffered commands (if possible)
01181 static void NetworkSend()
01182 {
01183   NetworkTCPSocketHandler *cs;
01184   FOR_ALL_CLIENTS(cs) {
01185     if (cs->writable) {
01186       cs->Send_Packets();
01187 
01188       if (cs->status == STATUS_MAP) {
01189         // This client is in the middle of a map-send, call the function for that
01190         SEND_COMMAND(PACKET_SERVER_MAP)(cs);
01191       }
01192     }
01193   }
01194 }
01195 
01196 // Handle the local-command-queue
01197 static void NetworkHandleLocalQueue()
01198 {
01199   CommandPacket *cp, **cp_prev;
01200 
01201   cp_prev = &_local_command_queue;
01202 
01203   while ( (cp = *cp_prev) != NULL) {
01204 
01205     // The queue is always in order, which means
01206     // that the first element will be executed first.
01207     if (_frame_counter < cp->frame) break;
01208 
01209     if (_frame_counter > cp->frame) {
01210       // If we reach here, it means for whatever reason, we've already executed
01211       // past the command we need to execute.
01212       error("[net] Trying to execute a packet in the past!");
01213     }
01214 
01215     // We can execute this command
01216     NetworkExecuteCommand(cp);
01217 
01218     *cp_prev = cp->next;
01219     free(cp);
01220   }
01221 
01222   // Just a safety check, to be removed in the future.
01223   // Make sure that no older command appears towards the end of the queue
01224   // In that case we missed executing it. This will never happen.
01225   for (cp = _local_command_queue; cp; cp = cp->next) {
01226     assert(_frame_counter < cp->frame);
01227   }
01228 
01229 }
01230 
01231 static bool NetworkDoClientLoop()
01232 {
01233   _frame_counter++;
01234 
01235   NetworkHandleLocalQueue();
01236 
01237   StateGameLoop();
01238 
01239   // Check if we are in sync!
01240   if (_sync_frame != 0) {
01241     if (_sync_frame == _frame_counter) {
01242 #ifdef NETWORK_SEND_DOUBLE_SEED
01243       if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
01244 #else
01245       if (_sync_seed_1 != _random.state[0]) {
01246 #endif
01247         NetworkError(STR_NETWORK_ERR_DESYNC);
01248         DebugDumpCommands("ddc:serr:%d;%d\n", _date, _date_fract);
01249         DEBUG(net, 0, "Sync error detected!");
01250         NetworkClientError(NETWORK_RECV_STATUS_DESYNC, DEREF_CLIENT(0));
01251         return false;
01252       }
01253 
01254       // If this is the first time we have a sync-frame, we
01255       //   need to let the server know that we are ready and at the same
01256       //   frame as he is.. so we can start playing!
01257       if (_network_first_time) {
01258         _network_first_time = false;
01259         SEND_COMMAND(PACKET_CLIENT_ACK)();
01260       }
01261 
01262       _sync_frame = 0;
01263     } else if (_sync_frame < _frame_counter) {
01264       DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
01265       _sync_frame = 0;
01266     }
01267   }
01268 
01269   return true;
01270 }
01271 
01272 // We have to do some UDP checking
01273 void NetworkUDPGameLoop()
01274 {
01275   if (_network_udp_server) {
01276     _udp_server_socket->ReceivePackets();
01277     _udp_master_socket->ReceivePackets();
01278   } else {
01279     _udp_client_socket->ReceivePackets();
01280     if (_network_udp_broadcast > 0) _network_udp_broadcast--;
01281     NetworkGameListRequery();
01282   }
01283 }
01284 
01285 // The main loop called from ttd.c
01286 //  Here we also have to do StateGameLoop if needed!
01287 void NetworkGameLoop()
01288 {
01289   if (!_networking) return;
01290 
01291   if (!NetworkReceive()) return;
01292 
01293   if (_network_server) {
01294 #ifdef DEBUG_DUMP_COMMANDS
01295     static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
01296     static Date next_date = 0;
01297     static uint32 next_date_fract;
01298     static CommandPacket *cp = NULL;
01299     if (f == NULL && next_date == 0) {
01300       printf("Cannot open commands.log\n");
01301       next_date = 1;
01302     }
01303 
01304     while (f != NULL && !feof(f)) {
01305       if (cp != NULL && _date == next_date && _date_fract == next_date_fract) {
01306         _current_player = cp->player;
01307         _cmd_text = cp->text;
01308         DoCommandP(cp->tile, cp->p1, cp->p2, NULL, cp->cmd);
01309         free(cp);
01310         cp = NULL;
01311       }
01312 
01313       if (cp != NULL) break;
01314 
01315       char buff[4096];
01316       if (fgets(buff, lengthof(buff), f) == NULL) break;
01317       if (strncmp(buff, "ddc:cmd:", 8) != 0) continue;
01318       cp = MallocT<CommandPacket>(1);
01319       int player;
01320       sscanf(&buff[8], "%d;%d;%d;%d;%d;%d;%d;%s", &next_date, &next_date_fract, &player, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text);
01321       cp->player = (Owner)player;
01322     }
01323 #endif /* DEBUG_DUMP_COMMANDS */
01324 
01325     bool send_frame = false;
01326 
01327     // We first increase the _frame_counter
01328     _frame_counter++;
01329     // Update max-frame-counter
01330     if (_frame_counter > _frame_counter_max) {
01331       _frame_counter_max = _frame_counter + _network_frame_freq;
01332       send_frame = true;
01333     }
01334 
01335     NetworkHandleLocalQueue();
01336 
01337     // Then we make the frame
01338     StateGameLoop();
01339 
01340     _sync_seed_1 = _random.state[0];
01341 #ifdef NETWORK_SEND_DOUBLE_SEED
01342     _sync_seed_2 = _random.state[1];
01343 #endif
01344 
01345     NetworkServer_Tick(send_frame);
01346   } else {
01347     // Client
01348 
01349     // Make sure we are at the frame were the server is (quick-frames)
01350     if (_frame_counter_server > _frame_counter) {
01351       while (_frame_counter_server > _frame_counter) {
01352         if (!NetworkDoClientLoop()) break;
01353       }
01354     } else {
01355       // Else, keep on going till _frame_counter_max
01356       if (_frame_counter_max > _frame_counter) NetworkDoClientLoop();
01357     }
01358   }
01359 
01360   NetworkSend();
01361 }
01362 
01363 static void NetworkGenerateUniqueId()
01364 {
01365   Md5 checksum;
01366   uint8 digest[16];
01367   char hex_output[16*2 + 1];
01368   char coding_string[NETWORK_NAME_LENGTH];
01369   int di;
01370 
01371   snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID");
01372 
01373   /* Generate the MD5 hash */
01374   checksum.Append((const uint8*)coding_string, strlen(coding_string));
01375   checksum.Finish(digest);
01376 
01377   for (di = 0; di < 16; ++di)
01378     sprintf(hex_output + di * 2, "%02x", digest[di]);
01379 
01380   /* _network_unique_id is our id */
01381   snprintf(_network_unique_id, sizeof(_network_unique_id), "%s", hex_output);
01382 }
01383 
01384 void NetworkStartDebugLog(const char *hostname, uint16 port)
01385 {
01386   extern SOCKET _debug_socket;  // Comes from debug.c
01387   SOCKET s;
01388   struct sockaddr_in sin;
01389 
01390   DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", hostname, port);
01391 
01392   s = socket(AF_INET, SOCK_STREAM, 0);
01393   if (s == INVALID_SOCKET) {
01394     DEBUG(net, 0, "Failed to open socket for redirection DEBUG()");
01395     return;
01396   }
01397 
01398   if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed");
01399 
01400   sin.sin_family = AF_INET;
01401   sin.sin_addr.s_addr = NetworkResolveHost(hostname);
01402   sin.sin_port = htons(port);
01403 
01404   if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
01405     DEBUG(net, 0, "Failed to redirection DEBUG() to %s:%d", hostname, port);
01406     return;
01407   }
01408 
01409   if (!SetNonBlocking(s)) DEBUG(net, 0, "Setting non-blocking mode failed");
01410   _debug_socket = s;
01411 
01412   DEBUG(net, 0, "DEBUG() is now redirected");
01413 }
01414 
01416 void NetworkStartUp()
01417 {
01418   DEBUG(net, 3, "[core] starting network...");
01419 
01420   /* Network is available */
01421   _network_available = NetworkCoreInitialize();;
01422   _network_dedicated = false;
01423   _network_last_advertise_frame = 0;
01424   _network_need_advertise = true;
01425   _network_advertise_retries = 0;
01426 
01427   /* Load the ip from the openttd.cfg */
01428   _network_server_bind_ip = inet_addr(_network_server_bind_ip_host);
01429   /* And put the data back in it in case it was an invalid ip */
01430   snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
01431 
01432   /* Generate an unique id when there is none yet */
01433   if (_network_unique_id[0] == '\0') NetworkGenerateUniqueId();
01434 
01435   {
01436     byte cl_max = _network_game_info.clients_max;
01437     byte cp_max = _network_game_info.companies_max;
01438     byte sp_max = _network_game_info.spectators_max;
01439     byte s_lang = _network_game_info.server_lang;
01440 
01441     memset(&_network_game_info, 0, sizeof(_network_game_info));
01442     _network_game_info.clients_max = cl_max;
01443     _network_game_info.companies_max = cp_max;
01444     _network_game_info.spectators_max = sp_max;
01445     _network_game_info.server_lang = s_lang;
01446   }
01447 
01448 
01449   NetworkInitialize();
01450   DEBUG(net, 3, "[core] network online, multiplayer available");
01451   NetworkFindIPs();
01452 }
01453 
01455 void NetworkShutDown()
01456 {
01457   NetworkDisconnect();
01458   NetworkUDPShutdown();
01459 
01460   DEBUG(net, 3, "[core] shutting down network");
01461 
01462   _network_available = false;
01463 
01464   NetworkCoreShutdown();
01465 }
01466 
01471 bool IsNetworkCompatibleVersion(const char *other)
01472 {
01473   extern const char _openttd_revision[];
01474   return strncmp(_openttd_revision, other, NETWORK_REVISION_LENGTH - 1) == 0;
01475 }
01476 
01477 #endif /* ENABLE_NETWORK */
01478 
01479 /* NOTE: this variable needs to be always available */
01480 PlayerID _network_playas;

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