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