// ----------------------------------------------------------------------------
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
Beispiel #2
0
// ----------------------------------------------------------------------------
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