From 93ec81f3099d69ec487bb3958d32968399a52ae6 Mon Sep 17 00:00:00 2001 From: hilnius Date: Mon, 26 Aug 2013 14:14:52 +0000 Subject: [PATCH] now to know the public ip address, the GetPublicAddress protocol uses randomly selected STUN servers from the UserConfig file. If the server doesn't answer after two seconds, the protocol will reset and pick a random server again. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@13574 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/network/protocols/get_public_address.cpp | 50 +++++++++++++++++--- src/network/protocols/get_public_address.hpp | 1 + src/network/stk_host.cpp | 7 ++- src/network/stk_host.hpp | 5 +- src/states_screens/race_result_gui.cpp | 34 +++++++++++++ 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/src/network/protocols/get_public_address.cpp b/src/network/protocols/get_public_address.cpp index a700d34f9..c7d72b6a1 100644 --- a/src/network/protocols/get_public_address.cpp +++ b/src/network/protocols/get_public_address.cpp @@ -18,14 +18,18 @@ #include "network/protocols/get_public_address.hpp" +#include "config/user_config.hpp" #include "network/network_manager.hpp" #include "network/client_network_manager.hpp" #include "network/protocols/connect_to_server.hpp" #include "network/network_interface.hpp" #include "utils/log.hpp" +#include "utils/random_generator.hpp" #include +#include +#include int stunRand() { @@ -92,16 +96,48 @@ void GetPublicAddress::asynchronousUpdate() bytes[19] = (uint8_t)(m_stun_tansaction_id[2]); bytes[20] = '\0'; - Log::verbose("GetPublicAddress", "Querrying STUN server 132.177.123.6"); - unsigned int dst = (132<<24)+(177<<16)+(123<<8)+6; - NetworkManager::getInstance()->setManualSocketsMode(true); - NetworkManager::getInstance()->getHost()->sendRawPacket(bytes, 20, TransportAddress(dst, 3478)); - m_state = TEST_SENT; + // time to pick a random stun server + std::vector stun_servers = UserConfigParams::m_stun_servers; + + RandomGenerator random_gen; + int rand_result = random_gen.get(stun_servers.size()); + Log::verbose("GetPublicAddress", "Using STUN server %s", stun_servers[rand_result]); + + // resolve the name into an IP address + struct addrinfo hints, *res, *p; + int status; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(stun_servers[rand_result], NULL, &hints, &res)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); + return; + } + for(p = res;p != NULL; p = p->ai_next) + { + struct sockaddr_in* interface = (struct sockaddr_in*)(p->ai_addr); + + m_stun_server_ip = ntohl(interface->sin_addr.s_addr); + NetworkManager::getInstance()->setManualSocketsMode(true); + NetworkManager::getInstance()->getHost()->sendRawPacket(bytes, 20, TransportAddress(m_stun_server_ip, 3478)); + m_state = TEST_SENT; + + freeaddrinfo(res); // free the linked list + return; + } + freeaddrinfo(res); // free the linked list + } if (m_state == TEST_SENT) { - unsigned int dst = (132<<24)+(177<<16)+(123<<8)+6; - uint8_t* data = NetworkManager::getInstance()->getHost()->receiveRawPacket(TransportAddress(dst, 3478)); + uint8_t* data = NetworkManager::getInstance()->getHost()->receiveRawPacket(TransportAddress(m_stun_server_ip, 3478), 2000); + if (!data) + { + m_state = NOTHING_DONE; // will send the test again to an other server + return; + } assert(data); // check that the stun response is a response, contains the magic cookie and the transaction ID diff --git a/src/network/protocols/get_public_address.hpp b/src/network/protocols/get_public_address.hpp index b591ba429..442758791 100644 --- a/src/network/protocols/get_public_address.hpp +++ b/src/network/protocols/get_public_address.hpp @@ -44,6 +44,7 @@ class GetPublicAddress : public Protocol STATE m_state; uint32_t m_stun_tansaction_id[3]; static const uint32_t m_stun_magic_cookie = 0x2112A442; + uint32_t m_stun_server_ip; }; #endif // GET_PUBLIC_ADDRESS_HPP diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index 9088f5d94..170d14a19 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -204,7 +204,7 @@ uint8_t* STKHost::receiveRawPacket(TransportAddress* sender) // ---------------------------------------------------------------------------- -uint8_t* STKHost::receiveRawPacket(TransportAddress sender) +uint8_t* STKHost::receiveRawPacket(TransportAddress sender, int max_tries) { uint8_t* buffer; // max size needed normally (only used for stun) buffer = (uint8_t*)(malloc(sizeof(uint8_t)*2048)); @@ -227,6 +227,11 @@ uint8_t* STKHost::receiveRawPacket(TransportAddress sender) i++; len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len); irr_driver->getDevice()->sleep(1); // wait 1 millisecond between two checks + if (i >= max_tries && max_tries != -1) + { + Log::verbose("STKHost", "No answer from the server."); + return NULL; + } } if (addr.sa_family == AF_INET) { diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index 8b0de1097..ac9466127 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -120,10 +120,13 @@ class STKHost * parameter. Does not check the port right now. * \param sender : Transport address of the original sender of the * wanted packet. + * \param max_tries : Number of times we try to read data from the + * socket. This is aproximately the time we wait in milliseconds. + * -1 means eternal tries. * \return A string containing the data of the received packet * matching the sender's ip address. */ - uint8_t* receiveRawPacket(TransportAddress sender); + uint8_t* receiveRawPacket(TransportAddress sender, int max_tries = -1); /*! \brief Broadcasts a packet to all peers. * \param data : Data to send. */ diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 5ef1b549b..d64c4c3e0 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -36,6 +36,7 @@ #include "modes/demo_world.hpp" #include "modes/overworld.hpp" #include "modes/world_with_rank.hpp" +#include "network/network_world.hpp" #include "race/highscores.hpp" #include "states_screens/feature_unlocked.hpp" #include "states_screens/main_menu_screen.hpp" @@ -96,6 +97,23 @@ void RaceResultGUI::enableAllButtons() enableGPProgress(); } + // If we're in a network world, change the buttons text + if (NetworkWorld::getInstance()->isRunning()) + { + top->setVisible(false); + middle->setText( _("Continue.") ); + middle->setVisible(true); + middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + bottom->setText( _("Quit the server.") ); + bottom->setVisible(true); + if (race_manager->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX) + { + middle->setVisible(false); // you have to wait the server to start again + bottom->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + } + return; + } + // If something was unlocked // ------------------------- int n = unlock_manager->getCurrentSlot()->getRecentlyCompletedChallenges().size(); @@ -215,6 +233,22 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget, assert(false); } + // If we're playing online : + if (NetworkWorld::getInstance()->isRunning()) + { + StateManager::get()->popMenu(); + if (name == "middle") // Continue button (return to server lobby) + { + } + if (name == "bottom") // Quit server (return to main menu) + { + race_manager->exitRace(); + race_manager->setAIKartOverride(""); + StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); + } + return; + } + // Next check for GP // ----------------- if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)