fixing all kind of problems with connection. Now everything works even if weird network configurations (like mine). It might not work behind professional (work) NATs.

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@13643 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hilnius 2013-09-07 18:49:48 +00:00
parent ff8fda6219
commit 6c9473dc1b
24 changed files with 212 additions and 47 deletions

View File

@ -25,17 +25,32 @@
#include "network/network_manager.hpp"
/*! \class ClientNetworkManager
* \ingroup network
*/
class ClientNetworkManager : public NetworkManager
{
friend class Singleton<NetworkManager>;
public:
/*! \brief Get the instance.
* This is a utility function to avoid passing templates parameters
* to the getInstance singleton method.
*/
static ClientNetworkManager* getInstance()
{
return Singleton<NetworkManager>::getInstance<ClientNetworkManager>();
}
/*! \brief Initializes network.
* This starts the threads and initializes network libraries.
*/
virtual void run();
/*! \brief Resets the network socket. */
virtual void reset();
/*! \brief Sends a packet to the server.
* \param data : The network 8-bit string to send.
* \param reliable : If set to true, ENet will ensure that the packet is received.
*/
virtual void sendPacket(const NetworkString& data, bool reliable = true);
STKPeer* getPeer();

View File

@ -70,6 +70,10 @@ class Event
*/
void removeFront(int size);
/*! \brief Get a copy of the data.
* \return A copy of the message data. This is empty for events like
* connection or disconnections.
*/
NetworkString data() const { return m_data; }
EVENT_TYPE type; //!< Type of the event.

View File

@ -56,15 +56,37 @@ class GameSetup
bool removePlayer(uint32_t id); //!< Remove a player by id.
bool removePlayer(uint8_t id); //!< Remove a player by local id.
void setPlayerKart(uint8_t id, std::string kart_name); //!< Set the kart of a player
void bindKartsToProfiles();
void bindKartsToProfiles(); //!< Sets the right world_kart_id in profiles
std::vector<NetworkPlayerProfile*> getPlayers() { return m_players; }
int getPlayerCount() { return m_players.size(); }
const NetworkPlayerProfile* getProfile(uint32_t id); //!< Get a profile by database id
const NetworkPlayerProfile* getProfile(uint8_t id); //!< Get the profile by the lobby id
/*! \brief Get a network player profile matching a universal id.
* \param id : Global id of the player (the one in the SQL database)
* \return The profile of the player matching the id.
*/
const NetworkPlayerProfile* getProfile(uint32_t id);
/*! \brief Get a network player profile matching a kart name.
* \param kart_name : Name of the kart used by the player.
* \return The profile of the player having the kart kart_name
*/
const NetworkPlayerProfile* getProfile(uint8_t id);
/*! \brief Get a network player profile matching a kart name.
* \param kart_name : Name of the kart used by the player.
* \return The profile of the player having the kart kart_name.
*/
const NetworkPlayerProfile* getProfile(std::string kart_name);
/*! \brief Used to know if a kart is available.
* \param kart_name : Name of the kart to check.
* \return True if the kart hasn't been selected yet, false elseway.
*/
bool isKartAvailable(std::string kart_name);
/*! \brief Used to know if a kart is playable.
* \param kart_name : Name of the kart to check.
* \return True if the kart is playable (standard kart).
* Currently this is always true as the kart selection screen shows
* only the standard karts.
*/
bool isKartAllowed(std::string kart_name) {return true; }
protected:

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file network_interface.hpp
* \brief Defines an interface to network middle-level functions.
*/
#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H
@ -26,19 +30,21 @@
#include <pthread.h>
#include <string>
/** \class NetworkInterface
* \ingroup network
*/
class NetworkInterface : public Singleton<NetworkInterface>
{
friend class Singleton<NetworkInterface>;
public:
void initNetwork(bool server);
protected:
// protected functions
NetworkInterface();
virtual ~NetworkInterface();
};
#endif // NETWORK_INTERFACE_H

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file network_manager.hpp
* \brief Instantiates the generic functionnalities of a network manager.
*/
#ifndef NETWORKMANAGER_HPP
#define NETWORKMANAGER_HPP

View File

@ -1,3 +1,25 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file network_string.hpp
* \brief Defines functions to easily manipulate 8-bit network destinated strings.
*/
#ifndef NETWORK_STRING_HPP
#define NETWORK_STRING_HPP

View File

@ -1,3 +1,24 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file network_world.hpp
*/
#ifndef NETWORK_WORLD_HPP
#define NETWORK_WORLD_HPP

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file protocol.hpp
* \brief Generic protocols declarations.
*/
#ifndef PROTOCOL_HPP
#define PROTOCOL_HPP

View File

@ -93,10 +93,15 @@ void ConnectToPeer::asynchronousUpdate()
STKHost* host = NetworkManager::getInstance()->getHost();
TransportAddress broadcast_address;
broadcast_address.ip = -1; // 255.255.255.255
broadcast_address.port = m_peer_address.port;
broadcast_address.port = m_peer_address.port; // 0b10101100000101101101111111111111; // for test
char data[] = "aloha_stk\0";
host->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
Log::info("ConnectToPeer", "Broadcast aloha sent.");
Time::sleep(1);
broadcast_address.ip = 0x7f000001; // 127.0.0.1 (localhost)
broadcast_address.port = m_peer_address.port;
host->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
Log::info("ConnectToPeer", "Broadcast aloha to self.");
}
else
{

View File

@ -154,6 +154,7 @@ void ConnectToServer::asynchronousUpdate()
if (m_server_address.ip == 0 || m_server_address.port == 0)
{ // server data not correct, hide address and stop
m_state = HIDING_ADDRESS;
Log::error("ConnectToServer", "Server address is "ADDRESS_FORMAT, ADDRESS_ARGS(m_server_address.ip, m_server_address.port));
m_current_protocol_id = m_listener->requestStart(new HidePublicAddress());
return;
}
@ -161,9 +162,19 @@ void ConnectToServer::asynchronousUpdate()
{
// just send a broadcast packet, the client will know our ip address and will connect
STKHost* host = NetworkManager::getInstance()->getHost();
host->stopListening(); // stop the listening
TransportAddress sender;
TransportAddress broadcast_address;
broadcast_address.ip = -1; // 255.255.255.255
broadcast_address.port = 7321; // 0b10101100000101101101111111111111; // for test
char data2[] = "aloha_stk\0";
host->sendRawPacket((uint8_t*)(data2), 10, broadcast_address);
Log::info("ConnectToServer", "Waiting broadcast message.");
const uint8_t* received_data = host->receiveRawPacket(&sender); // get the sender
host->startListening(); // start listening again
const char data[] = "aloha_stk\0";
if (strcmp(data, (char*)(received_data)) == 0)
{
@ -173,12 +184,12 @@ void ConnectToServer::asynchronousUpdate()
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
getifaddrs (&ifap); // get the info
for (ifa = ifap; ifa; ifa = ifa->ifa_next)
for (ifa = ifap; ifa; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr->sa_family==AF_INET)
if (ifa->ifa_addr->sa_family==AF_INET)
{
sa = (struct sockaddr_in *) ifa->ifa_addr;
if (turnEndianness(sa->sin_addr.s_addr) == sender.ip) // this interface is ours
if (ntohl(sa->sin_addr.s_addr) == sender.ip) // this interface is ours
sender.ip = 0x7f000001; // 127.0.0.1
}
}
@ -186,7 +197,7 @@ void ConnectToServer::asynchronousUpdate()
#else
// Query the list of all IP addresses on the local host
// First call to GetIpAddrTable with 0 bytes buffer
// will return insufficient buffer error, and size
// will return insufficient buffer error, and size
// will contain the number of bytes needed for all
// data. Repeat the process of querying the size
// using GetIpAddrTable in a while loop since it
@ -263,6 +274,8 @@ void ConnectToServer::asynchronousUpdate()
m_listener->requestTerminate(this);
m_state = EXITING;
break;
case EXITING:
break;
}
}

View File

@ -19,6 +19,7 @@
#include "network/protocols/get_peer_address.hpp"
#include "network/protocol_manager.hpp"
#include "network/network_manager.hpp"
#include "online/http_manager.hpp"
#include "online/current_user.hpp"
#include "config/user_config.hpp"
@ -64,7 +65,10 @@ void GetPeerAddress::asynchronousUpdate()
{
TransportAddress* addr = static_cast<TransportAddress*>(m_callback_object);
result->get("ip", &addr->ip);
result->get("port", &addr->port);
if (addr->ip == NetworkManager::getInstance()->getPublicAddress().ip)
result->get("private_port", &addr->port);
else
result->get("port", &addr->port);
Log::debug("GetPeerAddress", "Address gotten successfully.");
}
else

View File

@ -48,7 +48,9 @@ void ShowPublicAddress::asynchronousUpdate()
m_request->setParameter("token",Online::CurrentUser::get()->getToken());
m_request->setParameter("address",addr.ip);
m_request->setParameter("port",addr.port);
m_request->setParameter("private_port",NetworkManager::getInstance()->getHost()->getPort());
m_request->setParameter("action","set");
Log::info("ShowPublicAddress", "Showing addr %u and port %d", addr.ip, addr.port);
Online::HTTPManager::get()->addRequest(m_request);
m_state = REQUEST_PENDING;

View File

@ -47,8 +47,10 @@ void StartServer::asynchronousUpdate()
m_request->setParameter("token",Online::CurrentUser::get()->getToken());
m_request->setParameter("address",addr.ip);
m_request->setParameter("port",addr.port);
m_request->setParameter("private_port",NetworkManager::getInstance()->getHost()->getPort());
m_request->setParameter("max_players",UserConfigParams::m_server_max_players);
m_request->setParameter("action","start-server");
Log::info("ShowPublicAddress", "Showing addr %u and port %d", addr.ip, addr.port);
Online::HTTPManager::get()->addRequest(m_request);
m_state = REQUEST_PENDING;

View File

@ -53,6 +53,7 @@ void StopServer::asynchronousUpdate()
m_request->setParameter("address",addr.ip);
m_request->setParameter("port",addr.port);
m_request->setParameter("action","stop-server");
Log::info("StopServer", "address %u, port %d", addr.ip, addr.port);
Online::HTTPManager::get()->addRequest(m_request);
m_state = REQUEST_PENDING;

View File

@ -1,6 +1,6 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008 Joerg Henrichs
// Copyright (C) 2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@ -16,6 +16,9 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file remote_kart_info.hpp
*/
#ifndef HEADER_REMOTE_KART_INFO_HPP
#define HEADER_REMOTE_KART_INFO_HPP

View File

@ -16,6 +16,9 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file server_network_manager.hpp
*/
#ifndef SERVER_NETWORK_MANAGER_HPP
#define SERVER_NETWORK_MANAGER_HPP

View File

@ -16,22 +16,39 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file singleton.hpp
*/
#ifndef SINGLETON_HPP
#define SINGLETON_HPP
#include "utils/log.hpp"
/*! \class ProtocolManager
* \brief Manages the protocols at runtime.
* This has been designed to allow multi-inheritance. This is advised to
* re-declare getInstance, but whithout templates parameters in the inheriting
* classes.
*/
template <typename T>
class Singleton
{
protected:
/*! \brief Constructor */
Singleton () { m_singleton = NULL; }
/*! \brief Destructor */
virtual ~Singleton ()
{
Log::info("Singleton", "Destroyed singleton.");
}
public:
/*! \brief Used to get the instance, after a dynamic cast.
* This is important when making a double-inheritance of this class.
* For example, if A is a singleton inherited by B, you can call
* B::getInstance<A>() to have the instance returned as a A*.
* If the cast fails, a log message will notify it.
*/
template<typename S>
static S *getInstance ()
{
@ -43,11 +60,13 @@ class Singleton
Log::debug("Singleton", "THE SINGLETON HAS NOT BEEN REALOCATED, IT IS NOT OF THE REQUESTED TYPE.");
return result;
}
/*! \brief Used to get the instance. */
static T *getInstance()
{
return (dynamic_cast<T*> (m_singleton));
return m_singleton;
}
/*! \brief Used to kill the singleton, if needed. */
static void kill ()
{
if (m_singleton)

View File

@ -28,6 +28,7 @@
# define inet_ntop InetNtop
#else
# include <arpa/inet.h>
# include <errno.h>
#endif
#include <pthread.h>
#include <signal.h>
@ -51,6 +52,7 @@ void* STKHost::receive_data(void* self)
myself->m_listening = false;
delete myself->m_listening_thread;
myself->m_listening_thread = NULL;
Log::info("STKHost", "Listening has been stopped");
return NULL;
}
@ -133,7 +135,11 @@ void STKHost::stopListening()
{
if(m_listening_thread)
{
pthread_mutex_unlock(&m_exit_mutex); // will stop the update function
pthread_mutex_unlock(&m_exit_mutex); // will stop the update function on its next update
while (m_listening == true)
{
Time::sleep(1);
}
}
}
@ -183,32 +189,31 @@ uint8_t* STKHost::receiveRawPacket(TransportAddress* sender)
memset(buffer, 0, 2048);
socklen_t from_len;
struct sockaddr addr;
struct sockaddr_in addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len);
int len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len);
int i = 0;
// wait to receive the message because enet sockets are non-blocking
while(len == -1) // nothing received
{
i++;
len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, &addr, &from_len);
len = recvfrom(m_host->socket, (char*)buffer, 2048, 0, (struct sockaddr*)(&addr), &from_len);
Time::sleep(1); // wait 1 millisecond between two checks
}
if (len == SOCKET_ERROR)
{
Log::error("STKHost", "Problem with the socket. Please contact the dev team.");
}
struct sockaddr_in *sin = (struct sockaddr_in *) (&addr);
// we received the data
sender->ip = turnEndianness((uint32_t)(sin->sin_addr.s_addr));
sender->port = turnEndianness(sin->sin_port);
sender->ip = ntohl((uint32_t)(addr.sin_addr.s_addr));
sender->port = ntohs(addr.sin_port);
if (addr.sa_family == AF_INET)
if (addr.sin_family == AF_INET)
{
char s[20];
inet_ntop(AF_INET, &(((struct sockaddr_in *)&addr)->sin_addr), s, 20);
inet_ntop(AF_INET, &(addr.sin_addr), s, 20);
Log::info("STKHost", "IPv4 Address of the sender was %s", s);
}
return buffer;
@ -245,7 +250,7 @@ uint8_t* STKHost::receiveRawPacket(TransportAddress sender, int max_tries)
Time::sleep(1); // wait 1 millisecond between two checks
if (i >= max_tries && max_tries != -1)
{
Log::verbose("STKHost", "No answer from the server on %u.%u.%u.%u:%u", (m_host->address.host&0xff),
Log::verbose("STKHost", "No answer from the server on %u.%u.%u.%u:%u", (m_host->address.host&0xff),
(m_host->address.host>>8&0xff),
(m_host->address.host>>16&0xff),
(m_host->address.host>>24&0xff),
@ -277,7 +282,7 @@ bool STKHost::peerExists(TransportAddress peer)
{
for (unsigned int i = 0; i < m_host->peerCount; i++)
{
if (m_host->peers[i].address.host == turnEndianness(peer.ip) &&
if (m_host->peers[i].address.host == ntohl(peer.ip) &&
m_host->peers[i].address.port == peer.port)
{
return true;
@ -292,7 +297,7 @@ bool STKHost::isConnectedTo(TransportAddress peer)
{
for (unsigned int i = 0; i < m_host->peerCount; i++)
{
if (m_host->peers[i].address.host == turnEndianness(peer.ip) &&
if (m_host->peers[i].address.host == ntohl(peer.ip) &&
m_host->peers[i].address.port == peer.port &&
m_host->peers[i].state == ENET_PEER_STATE_CONNECTED)
{
@ -314,4 +319,15 @@ int STKHost::mustStopListening()
return 0;
}
return 1;
}
}
uint16_t STKHost::getPort() const
{
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (getsockname(m_host->socket, (struct sockaddr *)&sin, &len) == -1)
Log::error("STKHost", "Error while using getsockname().");
else
return ntohs(sin.sin_port);
return 0;
}

View File

@ -144,7 +144,10 @@ class STKHost
/*! \brief Returns true when the thread should stop listening. */
int mustStopListening();
/*! \brief Returns true when the thread has stopped listening. */
bool hasStoppedListening() { return m_listening; }
bool hasStoppedListening() const { return m_listening; }
uint32_t getAddress() const { return m_host->address.host; }
uint16_t getPort() const;
protected:
ENetHost* m_host; //!< ENet host interfacing sockets.
pthread_t* m_listening_thread; //!< Thread listening network events.

View File

@ -112,7 +112,7 @@ void STKPeer::sendPacket(NetworkString const& data, bool reliable)
uint32_t STKPeer::getAddress() const
{
return turnEndianness(m_peer->address.host);
return ntohl(m_peer->address.host);
}
//-----------------------------------------------------------------------------

View File

@ -16,6 +16,10 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*! \file stk_peer.hpp
* \brief Defines functions to easily manipulate 8-bit network destinated strings.
*/
#ifndef STK_PEER_HPP
#define STK_PEER_HPP
@ -24,6 +28,10 @@
#include "network/game_setup.hpp"
#include <enet/enet.h>
/*! \class STKPeer
* \brief Represents a peer.
* This class is used to interface the ENetPeer structure.
*/
class STKPeer
{
friend class Event;

View File

@ -1,15 +1 @@
#include "network/types.hpp"
uint32_t turnEndianness(uint32_t val)
{
return ((val&0xff000000)>>24)
+((val&0x00ff0000)>>8)
+((val&0x0000ff00)<<8)
+((val&0x000000ff)<<24);
}
uint16_t turnEndianness(uint16_t val)
{
return ((val&0xff00)>>8)
+((val&0x00ff)<<8);
}

View File

@ -26,6 +26,10 @@
#include <string>
/*! functions to write easily addresses in logs. */
#define ADDRESS_FORMAT "%d.%d.%d.%d:%d"
#define ADDRESS_ARGS(ip,port) ((ip>>24)&0xff),((ip>>16)&0xff),((ip>>8)&0xff),((ip>>0)&0xff),port
/*! \class CallbackObject
* \brief Class that must be inherited to pass objects to protocols.
*/
@ -71,8 +75,5 @@ class PlayerLogin : public CallbackObject
std::string password; //!< Password of the player
};
uint32_t turnEndianness(uint32_t val);
uint16_t turnEndianness(uint16_t val);
#endif // TYPES_HPP

View File

@ -28,6 +28,7 @@
typedef unsigned __int64 uint64_t;
#else
# include <stdint.h>
#define SOCKET_ERROR -1
#endif
#endif