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_client.h"
00020 #include "network_server.h"
00021 #include "network_content.h"
00022 #include "network_udp.h"
00023 #include "network_gamelist.h"
00024 #include "network_base.h"
00025 #include "core/udp.h"
00026 #include "core/host.h"
00027 #include "network_gui.h"
00028 #include "../console_func.h"
00029 #include "../3rdparty/md5/md5.h"
00030 #include "../core/random_func.hpp"
00031 #include "../window_func.h"
00032 #include "../company_func.h"
00033 #include "../company_base.h"
00034 #include "../landscape_type.h"
00035 #include "../rev.h"
00036 #include "../core/pool_func.hpp"
00037 #include "../gfx_func.h"
00038 #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 cs->Send_Packets(true);
00575
00576 delete cs->GetInfo();
00577 delete cs;
00578 }
00579
00580
00581 static void NetworkAcceptClients(SOCKET ls)
00582 {
00583 for (;;) {
00584 struct sockaddr_storage sin;
00585 memset(&sin, 0, sizeof(sin));
00586 socklen_t sin_len = sizeof(sin);
00587 SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
00588 if (s == INVALID_SOCKET) return;
00589
00590 SetNonBlocking(s);
00591
00592 NetworkAddress address(sin, sin_len);
00593 DEBUG(net, 1, "Client connected from %s on frame %d", address.GetHostname(), _frame_counter);
00594
00595 SetNoDelay(s);
00596
00597
00598 bool banned = false;
00599 for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) {
00600 banned = address.IsInNetmask(*iter);
00601 if (banned) {
00602 Packet p(PACKET_SERVER_BANNED);
00603 p.PrepareToSend();
00604
00605 DEBUG(net, 1, "Banned ip tried to join (%s), refused", *iter);
00606
00607 send(s, (const char*)p.buffer, p.size, 0);
00608 closesocket(s);
00609 break;
00610 }
00611 }
00612
00613 if (banned) continue;
00614
00615 NetworkClientSocket *cs = NetworkAllocClient(s);
00616 if (cs == NULL) {
00617
00618
00619 Packet p(PACKET_SERVER_FULL);
00620 p.PrepareToSend();
00621
00622 send(s, (const char*)p.buffer, p.size, 0);
00623 closesocket(s);
00624
00625 continue;
00626 }
00627
00628
00629
00630
00631 cs->status = STATUS_INACTIVE;
00632
00633 cs->GetInfo()->client_address = address;
00634 }
00635 }
00636
00637
00638 static bool NetworkListen()
00639 {
00640 assert(_listensockets.Length() == 0);
00641
00642 NetworkAddressList addresses;
00643 GetBindAddresses(&addresses, _settings_client.network.server_port);
00644
00645 for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) {
00646 address->Listen(SOCK_STREAM, &_listensockets);
00647 }
00648
00649 if (_listensockets.Length() == 0) {
00650 ServerStartError("Could not create listening socket");
00651 return false;
00652 }
00653
00654 return true;
00655 }
00656
00658 static void InitializeNetworkPools()
00659 {
00660 _networkclientsocket_pool.CleanPool();
00661 _networkclientinfo_pool.CleanPool();
00662 }
00663
00664
00665 static void NetworkClose()
00666 {
00667 NetworkClientSocket *cs;
00668
00669 FOR_ALL_CLIENT_SOCKETS(cs) {
00670 if (!_network_server) {
00671 SEND_COMMAND(PACKET_CLIENT_QUIT)();
00672 cs->Send_Packets();
00673 }
00674 NetworkCloseClient(cs, false);
00675 }
00676
00677 if (_network_server) {
00678
00679 for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00680 closesocket(s->second);
00681 }
00682 _listensockets.Clear();
00683 DEBUG(net, 1, "[tcp] closed listeners");
00684 }
00685
00686 TCPConnecter::KillAll();
00687
00688 _networking = false;
00689 _network_server = false;
00690
00691 NetworkFreeLocalCommandQueue();
00692
00693 free(_network_company_states);
00694 _network_company_states = NULL;
00695
00696 InitializeNetworkPools();
00697 }
00698
00699
00700 static void NetworkInitialize()
00701 {
00702 InitializeNetworkPools();
00703 NetworkUDPInitialize();
00704
00705 _sync_frame = 0;
00706 _network_first_time = true;
00707
00708 _network_reconnect = 0;
00709 }
00710
00712 class TCPQueryConnecter : TCPConnecter {
00713 public:
00714 TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00715
00716 virtual void OnFailure()
00717 {
00718 NetworkDisconnect();
00719 }
00720
00721 virtual void OnConnect(SOCKET s)
00722 {
00723 _networking = true;
00724 NetworkAllocClient(s);
00725 SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
00726 }
00727 };
00728
00729
00730
00731
00732 void NetworkTCPQueryServer(NetworkAddress address)
00733 {
00734 if (!_network_available) return;
00735
00736 NetworkDisconnect();
00737 NetworkInitialize();
00738
00739 new TCPQueryConnecter(address);
00740 }
00741
00742
00743
00744
00745 void NetworkAddServer(const char *b)
00746 {
00747 if (*b != '\0') {
00748 const char *port = NULL;
00749 const char *company = NULL;
00750 char host[NETWORK_HOSTNAME_LENGTH];
00751 uint16 rport;
00752
00753 strecpy(host, b, lastof(host));
00754
00755 strecpy(_settings_client.network.connect_to_ip, b, lastof(_settings_client.network.connect_to_ip));
00756 rport = NETWORK_DEFAULT_PORT;
00757
00758 ParseConnectionString(&company, &port, host);
00759 if (port != NULL) rport = atoi(port);
00760
00761 NetworkUDPQueryServer(NetworkAddress(host, rport), true);
00762 }
00763 }
00764
00770 void GetBindAddresses(NetworkAddressList *addresses, uint16 port)
00771 {
00772 for (char **iter = _network_bind_list.Begin(); iter != _network_bind_list.End(); iter++) {
00773 *addresses->Append() = NetworkAddress(*iter, port);
00774 }
00775
00776
00777 if (addresses->Length() == 0) {
00778 *addresses->Append() = NetworkAddress("", port);
00779 }
00780 }
00781
00782
00783
00784
00785 void NetworkRebuildHostList()
00786 {
00787 _network_host_list.Clear();
00788
00789 for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) {
00790 if (item->manually) *_network_host_list.Append() = strdup(item->address.GetAddressAsString(false));
00791 }
00792 }
00793
00795 class TCPClientConnecter : TCPConnecter {
00796 public:
00797 TCPClientConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00798
00799 virtual void OnFailure()
00800 {
00801 NetworkError(STR_NETWORK_ERROR_NOCONNECTION);
00802 }
00803
00804 virtual void OnConnect(SOCKET s)
00805 {
00806 _networking = true;
00807 NetworkAllocClient(s);
00808 IConsoleCmdExec("exec scripts/on_client.scr 0");
00809 NetworkClient_Connected();
00810 }
00811 };
00812
00813
00814
00815 void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password, const char *join_company_password)
00816 {
00817 if (!_network_available) return;
00818
00819 if (address.GetPort() == 0) return;
00820
00821 strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host));
00822 _settings_client.network.last_port = address.GetPort();
00823 _network_join_as = join_as;
00824 _network_join_server_password = join_server_password;
00825 _network_join_company_password = join_company_password;
00826
00827 NetworkDisconnect();
00828 NetworkInitialize();
00829
00830 _network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
00831 ShowJoinStatusWindow();
00832
00833 new TCPClientConnecter(address);
00834 }
00835
00836 static void NetworkInitGameInfo()
00837 {
00838 if (StrEmpty(_settings_client.network.server_name)) {
00839 snprintf(_settings_client.network.server_name, sizeof(_settings_client.network.server_name), "Unnamed Server");
00840 }
00841
00842
00843 _network_game_info.clients_on = _network_dedicated ? 0 : 1;
00844
00845 NetworkClientInfo *ci = new NetworkClientInfo(CLIENT_ID_SERVER);
00846 ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : _local_company;
00847
00848 sockaddr_in sock;
00849 memset(&sock, 0, sizeof(sock));
00850 sock.sin_family = AF_INET;
00851 ci->client_address = NetworkAddress((sockaddr*)&sock, sizeof(sock));
00852
00853 strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name));
00854 strecpy(ci->unique_id, _settings_client.network.network_id, lastof(ci->unique_id));
00855 }
00856
00857 bool NetworkServerStart()
00858 {
00859 if (!_network_available) return false;
00860
00861
00862 IConsoleCmdExec("exec scripts/pre_server.scr 0");
00863 if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0");
00864
00865 NetworkDisconnect();
00866 NetworkInitialize();
00867 if (!NetworkListen()) return false;
00868
00869
00870 _network_udp_server = _udp_server_socket->Listen();
00871
00872 _network_company_states = CallocT<NetworkCompanyState>(MAX_COMPANIES);
00873 _network_server = true;
00874 _networking = true;
00875 _frame_counter = 0;
00876 _frame_counter_server = 0;
00877 _frame_counter_max = 0;
00878 _last_sync_frame = 0;
00879 _network_own_client_id = CLIENT_ID_SERVER;
00880
00881 _network_clients_connected = 0;
00882 _network_company_passworded = 0;
00883
00884 NetworkInitGameInfo();
00885
00886
00887 IConsoleCmdExec("exec scripts/on_server.scr 0");
00888
00889 if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
00890
00891
00892 _network_last_advertise_frame = 0;
00893 _network_need_advertise = true;
00894 NetworkUDPAdvertise();
00895 return true;
00896 }
00897
00898
00899
00900 void NetworkReboot()
00901 {
00902 if (_network_server) {
00903 NetworkClientSocket *cs;
00904 FOR_ALL_CLIENT_SOCKETS(cs) {
00905 SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs);
00906 cs->Send_Packets();
00907 }
00908 }
00909
00910 NetworkClose();
00911 }
00912
00917 void NetworkDisconnect(bool blocking)
00918 {
00919 if (_network_server) {
00920 NetworkClientSocket *cs;
00921 FOR_ALL_CLIENT_SOCKETS(cs) {
00922 SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs);
00923 cs->Send_Packets();
00924 }
00925 }
00926
00927 if (_settings_client.network.server_advertise) NetworkUDPRemoveAdvertise(blocking);
00928
00929 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
00930
00931 NetworkClose();
00932 }
00933
00934
00935 static bool NetworkReceive()
00936 {
00937 NetworkClientSocket *cs;
00938 fd_set read_fd, write_fd;
00939 struct timeval tv;
00940
00941 FD_ZERO(&read_fd);
00942 FD_ZERO(&write_fd);
00943
00944 FOR_ALL_CLIENT_SOCKETS(cs) {
00945 FD_SET(cs->sock, &read_fd);
00946 FD_SET(cs->sock, &write_fd);
00947 }
00948
00949
00950 for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00951 FD_SET(s->second, &read_fd);
00952 }
00953
00954 tv.tv_sec = tv.tv_usec = 0;
00955 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00956 int n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
00957 #else
00958 int n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
00959 #endif
00960 if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERROR_LOSTCONNECTION);
00961
00962
00963 for (SocketList::iterator s = _listensockets.Begin(); s != _listensockets.End(); s++) {
00964 if (FD_ISSET(s->second, &read_fd)) NetworkAcceptClients(s->second);
00965 }
00966
00967
00968 FOR_ALL_CLIENT_SOCKETS(cs) {
00969 cs->writable = !!FD_ISSET(cs->sock, &write_fd);
00970 if (FD_ISSET(cs->sock, &read_fd)) {
00971 if (_network_server) {
00972 NetworkServer_ReadPackets(cs);
00973 } else {
00974 NetworkRecvStatus res;
00975
00976
00977 if (cs->HasClientQuit()) return false;
00978
00979 res = NetworkClient_ReadPackets(cs);
00980 if (res != NETWORK_RECV_STATUS_OKAY) {
00981
00982
00983 NetworkClientError(res, cs);
00984 return false;
00985 }
00986 }
00987 }
00988 }
00989 return true;
00990 }
00991
00992
00993 static void NetworkSend()
00994 {
00995 NetworkClientSocket *cs;
00996 FOR_ALL_CLIENT_SOCKETS(cs) {
00997 if (cs->writable) {
00998 cs->Send_Packets();
00999
01000 if (cs->status == STATUS_MAP) {
01001
01002 SEND_COMMAND(PACKET_SERVER_MAP)(cs);
01003 }
01004 }
01005 }
01006 }
01007
01008 static bool NetworkDoClientLoop()
01009 {
01010 _frame_counter++;
01011
01012 NetworkExecuteLocalCommandQueue();
01013
01014 StateGameLoop();
01015
01016
01017 if (_sync_frame != 0) {
01018 if (_sync_frame == _frame_counter) {
01019 #ifdef NETWORK_SEND_DOUBLE_SEED
01020 if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) {
01021 #else
01022 if (_sync_seed_1 != _random.state[0]) {
01023 #endif
01024 NetworkError(STR_NETWORK_ERROR_DESYNC);
01025 DEBUG(desync, 1, "sync_err: %d; %d\n", _date, _date_fract);
01026 DEBUG(net, 0, "Sync error detected!");
01027 NetworkClientError(NETWORK_RECV_STATUS_DESYNC, NetworkClientSocket::Get(0));
01028 return false;
01029 }
01030
01031
01032
01033
01034 if (_network_first_time) {
01035 _network_first_time = false;
01036 SEND_COMMAND(PACKET_CLIENT_ACK)();
01037 }
01038
01039 _sync_frame = 0;
01040 } else if (_sync_frame < _frame_counter) {
01041 DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
01042 _sync_frame = 0;
01043 }
01044 }
01045
01046 return true;
01047 }
01048
01049
01050 void NetworkUDPGameLoop()
01051 {
01052 _network_content_client.SendReceive();
01053 TCPConnecter::CheckCallbacks();
01054
01055 if (_network_udp_server) {
01056 _udp_server_socket->ReceivePackets();
01057 _udp_master_socket->ReceivePackets();
01058 } else {
01059 _udp_client_socket->ReceivePackets();
01060 if (_network_udp_broadcast > 0) _network_udp_broadcast--;
01061 NetworkGameListRequery();
01062 }
01063 }
01064
01065
01066
01067 void NetworkGameLoop()
01068 {
01069 if (!_networking) return;
01070
01071 if (!NetworkReceive()) return;
01072
01073 if (_network_server) {
01074 #ifdef DEBUG_DUMP_COMMANDS
01075 static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
01076 static Date next_date = 0;
01077 static uint32 next_date_fract;
01078 static CommandPacket *cp = NULL;
01079 if (f == NULL && next_date == 0) {
01080 printf("Cannot open commands.log\n");
01081 next_date = 1;
01082 }
01083
01084 while (f != NULL && !feof(f)) {
01085 if (cp != NULL && _date == next_date && _date_fract == next_date_fract) {
01086 _current_company = cp->company;
01087 DoCommandP(cp->tile, cp->p1, cp->p2, cp->cmd, NULL, cp->text);
01088 free(cp);
01089 cp = NULL;
01090 }
01091
01092 if (cp != NULL) break;
01093
01094 char buff[4096];
01095 if (fgets(buff, lengthof(buff), f) == NULL) break;
01096 if (strncmp(buff, "cmd: ", 8) != 0) continue;
01097 cp = MallocT<CommandPacket>(1);
01098 int company;
01099 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);
01100 cp->company = (CompanyID)company;
01101 }
01102 #endif
01103 if (_frame_counter >= _frame_counter_max) {
01104
01105
01106
01107 CheckPauseOnJoin();
01108 CheckMinActiveClients();
01109 }
01110
01111 bool send_frame = false;
01112
01113
01114 _frame_counter++;
01115
01116 if (_frame_counter > _frame_counter_max) {
01117 _frame_counter_max = _frame_counter + _settings_client.network.frame_freq;
01118 send_frame = true;
01119 }
01120
01121 NetworkExecuteLocalCommandQueue();
01122
01123
01124 StateGameLoop();
01125
01126 _sync_seed_1 = _random.state[0];
01127 #ifdef NETWORK_SEND_DOUBLE_SEED
01128 _sync_seed_2 = _random.state[1];
01129 #endif
01130
01131 NetworkServer_Tick(send_frame);
01132 } else {
01133
01134
01135
01136 if (_frame_counter_server > _frame_counter) {
01137 while (_frame_counter_server > _frame_counter) {
01138 if (!NetworkDoClientLoop()) break;
01139 }
01140 } else {
01141
01142 if (_frame_counter_max > _frame_counter) NetworkDoClientLoop();
01143 }
01144 }
01145
01146 NetworkSend();
01147 }
01148
01149 static void NetworkGenerateUniqueId()
01150 {
01151 Md5 checksum;
01152 uint8 digest[16];
01153 char hex_output[16 * 2 + 1];
01154 char coding_string[NETWORK_NAME_LENGTH];
01155 int di;
01156
01157 snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID");
01158
01159
01160 checksum.Append((const uint8*)coding_string, strlen(coding_string));
01161 checksum.Finish(digest);
01162
01163 for (di = 0; di < 16; ++di) {
01164 sprintf(hex_output + di * 2, "%02x", digest[di]);
01165 }
01166
01167
01168 snprintf(_settings_client.network.network_id, sizeof(_settings_client.network.network_id), "%s", hex_output);
01169 }
01170
01171 void NetworkStartDebugLog(NetworkAddress address)
01172 {
01173 extern SOCKET _debug_socket;
01174
01175 DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort());
01176
01177 SOCKET s = address.Connect();
01178 if (s == INVALID_SOCKET) {
01179 DEBUG(net, 0, "Failed to open socket for redirection DEBUG()");
01180 return;
01181 }
01182
01183 _debug_socket = s;
01184
01185 DEBUG(net, 0, "DEBUG() is now redirected");
01186 }
01187
01189 void NetworkStartUp()
01190 {
01191 DEBUG(net, 3, "[core] starting network...");
01192
01193
01194 _network_available = NetworkCoreInitialize();;
01195 _network_dedicated = false;
01196 _network_last_advertise_frame = 0;
01197 _network_need_advertise = true;
01198 _network_advertise_retries = 0;
01199
01200
01201 if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateUniqueId();
01202
01203 memset(&_network_game_info, 0, sizeof(_network_game_info));
01204
01205 NetworkInitialize();
01206 DEBUG(net, 3, "[core] network online, multiplayer available");
01207 NetworkFindBroadcastIPs(&_broadcast_list);
01208 }
01209
01211 void NetworkShutDown()
01212 {
01213 NetworkDisconnect(true);
01214 NetworkUDPClose();
01215
01216 DEBUG(net, 3, "[core] shutting down network");
01217
01218 _network_available = false;
01219
01220 NetworkCoreShutdown();
01221 }
01222
01227 bool IsNetworkCompatibleVersion(const char *other)
01228 {
01229 return strncmp(_openttd_revision, other, NETWORK_REVISION_LENGTH - 1) == 0;
01230 }
01231
01232 #endif