12 #include "../stdafx.h" 
   16 #include "../strings_func.h" 
   17 #include "../command_func.h" 
   18 #include "../date_func.h" 
   29 #include "../console_func.h" 
   30 #include "../3rdparty/md5/md5.h" 
   31 #include "../core/random_func.hpp" 
   32 #include "../window_func.h" 
   33 #include "../company_func.h" 
   34 #include "../company_base.h" 
   35 #include "../landscape_type.h" 
   37 #include "../core/pool_func.hpp" 
   38 #include "../gfx_func.h" 
   41 #include "../safeguards.h" 
   43 #ifdef DEBUG_DUMP_COMMANDS 
   44 #include "../fileio_func.h" 
   76 #ifdef NETWORK_SEND_DOUBLE_SEED 
  106   NetworkClientSocket *cs;
 
  131     if (ci->
client_id == client_id) 
return ci;
 
  144   NetworkClientSocket *cs;
 
  147     if (cs->client_id == client_id) 
return cs;
 
  153 byte NetworkSpectatorCount()
 
  163   if (_network_dedicated) count--;
 
  176   if (strcmp(password, 
"*") == 0) password = 
"";
 
  178   if (_network_server) {
 
  196   if (
StrEmpty(password)) 
return password;
 
  200   memset(salted_password, 0, 
sizeof(salted_password));
 
  201   seprintf(salted_password, 
lastof(salted_password), 
"%s", password);
 
  204     salted_password[i] ^= password_server_id[i] ^ (password_game_seed >> (i % 32));
 
  212   checksum.Append(salted_password, 
sizeof(salted_password) - 1);
 
  213   checksum.Finish(digest);
 
  215   for (
int di = 0; di < 16; di++) 
seprintf(hashed_password + di * 2, 
lastof(hashed_password), 
"%02x", digest[di]);
 
  217   return hashed_password;
 
  227   return HasBit(_network_company_passworded, company_id);
 
  233 void NetworkTextMessage(
NetworkAction action, 
TextColour colour, 
bool self_send, 
const char *name, 
const char *str, int64 data)
 
  237     case NETWORK_ACTION_SERVER_MESSAGE:
 
  239       strid = STR_NETWORK_SERVER_MESSAGE;
 
  242     case NETWORK_ACTION_COMPANY_SPECTATOR:
 
  244       strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE;
 
  246     case NETWORK_ACTION_COMPANY_JOIN:
 
  248       strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN;
 
  250     case NETWORK_ACTION_COMPANY_NEW:
 
  252       strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW;
 
  254     case NETWORK_ACTION_JOIN:
 
  256       strid = _network_server ? STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :  STR_NETWORK_MESSAGE_CLIENT_JOINED;
 
  258     case NETWORK_ACTION_LEAVE:          strid = STR_NETWORK_MESSAGE_CLIENT_LEFT; 
break;
 
  259     case NETWORK_ACTION_NAME_CHANGE:    strid = STR_NETWORK_MESSAGE_NAME_CHANGE; 
break;
 
  260     case NETWORK_ACTION_GIVE_MONEY:     strid = self_send ? STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY : STR_NETWORK_MESSAGE_GIVE_MONEY;   
break;
 
  261     case NETWORK_ACTION_CHAT_COMPANY:   strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; 
break;
 
  262     case NETWORK_ACTION_CHAT_CLIENT:    strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT  : STR_NETWORK_CHAT_CLIENT;  
break;
 
  263     default:                            strid = STR_NETWORK_CHAT_ALL; 
break;
 
  276   GetString(msg_ptr, strid, 
lastof(message));
 
  284 uint NetworkCalculateLag(
const NetworkClientSocket *cs)
 
  286   int lag = cs->last_frame_server - cs->last_frame;
 
  299 void NetworkError(
StringID error_string)
 
  314   static const StringID network_error_strings[] = {
 
  315     STR_NETWORK_ERROR_CLIENT_GENERAL,
 
  316     STR_NETWORK_ERROR_CLIENT_DESYNC,
 
  317     STR_NETWORK_ERROR_CLIENT_SAVEGAME,
 
  318     STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST,
 
  319     STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR,
 
  320     STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH,
 
  321     STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED,
 
  322     STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED,
 
  323     STR_NETWORK_ERROR_CLIENT_WRONG_REVISION,
 
  324     STR_NETWORK_ERROR_CLIENT_NAME_IN_USE,
 
  325     STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD,
 
  326     STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH,
 
  327     STR_NETWORK_ERROR_CLIENT_KICKED,
 
  328     STR_NETWORK_ERROR_CLIENT_CHEATER,
 
  329     STR_NETWORK_ERROR_CLIENT_SERVER_FULL,
 
  330     STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS,
 
  331     STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD,
 
  332     STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER,
 
  333     STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP,
 
  334     STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN,
 
  336   assert_compile(
lengthof(network_error_strings) == NETWORK_ERROR_END);
 
  338   if (err >= (ptrdiff_t)
lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL;
 
  340   return network_error_strings[err];
 
  350   if (!_networking) 
return;
 
  352   switch (changed_mode) {
 
  359       if (!paused && !changed) 
return;
 
  369         str = STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + i;
 
  371         switch (changed_mode) {
 
  376           default: NOT_REACHED();
 
  378         str = paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED;
 
  382       GetString(buffer, str, 
lastof(buffer));
 
  383       NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, 
CC_DEFAULT, 
false, NULL, buffer);
 
  415   const NetworkClientSocket *cs;
 
  419     if (cs->status != NetworkClientSocket::STATUS_ACTIVE) 
continue;
 
  433       !_network_dedicated ||
 
  446   const NetworkClientSocket *cs;
 
  448     if (cs->status >= NetworkClientSocket::STATUS_AUTHORIZED && cs->status < NetworkClientSocket::STATUS_ACTIVE) 
return true;
 
  476   bool ipv6 = (strchr(connection_string, 
':') != strrchr(connection_string, 
':'));
 
  478   for (p = connection_string; *p != 
'\0'; p++) {
 
  510   _network_clients_connected++;
 
  532   if (_network_server) {
 
  540     NetworkClientSocket *cs;
 
  554   _network_server = 
false;
 
  565 static void NetworkInitialize(
bool close_admins = 
true)
 
  571   _network_first_time = 
true;
 
  573   _network_reconnect = 0;
 
  581   virtual void OnFailure()
 
  586   virtual void OnConnect(SOCKET s)
 
  599   if (!_network_available) 
return;
 
  610 void NetworkAddServer(
const char *b)
 
  613     const char *port = NULL;
 
  614     const char *company = NULL;
 
  624     if (port != NULL) rport = atoi(port);
 
  637   for (
char **iter = _network_bind_list.
Begin(); iter != _network_bind_list.
End(); iter++) {
 
  642   if (addresses->
Length() == 0) {
 
  650 void NetworkRebuildHostList()
 
  652   _network_host_list.
Clear();
 
  655     if (item->manually) *_network_host_list.
Append() = 
stredup(item->address.GetAddressAsString(
false));
 
  664   virtual void OnFailure()
 
  666     NetworkError(STR_NETWORK_ERROR_NOCONNECTION);
 
  669   virtual void OnConnect(SOCKET s)
 
  680 void NetworkClientConnectGame(
NetworkAddress address, 
CompanyID join_as, 
const char *join_server_password, 
const char *join_company_password)
 
  682   if (!_network_available) 
return;
 
  684   if (address.
GetPort() == 0) 
return;
 
  696   ShowJoinStatusWindow();
 
  701 static void NetworkInitGameInfo()
 
  708   _network_game_info.
clients_on = _network_dedicated ? 0 : 1;
 
  718 bool NetworkServerStart()
 
  720   if (!_network_available) 
return false;
 
  724   if (_network_dedicated) 
IConsoleCmdExec(
"exec scripts/pre_dedicated.scr 0");
 
  727   NetworkInitialize(
false);
 
  728   DEBUG(net, 1, 
"starting listeners for clients");
 
  733     DEBUG(net, 1, 
"starting listeners for admins");
 
  738   DEBUG(net, 1, 
"starting listeners for incoming server queries");
 
  739   _network_udp_server = _udp_server_socket->
Listen();
 
  742   _network_server = 
true;
 
  745   _frame_counter_server = 0;
 
  746   _frame_counter_max = 0;
 
  747   _last_sync_frame = 0;
 
  750   _network_clients_connected = 0;
 
  751   _network_company_passworded = 0;
 
  753   NetworkInitGameInfo();
 
  758   if (_network_dedicated) 
IConsoleCmdExec(
"exec scripts/on_dedicated.scr 0");
 
  761   _network_need_advertise = 
true;
 
  774   if (_network_server) {
 
  775     NetworkClientSocket *cs;
 
  800   if (_network_server) {
 
  801     NetworkClientSocket *cs;
 
  832   if (_network_server) {
 
  841 static void NetworkSend()
 
  843   if (_network_server) {
 
  867 void NetworkGameLoop()
 
  869   if (!_networking) 
return;
 
  873   if (_network_server) {
 
  877       static Date last_log;
 
  878       if (last_log != 
_date) {
 
  884 #ifdef DEBUG_DUMP_COMMANDS 
  887     static Date next_date = 0;
 
  888     static uint32 next_date_fract;
 
  890     static bool check_sync_state = 
false;
 
  891     static uint32 sync_state[2];
 
  892     if (f == NULL && next_date == 0) {
 
  893       DEBUG(net, 0, 
"Cannot open commands.log");
 
  897     while (f != NULL && !feof(f)) {
 
  901           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));
 
  905         if (check_sync_state) {
 
  909             DEBUG(net, 0, 
"sync check: %08x; %02x; mismatch expected {%08x, %08x}, got {%08x, %08x}",
 
  913           check_sync_state = 
false;
 
  917       if (cp != NULL || check_sync_state) 
break;
 
  920       if (fgets(buff, 
lengthof(buff), f) == NULL) 
break;
 
  926         if (p == NULL) 
break;
 
  930       if (strncmp(p, 
"cmd: ", 5) == 0
 
  931 #ifdef DEBUG_FAILED_DUMP_COMMANDS
 
  932         || strncmp(p, 
"cmdf: ", 6) == 0
 
  937         cp = CallocT<CommandPacket>(1);
 
  939         int ret = sscanf(p, 
"%x; %x; %x; %x; %x; %x; %x; \"%[^\"]\"", &next_date, &next_date_fract, &company, &cp->
tile, &cp->
p1, &cp->
p2, &cp->
cmd, cp->
text);
 
  943         assert(ret == 8 || ret == 7);
 
  945       } 
else if (strncmp(p, 
"join: ", 6) == 0) {
 
  947         int ret = sscanf(p + 6, 
"%x; %x", &next_date, &next_date_fract);
 
  949         DEBUG(net, 0, 
"injecting pause for join at %08x:%02x; please join when paused", next_date, next_date_fract);
 
  950         cp = CallocT<CommandPacket>(1);
 
  956       } 
else if (strncmp(p, 
"sync: ", 6) == 0) {
 
  957         int ret = sscanf(p + 6, 
"%x; %x; %x; %x", &next_date, &next_date_fract, &sync_state[0], &sync_state[1]);
 
  959         check_sync_state = 
true;
 
  960       } 
else if (strncmp(p, 
"msg: ", 5) == 0 || strncmp(p, 
"client: ", 8) == 0 ||
 
  961             strncmp(p, 
"load: ", 6) == 0 || strncmp(p, 
"save: ", 6) == 0) {
 
  963 #ifndef DEBUG_FAILED_DUMP_COMMANDS 
  964       } 
else if (strncmp(p, 
"cmdf: ", 6) == 0) {
 
  965         DEBUG(net, 0, 
"Skipping replay of failed command: %s", p + 6);
 
  969         DEBUG(net, 0, 
"trying to parse: %s", p);
 
  973     if (f != NULL && feof(f)) {
 
  974       DEBUG(net, 0, 
"End of commands.log");
 
  979     if (_frame_counter >= _frame_counter_max) {
 
  988     bool send_frame = 
false;
 
  993     if (_frame_counter > _frame_counter_max) {
 
 1004 #ifdef NETWORK_SEND_DOUBLE_SEED 
 1013     if (_frame_counter_server > _frame_counter) {
 
 1015       while (_frame_counter_server > _frame_counter) {
 
 1020       if (_frame_counter_max > _frame_counter) {
 
 1030 static void NetworkGenerateServerId()
 
 1034   char hex_output[16 * 2 + 1];
 
 1038   seprintf(coding_string, 
lastof(coding_string), 
"%d%s", (uint)Random(), 
"OpenTTD Server ID");
 
 1041   checksum.Append((
const uint8*)coding_string, strlen(coding_string));
 
 1042   checksum.Finish(digest);
 
 1044   for (di = 0; di < 16; ++di) {
 
 1045     seprintf(hex_output + di * 2, 
lastof(hex_output), 
"%02x", digest[di]);
 
 1054   extern SOCKET _debug_socket;  
 
 1059   if (s == INVALID_SOCKET) {
 
 1060     DEBUG(net, 0, 
"Failed to open socket for redirection DEBUG()");
 
 1066   DEBUG(net, 0, 
"DEBUG() is now redirected");
 
 1072   DEBUG(net, 3, 
"[core] starting network...");
 
 1076   _network_dedicated = 
false;
 
 1077   _network_need_advertise = 
true;
 
 1078   _network_advertise_retries = 0;
 
 1083   memset(&_network_game_info, 0, 
sizeof(_network_game_info));
 
 1085   NetworkInitialize();
 
 1086   DEBUG(net, 3, 
"[core] network online, multiplayer available");
 
 1096   DEBUG(net, 3, 
"[core] shutting down network");
 
 1098   _network_available = 
false;