00001
00002
00003
00004
00005
00006
00007
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_internal.h"
00020 #include "network_client.h"
00021 #include "network_server.h"
00022 #include "network_content.h"
00023 #include "network_udp.h"
00024 #include "network_gamelist.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 #ifdef DEBUG_DUMP_COMMANDS
00039 #include "../fileio_func.h"
00040 #endif
00041 #include "table/strings.h"
00042
00043 DECLARE_POSTFIX_INCREMENT(ClientID);
00044
00045 assert_compile(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE);
00046
00047 NetworkClientInfoPool _networkclientinfo_pool("NetworkClientInfo");
00048 INSTANTIATE_POOL_METHODS(NetworkClientInfo)
00049
00050 bool _networking;
00051 bool _network_server;
00052 bool _network_available;
00053 bool _network_dedicated;
00054 bool _is_network_server;
00055 NetworkServerGameInfo _network_game_info;
00056 NetworkCompanyState *_network_company_states = NULL;
00057 ClientID _network_own_client_id;
00058 ClientID _redirect_console_to_client;
00059 bool _network_need_advertise;
00060 uint32 _network_last_advertise_frame;
00061 uint8 _network_reconnect;
00062 StringList _network_bind_list;
00063 StringList _network_host_list;
00064 StringList _network_ban_list;
00065 uint32 _frame_counter_server;
00066 uint32 _frame_counter_max;
00067 uint32 _frame_counter;
00068 uint32 _last_sync_frame;
00069 NetworkAddressList _broadcast_list;
00070 uint32 _sync_seed_1;
00071 #ifdef NETWORK_SEND_DOUBLE_SEED
00072 uint32 _sync_seed_2;
00073 #endif
00074 uint32 _sync_frame;
00075 bool _network_first_time;
00076 bool _network_udp_server;
00077 uint16 _network_udp_broadcast;
00078 uint8 _network_advertise_retries;
00079 CompanyMask _network_company_passworded;
00080
00081
00082 assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE);
00083 assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_BYTES);
00084
00085 extern NetworkUDPSocketHandler *_udp_client_socket;
00086 extern NetworkUDPSocketHandler *_udp_server_socket;
00087 extern NetworkUDPSocketHandler *_udp_master_socket;
00088
00089
00090 static SocketList _listensockets;
00091
00092
00093 static byte _network_clients_connected = 0;
00094
00095 static ClientID _network_client_id = CLIENT_ID_FIRST;
00096
00097
00098 extern void StateGameLoop();
00099
00103 NetworkClientInfo::~NetworkClientInfo()
00104 {
00105
00106 InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_CLIENT, this->client_id);
00107 }
00108
00114 NetworkClientInfo *NetworkFindClientInfoFromIndex(ClientIndex index)
00115 {
00116 return NetworkClientInfo::GetIfValid(index);
00117 }
00118
00124 NetworkClientInfo *NetworkFindClientInfoFromClientID(ClientID client_id)
00125 {
00126 NetworkClientInfo *ci;
00127
00128 FOR_ALL_CLIENT_INFOS(ci) {
00129 if (ci->client_id == client_id) return ci;
00130 }
00131
00132 return NULL;
00133 }
00134
00140 NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip)
00141 {
00142 NetworkClientInfo *ci;
00143 NetworkAddress address(ip);
00144
00145 if (address.GetAddressLength() == 0) return NULL;
00146
00147 FOR_ALL_CLIENT_INFOS(ci) {
00148 if (ci->client_address == address) return ci;
00149 }
00150
00151 return NULL;
00152 }
00153
00159 NetworkClientSocket *NetworkFindClientStateFromClientID(ClientID client_id)
00160 {
00161 NetworkClientSocket *cs;
00162
00163 FOR_ALL_CLIENT_SOCKETS(cs) {
00164 if (cs->client_id == client_id) return cs;
00165 }
00166
00167 return NULL;
00168 }
00169
00170
00171
00172 void NetworkGetClientName(char *client_name, size_t size, const NetworkClientSocket *cs)
00173 {
00174 const NetworkClientInfo *ci = cs->GetInfo();
00175
00176 if (StrEmpty(ci->client_name)) {
00177 snprintf(client_name, size, "Client #%4d", cs->client_id);
00178 } else {
00179 ttd_strlcpy(client_name, ci->client_name, size);
00180 }
00181 }
00182
00183 byte NetworkSpectatorCount()
00184 {
00185 const NetworkClientInfo *ci;
00186 byte count = 0;
00187
00188 FOR_ALL_CLIENT_INFOS(ci) {
00189 if (ci->client_playas == COMPANY_SPECTATOR) count++;
00190 }
00191
00192
00193 if (_network_dedicated) count--;
00194
00195 return count;
00196 }
00197
00203 bool NetworkCompanyIsPassworded(CompanyID company_id)
00204 {
00205 return HasBit(_network_company_passworded, company_id);
00206 }
00207
00208
00209
00210
00211 void NetworkTextMessage(NetworkAction action, ConsoleColour colour, bool self_send, const char *name, const char *str, int64 data)
00212 {
00213 const int duration = 10;
00214
00215 StringID strid;
00216 switch (action) {
00217 case NETWORK_ACTION_SERVER_MESSAGE:
00218
00219 strid = STR_NETWORK_SERVER_MESSAGE;
00220 colour = CC_DEFAULT;
00221 break;
00222 case NETWORK_ACTION_COMPANY_SPECTATOR:
00223 colour = CC_DEFAULT;
00224 strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE;
00225 break;
00226 case NETWORK_ACTION_COMPANY_JOIN:
00227 colour = CC_DEFAULT;
00228 strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN;
00229 break;
00230 case NETWORK_ACTION_COMPANY_NEW:
00231 colour = CC_DEFAULT;
00232 strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW;
00233 break;
00234 case NETWORK_ACTION_JOIN:
00235
00236 strid = _network_server ? STR_NETWORK_MESSAGE_CLIENT_JOINED_ID : STR_NETWORK_MESSAGE_CLIENT_JOINED;
00237 break;
00238 case NETWORK_ACTION_LEAVE: strid = STR_NETWORK_MESSAGE_CLIENT_LEFT; break;
00239 case NETWORK_ACTION_NAME_CHANGE: strid = STR_NETWORK_MESSAGE_NAME_CHANGE; break;
00240 case NETWORK_ACTION_GIVE_MONEY: strid = self_send ? STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY : STR_NETWORK_MESSAGE_GIVE_MONEY; break;
00241 case NETWORK_ACTION_CHAT_COMPANY: strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; break;
00242 case NETWORK_ACTION_CHAT_CLIENT: strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT; break;
00243 default: strid = STR_NETWORK_CHAT_ALL; break;
00244 }
00245
00246 char message[1024];
00247 SetDParamStr(0, name);
00248 SetDParamStr(1, str);
00249 SetDParam(2, data);
00250 GetString(message, strid, lastof(message));
00251
00252 DEBUG(desync, 1, "msg: %d; %d; %s\n", _date, _date_fract, message);
00253 IConsolePrintF(colour, "%s", message);
00254 NetworkAddChatMessage((TextColour)colour, duration, "%s", message);
00255 }
00256
00257
00258 uint NetworkCalculateLag(const NetworkClientSocket *cs)
00259 {
00260 int lag = cs->last_frame_server - cs->last_frame;
00261
00262
00263
00264 if (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq < _frame_counter)
00265 lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq);
00266
00267 return lag;
00268 }
00269
00270
00271
00272
00273 static void NetworkError(StringID error_string)
00274 {
00275 _switch_mode = SM_MENU;
00276 extern StringID _switch_mode_errorstr;
00277 _switch_mode_errorstr = error_string;
00278 }
00279
00280 static void ServerStartError(const char *error)
00281 {
00282 DEBUG(net, 0, "[server] could not start network: %s",error);
00283 NetworkError(STR_NETWORK_ERROR_SERVER_START);
00284 }
00285
00286 static void NetworkClientError(NetworkRecvStatus res, NetworkClientSocket *cs)
00287 {
00288
00289
00290 NetworkErrorCode errorno;
00291
00292
00293 if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
00294 cs->NetworkSocketHandler::CloseConnection();
00295 NetworkCloseClient(cs, true);
00296 _networking = false;
00297
00298 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00299 return;
00300 }
00301
00302 switch (res) {
00303 case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break;
00304 case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
00305 case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break;
00306 default: errorno = NETWORK_ERROR_GENERAL; break;
00307 }
00308
00309
00310 if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL &&
00311 res != NETWORK_RECV_STATUS_SERVER_BANNED) {
00312 SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
00313 }
00314
00315 _switch_mode = SM_MENU;
00316 NetworkCloseClient(cs, true);
00317 _networking = false;
00318 }
00319
00325 StringID GetNetworkErrorMsg(NetworkErrorCode err)
00326 {
00327
00328
00329 static const StringID network_error_strings[] = {
00330 STR_NETWORK_ERROR_CLIENT_GENERAL,
00331 STR_NETWORK_ERROR_CLIENT_DESYNC,
00332 STR_NETWORK_ERROR_CLIENT_SAVEGAME,
00333 STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST,
00334 STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR,
00335 STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH,
00336 STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED,
00337 STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED,
00338 STR_NETWORK_ERROR_CLIENT_WRONG_REVISION,
00339 STR_NETWORK_ERROR_CLIENT_NAME_IN_USE,
00340 STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD,
00341 STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH,
00342 STR_NETWORK_ERROR_CLIENT_KICKED,
00343 STR_NETWORK_ERROR_CLIENT_CHEATER,
00344 STR_NETWORK_ERROR_CLIENT_SERVER_FULL
00345 };
00346
00347 if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL;
00348
00349 return network_error_strings[err];
00350 }
00351
00357 void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode)
00358 {
00359 if (!_networking) return;
00360
00361 switch (changed_mode) {
00362 case PM_PAUSED_NORMAL:
00363 case PM_PAUSED_JOIN:
00364 case PM_PAUSED_ACTIVE_CLIENTS: {
00365 bool changed = ((_pause_mode == PM_UNPAUSED) != (prev_mode == PM_UNPAUSED));
00366 bool paused = (_pause_mode != PM_UNPAUSED);
00367 if (!paused && !changed) return;
00368
00369 StringID str;
00370 if (!changed) {
00371 int i = -1;
00372 if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL);
00373 if ((_pause_mode & PM_PAUSED_JOIN) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS);
00374 if ((_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS);
00375 str = STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + i;
00376 } else {
00377 switch (changed_mode) {
00378 case PM_PAUSED_NORMAL: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL); break;
00379 case PM_PAUSED_JOIN: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS); break;
00380 case PM_PAUSED_ACTIVE_CLIENTS: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS); break;
00381 default: NOT_REACHED();
00382 }
00383 str = paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED;
00384 }
00385
00386 char buffer[DRAW_STRING_BUFFER];
00387 GetString(buffer, str, lastof(buffer));
00388 NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, NULL, buffer);
00389 } break;
00390
00391 default:
00392 return;
00393 }
00394 }
00395
00396
00405 static void CheckPauseHelper(bool pause, PauseMode pm)
00406 {
00407 if (pause == ((_pause_mode & pm) != PM_UNPAUSED)) return;
00408
00409 DoCommandP(0, pm, pause ? 1 : 0, CMD_PAUSE);
00410 }
00411
00417 static uint NetworkCountActiveClients()
00418 {
00419 const NetworkClientSocket *cs;
00420 uint count = 0;
00421
00422 FOR_ALL_CLIENT_SOCKETS(cs) {
00423 if (cs->status != STATUS_ACTIVE) continue;
00424 if (!Company::IsValidID(cs->GetInfo()->client_playas)) continue;
00425 count++;
00426 }
00427
00428 return count;
00429 }
00430
00434 static void CheckMinActiveClients()
00435 {
00436 if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED ||
00437 !_network_dedicated ||
00438 (_settings_client.network.min_active_clients == 0 && (_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) == PM_UNPAUSED)) {
00439 return;
00440 }
00441 CheckPauseHelper(NetworkCountActiveClients() < _settings_client.network.min_active_clients, PM_PAUSED_ACTIVE_CLIENTS);
00442 }
00443
00448 static bool NetworkHasJoiningClient()
00449 {
00450 const NetworkClientSocket *cs;
00451 FOR_ALL_CLIENT_SOCKETS(cs) {
00452 if (cs->status >= STATUS_AUTH && cs->status < STATUS_ACTIVE) return true;
00453 }
00454
00455 return false;
00456 }
00457
00461 static void CheckPauseOnJoin()
00462 {
00463 if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED ||
00464 (!_settings_client.network.pause_on_join && (_pause_mode & PM_PAUSED_JOIN) == PM_UNPAUSED)) {
00465 return;
00466 }
00467 CheckPauseHelper(NetworkHasJoiningClient(), PM_PAUSED_JOIN);
00468 }
00469
00476 void ParseConnectionString(const char **company, const char **port, char *connection_string)
00477 {
00478 bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':'));
00479 char *p;
00480 for (p = connection_string; *p != '\0'; p++) {
00481 switch (*p) {
00482 case '[':
00483 ipv6 = true;
00484 break;
00485
00486 case ']':
00487 ipv6 = false;
00488 break;
00489
00490 case '#':
00491 *company = p + 1;
00492 *p = '\0';
00493 break;
00494
00495 case ':':
00496 if (ipv6) break;
00497 *port = p + 1;
00498 *p = '\0';
00499 break;
00500 }
00501 }
00502 }
00503
00504
00505
00506 static NetworkClientSocket *NetworkAllocClient(SOCKET s)
00507 {
00508 if (_network_server) {
00509
00510 if (_network_clients_connected >= MAX_CLIENTS) return NULL;
00511 if (_network_game_info.clients_on >= _settings_client.network.max_clients) return NULL;
00512
00513
00514 _network_clients_connected++;
00515 }
00516
00517 NetworkClientSocket *cs = new NetworkClientSocket(INVALID_CLIENT_ID);
00518 cs->sock = s;
00519 cs->last_frame = _frame_counter;
00520 cs->last_frame_server = _frame_counter;
00521
00522 if (_network_server) {
00523 cs->client_id = _network_client_id++;
00524 NetworkClientInfo *ci = new NetworkClientInfo(cs->client_id);
00525 cs->SetInfo(ci);
00526 ci->client_playas = COMPANY_INACTIVE_CLIENT;
00527 ci->join_date = _date;
00528
00529 SetWindowDirty(WC_CLIENT_LIST, 0);
00530 }
00531
00532 return cs;
00533 }
00534
00535
00536 void NetworkCloseClient(NetworkClientSocket *cs, bool error)
00537 {
00538
00539
00540
00541
00542
00543
00544
00545 if (cs->sock == INVALID_SOCKET) return;
00546
00547 if (error && !cs->HasClientQuit() && _network_server && cs->status > STATUS_INACTIVE) {
00548
00549 char client_name[NETWORK_CLIENT_NAME_LENGTH];
00550 NetworkClientSocket *new_cs;
00551
00552 NetworkGetClientName(client_name, sizeof(client_name), cs);
00553
00554 NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST);
00555
00556
00557 FOR_ALL_CLIENT_SOCKETS(new_cs) {
00558 if (new_cs->status > STATUS_AUTH && cs != new_cs) {
00559 SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->client_id, NETWORK_ERROR_CONNECTION_LOST);
00560 }
00561 }
00562 }
00563
00564 DEBUG(net, 1, "Closed client connection %d", cs->client_id);
00565
00566 if (_network_server) {
00567
00568 if (cs->status >= STATUS_AUTH) _network_game_info.clients_on--;
00569 _network_clients_connected--;
00570
00571 SetWindowDirty(WC_CLIENT_LIST, 0);
00572 }
00573
00574 delete cs->GetInfo();
00575 delete cs;
00576 }
00577
00578
00579 static void NetworkAcceptClients(SOCKET ls)
00580 {
00581 for (;;) {
00582 struct sockaddr_storage sin;
00583 memset(&sin, 0, sizeof(sin));
00584 socklen_t sin_len = sizeof(sin);
00585 SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
00586 if (s == INVALID_SOCKET) return;
00587
00588 SetNonBlocking(s);
00589
00590 NetworkAddress address(sin, sin_len);
00591 DEBUG(net, 1, "Client connected from %s on frame %d", address.GetHostname(), _frame_counter);
00592
00593 SetNoDelay(s);
00594
00595
00596 bool banned = false;
00597 for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) {
00598 banned = address.IsInNetmask(*iter);
00599 if (banned) {
00600 Packet p(PACKET_SERVER_BANNED);
00601 p.PrepareToSend();
00602
00603 DEBUG(net, 1, "Banned ip tried to join (%s), refused", *iter);
00604
00605 send(s, (const char*)p.buffer, p.size, 0);
00606 closesocket(s);
00607 break;
00608 }
00609 }
00610
00611 if (banned) continue;
00612
00613 NetworkClientSocket *cs = NetworkAllocClient(s);
00614 if (cs == NULL) {
00615
00616
00617 Packet p(PACKET_SERVER_FULL);
00618 p.PrepareToSend();
00619
00620 send(s, (const char*)p.buffer, p.size, 0);
00621 closesocket(s);
00622
00623 continue;
00624 }
00625
00626
00627
00628
00629 cs->status = STATUS_INACTIVE;
00630
00631 cs->GetInfo()->client_address = address;
00632 }
00633 }
00634
00635
00636 static bool NetworkListen()
00637 {
00638 assert(_listensockets.Length() == 0);
00639
00640 NetworkAddressList addresses;
00641 GetBindAddresses(&addresses, _settings_client.network.server_port);
00642
00643 for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) {
00644 address->Listen(SOCK_STREAM, &_listensockets);
00645 }
00646
00647 if (_listensockets.Length() == 0) {
00648 ServerStartError("Could not create listening socket");
00649 return false;
00650 }
00651
00652 return true;
00653 }
00654
00656 static void InitializeNetworkPools()
00657 {
00658 _networkclientsocket_pool.CleanPool();
00659 _networkclientinfo_pool.CleanPool();
00660 }
00661
00662
00663 static void NetworkClose()
00664 {
00665 NetworkClientSocket *cs;
00666
00667 FOR_ALL_CLIENT_SOCKETS(cs) {
00668 if (!_network_server) {
00669 SEND_COMMAND(PACKET_CLIENT_QUIT)();
00670 cs->Send_Packets();
00671 }
00672 NetworkCloseClient(cs, false);
00673 }
00674
00675 if (_network_server) {
00676
00677 for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00678 closesocket(s->second);
00679 }
00680 _listensockets.Clear();
00681 DEBUG(net, 1, "[tcp] closed listeners");
00682 }
00683
00684 TCPConnecter::KillAll();
00685
00686 _networking = false;
00687 _network_server = false;
00688
00689 NetworkFreeLocalCommandQueue();
00690
00691 free(_network_company_states);
00692 _network_company_states = NULL;
00693
00694 InitializeNetworkPools();
00695 }
00696
00697
00698 static void NetworkInitialize()
00699 {
00700 InitializeNetworkPools();
00701 NetworkUDPInitialize();
00702
00703 _sync_frame = 0;
00704 _network_first_time = true;
00705
00706 _network_reconnect = 0;
00707 }
00708
00710 class TCPQueryConnecter : TCPConnecter {
00711 public:
00712 TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00713
00714 virtual void OnFailure()
00715 {
00716 NetworkDisconnect();
00717 }
00718
00719 virtual void OnConnect(SOCKET s)
00720 {
00721 _networking = true;
00722 NetworkAllocClient(s);
00723 SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
00724 }
00725 };
00726
00727
00728
00729
00730 void NetworkTCPQueryServer(NetworkAddress address)
00731 {
00732 if (!_network_available) return;
00733
00734 NetworkDisconnect();
00735 NetworkInitialize();
00736
00737 new TCPQueryConnecter(address);
00738 }
00739
00740
00741
00742
00743 void NetworkAddServer(const char *b)
00744 {
00745 if (*b != '\0') {
00746 const char *port = NULL;
00747 const char *company = NULL;
00748 char host[NETWORK_HOSTNAME_LENGTH];
00749 uint16 rport;
00750
00751 strecpy(host, b, lastof(host));
00752
00753 strecpy(_settings_client.network.connect_to_ip, b, lastof(_settings_client.network.connect_to_ip));
00754 rport = NETWORK_DEFAULT_PORT;
00755
00756 ParseConnectionString(&company, &port, host);
00757 if (port != NULL) rport = atoi(port);
00758
00759 NetworkUDPQueryServer(NetworkAddress(host, rport), true);
00760 }
00761 }
00762
00768 void GetBindAddresses(NetworkAddressList *addresses, uint16 port)
00769 {
00770 for (char **iter = _network_bind_list.Begin(); iter != _network_bind_list.End(); iter++) {
00771 *addresses->Append() = NetworkAddress(*iter, port);
00772 }
00773
00774
00775 if (addresses->Length() == 0) {
00776 *addresses->Append() = NetworkAddress("", port);
00777 }
00778 }
00779
00780
00781
00782
00783 void NetworkRebuildHostList()
00784 {
00785 _network_host_list.Clear();
00786
00787 for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) {
00788 if (item->manually) *_network_host_list.Append() = strdup(item->address.GetAddressAsString(false));
00789 }
00790 }
00791
00793 class TCPClientConnecter : TCPConnecter {
00794 public:
00795 TCPClientConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00796
00797 virtual void OnFailure()
00798 {
00799 NetworkError(STR_NETWORK_ERROR_NOCONNECTION);
00800 }
00801
00802 virtual void OnConnect(SOCKET s)
00803 {
00804 _networking = true;
00805 NetworkAllocClient(s);
00806 IConsoleCmdExec("exec scripts/on_client.scr 0");
00807 NetworkClient_Connected();
00808 }
00809 };
00810
00811
00812
00813 void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password, const char *join_company_password)
00814 {
00815 if (!_network_available) return;
00816
00817 if (address.GetPort() == 0) return;
00818
00819 strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host));
00820 _settings_client.network.last_port = address.GetPort();
00821 _network_join_as = join_as;
00822 _network_join_server_password = join_server_password;
00823 _network_join_company_password = join_company_password;
00824
00825 NetworkDisconnect();
00826 NetworkInitialize();
00827
00828 _network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
00829 ShowJoinStatusWindow();
00830
00831 new TCPClientConnecter(address);
00832 }
00833
00834 static void NetworkInitGameInfo()
00835 {
00836 if (StrEmpty(_settings_client.network.server_name)) {
00837 snprintf(_settings_client.network.server_name, sizeof(_settings_client.network.server_name), "Unnamed Server");
00838 }
00839
00840
00841 _network_game_info.clients_on = _network_dedicated ? 0 : 1;
00842
00843 NetworkClientInfo *ci = new NetworkClientInfo(CLIENT_ID_SERVER);
00844 ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : _local_company;
00845
00846 sockaddr_in sock;
00847 memset(&sock, 0, sizeof(sock));
00848 sock.sin_family = AF_INET;
00849 ci->client_address = NetworkAddress((sockaddr*)&sock, sizeof(sock));
00850
00851 strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name));
00852 strecpy(ci->unique_id, _settings_client.network.network_id, lastof(ci->unique_id));
00853 }
00854
00855 bool NetworkServerStart()
00856 {
00857 if (!_network_available) return false;
00858
00859
00860 IConsoleCmdExec("exec scripts/pre_server.scr 0");
00861 if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
00862
00863 NetworkDisconnect();
00864 NetworkInitialize();
00865 if (!NetworkListen()) return false;
00866
00867
00868 _network_udp_server = _udp_server_socket->Listen();
00869
00870 _network_company_states = CallocT<NetworkCompanyState>(MAX_COMPANIES);
00871 _network_server = true;
00872 _networking = true;
00873 _frame_counter = 0;
00874 _frame_counter_server = 0;
00875 _frame_counter_max = 0;
00876 _last_sync_frame = 0;
00877 _network_own_client_id = CLIENT_ID_SERVER;
00878
00879 _network_clients_connected = 0;
00880 _network_company_passworded = 0;
00881
00882 NetworkInitGameInfo();
00883
00884
00885 IConsoleCmdExec("exec scripts/on_server.scr 0");
00886
00887 if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
00888
00889
00890 _network_last_advertise_frame = 0;
00891 _network_need_advertise = true;
00892 NetworkUDPAdvertise();
00893 return true;
00894 }
00895
00896
00897
00898 void NetworkReboot()
00899 {
00900 if (_network_server) {
00901 NetworkClientSocket *cs;
00902 FOR_ALL_CLIENT_SOCKETS(cs) {
00903 SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs);
00904 cs->Send_Packets();
00905 }
00906 }
00907
00908 NetworkClose();
00909 }
00910
00915 void NetworkDisconnect(bool blocking)
00916 {
00917 if (_network_server) {
00918 NetworkClientSocket *cs;
00919 FOR_ALL_CLIENT_SOCKETS(cs) {
00920 SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs);
00921 cs->Send_Packets();
00922 }
00923 }
00924
00925 if (_settings_client.network.server_advertise) NetworkUDPRemoveAdvertise(blocking);
00926
00927 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00928
00929 NetworkClose();
00930 }
00931
00932
00933 static bool NetworkReceive()
00934 {
00935 NetworkClientSocket *cs;
00936 fd_set read_fd, write_fd;
00937 struct timeval tv;
00938
00939 FD_ZERO(&read_fd);
00940 FD_ZERO(&write_fd);
00941
00942 FOR_ALL_CLIENT_SOCKETS(cs) {
00943 FD_SET(cs->sock, &read_fd);
00944 FD_SET(cs->sock, &write_fd);
00945 }
00946
00947
00948 for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00949 FD_SET(s->second, &read_fd);
00950 }
00951
00952 tv.tv_sec = tv.tv_usec = 0;
00953 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00954 int n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
00955 #else
00956 int n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
00957 #endif
00958 if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERROR_LOSTCONNECTION);
00959
00960
00961 for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00962 if (FD_ISSET(s->second, &read_fd)) NetworkAcceptClients(s->second);
00963 }
00964
00965
00966 FOR_ALL_CLIENT_SOCKETS(cs) {
00967 cs->writable = !!FD_ISSET(cs->sock, &write_fd);
00968 if (FD_ISSET(cs->sock, &read_fd)) {
00969 if (_network_server) {
00970 NetworkServer_ReadPackets(cs);
00971 } else {
00972 NetworkRecvStatus res;
00973
00974
00975 if (cs->HasClientQuit()) return false;
00976
00977 res = NetworkClient_ReadPackets(cs);
00978 if (res != NETWORK_RECV_STATUS_OKAY) {
00979
00980
00981 NetworkClientError(res, cs);
00982 return false;
00983 }
00984 }
00985 }
00986 }
00987 return true;
00988 }
00989
00990
00991 static void NetworkSend()
00992 {
00993 NetworkClientSocket *cs;
00994 FOR_ALL_CLIENT_SOCKETS(cs) {
00995 if (cs->writable) {
00996 cs->Send_Packets();
00997
00998 if (cs->status == STATUS_MAP) {
00999
01000 SEND_COMMAND(PACKET_SERVER_MAP)(cs);
01001 }
01002 }
01003 }
01004 }
01005
01006 static bool NetworkDoClientLoop()
01007 {
01008 _frame_counter++;
01009
01010 NetworkExecuteLocalCommandQueue();
01011
01012 StateGameLoop();
01013
01014
01015 if (_sync_frame != 0) {
01016 if (_sync_frame == _frame_counter) {
01017 #ifdef NETWORK_SEND_DOUBLE_SEED
01018 if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
01019 #else
01020 if (_sync_seed_1 != _random.state[0]) {
01021 #endif
01022 NetworkError(STR_NETWORK_ERROR_DESYNC);
01023 DEBUG(desync, 1, "sync_err: %d; %d\n", _date, _date_fract);
01024 DEBUG(net, 0, "Sync error detected!");
01025 NetworkClientError(NETWORK_RECV_STATUS_DESYNC, NetworkClientSocket::Get(0));
01026 return false;
01027 }
01028
01029
01030
01031
01032 if (_network_first_time) {
01033 _network_first_time = false;
01034 SEND_COMMAND(PACKET_CLIENT_ACK)();
01035 }
01036
01037 _sync_frame = 0;
01038 } else if (_sync_frame < _frame_counter) {
01039 DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
01040 _sync_frame = 0;
01041 }
01042 }
01043
01044 return true;
01045 }
01046
01047
01048 void NetworkUDPGameLoop()
01049 {
01050 _network_content_client.SendReceive();
01051 TCPConnecter::CheckCallbacks();
01052
01053 if (_network_udp_server) {
01054 _udp_server_socket->ReceivePackets();
01055 _udp_master_socket->ReceivePackets();
01056 } else {
01057 _udp_client_socket->ReceivePackets();
01058 if (_network_udp_broadcast > 0) _network_udp_broadcast--;
01059 NetworkGameListRequery();
01060 }
01061 }
01062
01063
01064
01065 void NetworkGameLoop()
01066 {
01067 if (!_networking) return;
01068
01069 if (!NetworkReceive()) return;
01070
01071 if (_network_server) {
01072 #ifdef DEBUG_DUMP_COMMANDS
01073 static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
01074 static Date next_date = 0;
01075 static uint32 next_date_fract;
01076 static CommandPacket *cp = NULL;
01077 if (f == NULL && next_date == 0) {
01078 printf("Cannot open commands.log\n");
01079 next_date = 1;
01080 }
01081
01082 while (f != NULL && !feof(f)) {
01083 if (cp != NULL && _date == next_date && _date_fract == next_date_fract) {
01084 _current_company = cp->company;
01085 DoCommandP(cp->tile, cp->p1, cp->p2, cp->cmd, NULL, cp->text);
01086 free(cp);
01087 cp = NULL;
01088 }
01089
01090 if (cp != NULL) break;
01091
01092 char buff[4096];
01093 if (fgets(buff, lengthof(buff), f) == NULL) break;
01094 if (strncmp(buff, "cmd: ", 8) != 0) continue;
01095 cp = MallocT<CommandPacket>(1);
01096 int company;
01097 sscanf(&buff[8], "%d; %d; %d; %d; %d; %d; %d; %s", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text);
01098 cp->company = (CompanyID)company;
01099 }
01100 #endif
01101 if (_frame_counter >= _frame_counter_max) {
01102
01103
01104
01105 CheckPauseOnJoin();
01106 CheckMinActiveClients();
01107 }
01108
01109 bool send_frame = false;
01110
01111
01112 _frame_counter++;
01113
01114 if (_frame_counter > _frame_counter_max) {
01115 _frame_counter_max = _frame_counter + _settings_client.network.frame_freq;
01116 send_frame = true;
01117 }
01118
01119 NetworkExecuteLocalCommandQueue();
01120
01121
01122 StateGameLoop();
01123
01124 _sync_seed_1 = _random.state[0];
01125 #ifdef NETWORK_SEND_DOUBLE_SEED
01126 _sync_seed_2 = _random.state[1];
01127 #endif
01128
01129 NetworkServer_Tick(send_frame);
01130 } else {
01131
01132
01133
01134 if (_frame_counter_server > _frame_counter) {
01135 while (_frame_counter_server > _frame_counter) {
01136 if (!NetworkDoClientLoop()) break;
01137 }
01138 } else {
01139
01140 if (_frame_counter_max > _frame_counter) NetworkDoClientLoop();
01141 }
01142 }
01143
01144 NetworkSend();
01145 }
01146
01147 static void NetworkGenerateUniqueId()
01148 {
01149 Md5 checksum;
01150 uint8 digest[16];
01151 char hex_output[16 * 2 + 1];
01152 char coding_string[NETWORK_NAME_LENGTH];
01153 int di;
01154
01155 snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID");
01156
01157
01158 checksum.Append((const uint8*)coding_string, strlen(coding_string));
01159 checksum.Finish(digest);
01160
01161 for (di = 0; di < 16; ++di) {
01162 sprintf(hex_output + di * 2, "%02x", digest[di]);
01163 }
01164
01165
01166 snprintf(_settings_client.network.network_id, sizeof(_settings_client.network.network_id), "%s", hex_output);
01167 }
01168
01169 void NetworkStartDebugLog(NetworkAddress address)
01170 {
01171 extern SOCKET _debug_socket;
01172
01173 DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort());
01174
01175 SOCKET s = address.Connect();
01176 if (s == INVALID_SOCKET) {
01177 DEBUG(net, 0, "Failed to open socket for redirection DEBUG()");
01178 return;
01179 }
01180
01181 _debug_socket = s;
01182
01183 DEBUG(net, 0, "DEBUG() is now redirected");
01184 }
01185
01187 void NetworkStartUp()
01188 {
01189 DEBUG(net, 3, "[core] starting network...");
01190
01191
01192 _network_available = NetworkCoreInitialize();;
01193 _network_dedicated = false;
01194 _network_last_advertise_frame = 0;
01195 _network_need_advertise = true;
01196 _network_advertise_retries = 0;
01197
01198
01199 if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateUniqueId();
01200
01201 memset(&_network_game_info, 0, sizeof(_network_game_info));
01202
01203 NetworkInitialize();
01204 DEBUG(net, 3, "[core] network online, multiplayer available");
01205 NetworkFindBroadcastIPs(&_broadcast_list);
01206 }
01207
01209 void NetworkShutDown()
01210 {
01211 NetworkDisconnect(true);
01212 NetworkUDPClose();
01213
01214 DEBUG(net, 3, "[core] shutting down network");
01215
01216 _network_available = false;
01217
01218 NetworkCoreShutdown();
01219 }
01220
01225 bool IsNetworkCompatibleVersion(const char *other)
01226 {
01227 return strncmp(_openttd_revision, other, NETWORK_REVISION_LENGTH - 1) == 0;
01228 }
01229
01230 #endif