// ---------------------------------------------------------------------------- void ConnectToServer::asynchronousUpdate() { if (STKHost::get()->isClientServer() && !NetworkConfig::get()->getServerIdFile().empty()) { getClientServerInfo(); } switch(m_state.load()) { case SET_PUBLIC_ADDRESS: { if (!m_server) { while (!ServersManager::get()->refresh(false)) { if (ProtocolManager::lock()->isExiting()) return; StkTime::sleep(1); } while (!ServersManager::get()->listUpdated()) { if (ProtocolManager::lock()->isExiting()) return; StkTime::sleep(1); } auto servers = std::move(ServersManager::get()->getServers()); // Remove password protected servers servers.erase(std::remove_if(servers.begin(), servers.end(), [] (const std::shared_ptr<Server> a)->bool { return a->isPasswordProtected(); }), servers.end()); if (!servers.empty()) { // For quick play we choose the server with the least player std::sort(servers.begin(), servers.end(), [] (const std::shared_ptr<Server> a, const std::shared_ptr<Server> b)->bool { return a->getCurrentPlayers() < b->getCurrentPlayers(); }); m_server = servers[0]; m_server_address = m_server->getAddress(); } else { // Shutdown STKHost (go back to online menu too) STKHost::get()->setErrorMessage(m_quick_play_err_msg); STKHost::get()->requestShutdown(); m_state = EXITING; return; } servers.clear(); } if (m_server->supportsEncryption()) { STKHost::get()->setPublicAddress(); registerWithSTKServer(); } // Set to DONE will stop STKHost is not connected m_state = STKHost::get()->getPublicAddress().isUnset() ? DONE : GOT_SERVER_ADDRESS; break; } case GOT_SERVER_ADDRESS: { if (!STKHost::get()->isClientServer() && m_server_address.getIP() == STKHost::get()->getPublicAddress().getIP()) { Log::info("ConnectToServer", "Server is in the same lan"); std::string str_msg("connection-request"); BareNetworkString message(str_msg + StringUtils::toString(m_server->getPrivatePort())); // If use lan connection for wan server, send to all broadcast // addresses for (auto& addr : ServersManager::get()->getBroadcastAddresses()) { for (int i = 0; i < 5; i++) { STKHost::get()->sendRawPacket(message, addr); StkTime::sleep(1); } } } // 30 seconds connecting timeout total, use another port to try // direct connection to server first, if failed than use the one // that has stun mapped, the first 8 seconds allow the server to // start the connect to peer protocol first before the port is // remapped if (tryConnect(2000, 4, true/*another_port*/)) break; if (!tryConnect(2000, 11)) m_state = DONE; break; } case DONE: case EXITING: break; } } // asynchronousUpdate
// ---------------------------------------------------------------------------- void ConnectToServer::asynchronousUpdate() { switch(m_state) { case NONE: { Log::info("ConnectToServer", "Protocol starting"); // This protocol will write the public address of this // instance to STKHost. m_current_protocol = new GetPublicAddress(this); m_current_protocol->requestStart(); // This protocol will be unpaused in the callback from // GetPublicAddress requestPause(); m_state = GETTING_SELF_ADDRESS; break; } case GETTING_SELF_ADDRESS: { delete m_current_protocol; // delete GetPublicAddress m_current_protocol = NULL; registerWithSTKServer(); // Register us with STK server if (m_quick_join) { handleQuickConnect(); // Quick connect will give us the server details, // so we can immediately try to connect to the server m_state = REQUESTING_CONNECTION; } else { m_state = GOT_SERVER_ADDRESS; } } break; case GOT_SERVER_ADDRESS: { assert(!m_quick_join); delete m_current_protocol; m_current_protocol = NULL; Log::info("ConnectToServer", "Server's address known"); // we're in the same lan (same public ip address) !! if (m_server_address.getIP() == NetworkConfig::get()->getMyAddress().getIP()) { Log::info("ConnectToServer", "Server appears to be in the same LAN."); } m_state = REQUESTING_CONNECTION; m_current_protocol = new RequestConnection(m_server_id); m_current_protocol->requestStart(); break; } case REQUESTING_CONNECTION: // In case of a LAN server, m_crrent_protocol is NULL if (!m_current_protocol || m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED) { delete m_current_protocol; m_current_protocol = NULL; // Server knows we want to connect Log::info("ConnectToServer", "Connection request made"); if (m_server_address.getIP() == 0 || m_server_address.getPort() == 0 ) { // server data not correct, hide address and stop m_state = HIDING_ADDRESS; Log::error("ConnectToServer", "Server address is %s", m_server_address.toString().c_str()); m_current_protocol = new HidePublicAddress(); m_current_protocol->requestStart(); return; } if (m_server_address.getIP() == NetworkConfig::get()->getMyAddress().getIP() || NetworkConfig::get()->isLAN()) { // We're in the same lan (same public ip address). // The state will change to CONNECTING handleSameLAN(); } else { m_state = CONNECTING; m_current_protocol = new PingProtocol(m_server_address, 2.0); m_current_protocol->requestStart(); } } break; case CONNECTING: // waiting the server to answer our connection { static double timer = 0; if (StkTime::getRealTime() > timer+5.0) // every 5 seconds { STKHost::get()->connect(m_server_address); timer = StkTime::getRealTime(); Log::info("ConnectToServer", "Trying to connect to %s", m_server_address.toString().c_str()); } break; } case CONNECTED: { Log::info("ConnectToServer", "Connected"); if(m_current_protocol) { // Kill the ping protocol because we're connected m_current_protocol->requestTerminate(); } delete m_current_protocol; m_current_protocol = NULL; // LAN networking does not use the stk server tables. if(NetworkConfig::get()->isWAN()) { m_current_protocol = new HidePublicAddress(); m_current_protocol->requestStart(); } m_state = HIDING_ADDRESS; break; } case HIDING_ADDRESS: // Wait till we have hidden our address if (!m_current_protocol || m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED) { if(m_current_protocol) { delete m_current_protocol; m_current_protocol = NULL; Log::info("ConnectToServer", "Address hidden"); } m_state = DONE; // lobby room protocol if we're connected only if(STKHost::get()->getPeers()[0]->isConnected()) { Protocol *p = new ClientLobbyRoomProtocol(m_server_address); p->requestStart(); } } break; case DONE: requestTerminate(); m_state = EXITING; break; case EXITING: break; } } // asynchronousUpdate