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
This commit is contained in:
hilnius 2013-08-26 14:14:52 +00:00
parent 74c819fd8d
commit 93ec81f309
5 changed files with 88 additions and 9 deletions

View File

@ -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 <assert.h>
#include <netdb.h>
#include <sys/types.h>
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<char*> 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

View File

@ -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

View File

@ -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)
{

View File

@ -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.
*/

View File

@ -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)