diff --git a/src/network/network.cpp b/src/network/network.cpp index dacd3100e..c88ef760f 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -23,6 +23,7 @@ #include "network/event.hpp" #include "network/network_config.hpp" #include "network/network_string.hpp" +#include "network/socket_address.hpp" #include "network/transport_address.hpp" #include "utils/file_utils.hpp" #include "utils/log.hpp" @@ -179,6 +180,90 @@ int Network::receiveRawPacket(char *buffer, int buf_len, return len; } // receiveRawPacket +// ---------------------------------------------------------------------------- +/** \brief Sends a packet whithout ENet adding its headers. + * This function is used in particular to achieve the STUN protocol. + * \param data : Data to send. + * \param dst : Destination of the packet. + */ +void Network::sendRawPacket(const BareNetworkString &buffer, + const SocketAddress& dst) +{ + sendto(m_host->socket, buffer.getData(), buffer.size(), 0, + dst.getSockaddr(), dst.getSocklen()); + if (m_connection_debug) + { + Log::verbose("Network", "Raw packet sent to %s", + dst.toString().c_str()); + } + Network::logPacket(buffer, false); +} // sendRawPacket + +// ---------------------------------------------------------------------------- +/** \brief Receives a packet directly from the network interface and + * filter its address. + * Receive a packet whithout ENet processing it. Checks that the + * sender of the packet is the one that corresponds to the sender + * parameter. Does not check the port right now. + * \param buffer A buffer to receive the data in. + * \param buf_len Length of the buffer. + * \param[out] sender : Transport address of the original sender of the + * wanted packet. If the ip address is 0, do not check + * the sender's ip address, otherwise wait till a message + * from the specified sender arrives. All other messages + * are discarded. + * \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 Length of the received data, or -1 if no data was received. + */ +int Network::receiveRawPacket(char *buffer, int buf_len, + SocketAddress *sender, int max_tries) +{ + memset(buffer, 0, buf_len); + + struct sockaddr_storage addr = {}; + socklen_t from_len = sizeof(addr); + + int len = recvfrom(m_host->socket, buffer, buf_len, 0, + (struct sockaddr*)(&addr), &from_len); + + int count = 0; + // wait to receive the message because enet sockets are non-blocking + while(len < 0 && (countsocket, buffer, buf_len, 0, + (struct sockaddr*)(&addr), &from_len); + } + + // No message received + if(len<0) + return -1; + + Network::logPacket(BareNetworkString(buffer, len), true); + switch (addr.ss_family) + { + case AF_INET: + sender->setSockAddrIn(AF_INET, (sockaddr*)(&addr), + sizeof(sockaddr_in)); + break; + case AF_INET6: + sender->setSockAddrIn(AF_INET6, (sockaddr*)(&addr), + sizeof(sockaddr_in6)); + break; + default: + break; + } + if (m_connection_debug) + { + Log::verbose("Network", "Address of the sender was %s", + sender->toString().c_str()); + } + return len; +} // receiveRawPacket + // ---------------------------------------------------------------------------- /** \brief Broadcasts a packet to all peers. * \param data : Data to send. diff --git a/src/network/network.hpp b/src/network/network.hpp index 43d2dba7c..97bcda748 100644 --- a/src/network/network.hpp +++ b/src/network/network.hpp @@ -37,6 +37,7 @@ class BareNetworkString; class NetworkString; class TransportAddress; +class SocketAddress; /** \class EnetHost * A small wrapper around enet to allow sending and receiving @@ -68,6 +69,10 @@ public: const TransportAddress& dst); int receiveRawPacket(char *buffer, int buf_len, TransportAddress* sender, int max_tries = -1); + void sendRawPacket(const BareNetworkString &buffer, + const SocketAddress& dst); + int receiveRawPacket(char *buffer, int buf_len, + SocketAddress* sender, int max_tries = -1); void broadcastPacket(NetworkString *data, bool reliable = true); diff --git a/src/network/protocols/connect_to_peer.cpp b/src/network/protocols/connect_to_peer.cpp index d26be1fbc..699c02c5b 100644 --- a/src/network/protocols/connect_to_peer.cpp +++ b/src/network/protocols/connect_to_peer.cpp @@ -17,7 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "network/protocols/connect_to_peer.hpp" - +#include "network/network.hpp" #include "network/stk_host.hpp" #include "utils/time.hpp" #include "utils/log.hpp" @@ -26,7 +26,7 @@ /** Constructor for peer address. * \param address The address to connect to. */ -ConnectToPeer::ConnectToPeer(const TransportAddress &address) +ConnectToPeer::ConnectToPeer(const SocketAddress &address) : Protocol(PROTOCOL_CONNECTION) { m_peer_address = address; @@ -62,13 +62,14 @@ void ConnectToPeer::asynchronousUpdate() // the client will use enet intercept to discover if server // address or port is different from stk addons database. // (Happens if there is firewall in between) - TransportAddress broadcast_address; - broadcast_address = m_peer_address; + BareNetworkString aloha("aloha-stk"); // Enet packet will not have 0xFFFF for first 2 bytes - BareNetworkString aloha("aloha-stk"); + // We use the feature to distinguish between the enet packets + // and this aloha aloha.getBuffer().insert(aloha.getBuffer().begin(), 2, 0xFF); - STKHost::get()->sendRawPacket(aloha, broadcast_address); + + STKHost::get()->sendRawPacket(aloha, m_peer_address); Log::debug("ConnectToPeer", "Broadcast aloha sent."); // 20 seconds timeout if (m_tried_connection++ > 10) diff --git a/src/network/protocols/connect_to_peer.hpp b/src/network/protocols/connect_to_peer.hpp index 48b3c514b..32687373b 100644 --- a/src/network/protocols/connect_to_peer.hpp +++ b/src/network/protocols/connect_to_peer.hpp @@ -20,7 +20,7 @@ #define CONNECT_TO_PEER_HPP #include "network/protocol.hpp" -#include "network/transport_address.hpp" +#include "network/socket_address.hpp" #include "utils/cpp2011.hpp" /** One instance of this is started for every peer who tries to @@ -29,8 +29,7 @@ class ConnectToPeer : public Protocol { protected: - - TransportAddress m_peer_address; + SocketAddress m_peer_address; /** Timer use for tracking broadcast. */ uint64_t m_timer = 0; @@ -46,7 +45,7 @@ protected: } m_state; public: - ConnectToPeer(const TransportAddress &address); + ConnectToPeer(const SocketAddress &address); virtual ~ConnectToPeer() {} virtual void setup() OVERRIDE {} virtual void update(int ticks) OVERRIDE {} diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d5d0892db..2deacc53c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -31,6 +31,7 @@ #include "network/crypto.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" +#include "network/network.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" #include "network/peer_vote.hpp" @@ -2604,7 +2605,9 @@ void ServerLobby::checkIncomingConnectionRequests() { uint32_t addr, id; uint16_t port; + std::string ipv6; users_xml->getNode(i)->get("ip", &addr); + users_xml->getNode(i)->get("ipv6", &ipv6); users_xml->getNode(i)->get("port", &port); users_xml->getNode(i)->get("id", &id); users_xml->getNode(i)->get("aes-key", &keys[id].m_aes_key); @@ -2615,7 +2618,10 @@ void ServerLobby::checkIncomingConnectionRequests() keys[id].m_tried = false; if (ServerConfig::m_firewalled_server) { - TransportAddress peer_addr(addr, port); + SocketAddress peer_addr(addr, port); + if (!ipv6.empty()) + peer_addr.init(ipv6, port); + peer_addr.convertForIPv6Socket(); std::string peer_addr_str = peer_addr.toString(); if (sl->m_pending_peer_connection.find(peer_addr_str) != sl->m_pending_peer_connection.end()) diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 29c5b8c19..6a68f40c4 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -344,9 +344,7 @@ void loadServerLobbyFromConfig() if (m_ipv6_server) { -#ifdef ENABLE_IPV6 - m_firewalled_server = false; -#else +#ifndef ENABLE_IPV6 Log::warn("ServerConfig", "IPv6 support not compiled."); #endif } diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index e2abf326f..de4d919c4 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -1302,7 +1302,7 @@ void STKHost::handleDirectSocketRequest(Network* direct_socket, const int LEN=2048; char buffer[LEN]; - TransportAddress sender; + SocketAddress sender; int len = direct_socket->receiveRawPacket(buffer, LEN, &sender, 1); if(len<=0) return; BareNetworkString message(buffer, len); @@ -1383,6 +1383,25 @@ bool STKHost::peerExists(const TransportAddress& peer) return false; } // peerExists +// ---------------------------------------------------------------------------- +/** \brief Tells if a peer is known. + * \return True if the peer is known, false elseway. + */ +bool STKHost::peerExists(const SocketAddress& peer) +{ + std::lock_guard lock(m_peers_mutex); + for (auto p : m_peers) + { + auto stk_peer = p.second; + if (stk_peer->getSocketAddress() == peer || + ((stk_peer->getSocketAddress().isPublicAddressLocalhost() && + peer.isPublicAddressLocalhost()) && + stk_peer->getSocketAddress().getPort() == peer.getPort())) + return true; + } + return false; +} // peerExists + // ---------------------------------------------------------------------------- /** \brief Return the only server peer for client. * \return STKPeer the STKPeer of server. @@ -1691,3 +1710,17 @@ std::string STKHost::getVaildPublicAddress() const return m_public_address.toString(); return ""; } // getVaildPublicAddress + +// ---------------------------------------------------------------------------- +int STKHost::receiveRawPacket(char *buffer, int buffer_len, + SocketAddress* sender, int max_tries) +{ + return m_network->receiveRawPacket(buffer, buffer_len, sender, + max_tries); +} // receiveRawPacket +// ---------------------------------------------------------------------------- +void STKHost::sendRawPacket(const BareNetworkString &buffer, + const SocketAddress& dst) +{ + m_network->sendRawPacket(buffer, dst); +} // sendRawPacket diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index 325cf3ac5..5856a026b 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -54,6 +54,7 @@ class NetworkTimerSynchronizer; class Server; class ServerLobby; class SeparateProcess; +class SocketAddress; enum ENetCommandType : unsigned int { @@ -273,6 +274,8 @@ public: // ------------------------------------------------------------------------ bool peerExists(const TransportAddress& peer_address); // ------------------------------------------------------------------------ + bool peerExists(const SocketAddress& peer_address); + // ------------------------------------------------------------------------ bool isConnectedTo(const TransportAddress& peer_address); // ------------------------------------------------------------------------ std::shared_ptr getServerPeerForClient() const; @@ -307,6 +310,12 @@ public: m_network->sendRawPacket(buffer, dst); } // sendRawPacket // ------------------------------------------------------------------------ + int receiveRawPacket(char *buffer, int buffer_len, + SocketAddress* sender, int max_tries = -1); + // ------------------------------------------------------------------------ + void sendRawPacket(const BareNetworkString &buffer, + const SocketAddress& dst); + // ------------------------------------------------------------------------ Network* getNetwork() const { return m_network; } // ------------------------------------------------------------------------ /** Returns a copied list of peers. */ diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index f9f593de7..b8c9c37f5 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -23,6 +23,7 @@ #include "network/event.hpp" #include "network/network_config.hpp" #include "network/network_string.hpp" +#include "network/socket_address.hpp" #include "network/stk_ipv6.hpp" #include "network/stk_host.hpp" #include "network/transport_address.hpp" @@ -38,9 +39,25 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id) : m_peer_address(enet_peer->address), m_host(host) { m_addons_scores.fill(-1); - // We use 0.x.x.x ip to map to IPv6 address internally - if (m_peer_address.getIP() < 16777216) - m_ipv6_address = getIPV6ReadableFromMappedAddress(&enet_peer->address); + uint32_t addr = htonl(enet_peer->address.host); +#ifdef ENABLE_IPV6 + if (isIPv6Socket()) + { + // This will return the mapped IPv4 address too for IPv6 socket + // So we can sendto directly with it + struct sockaddr_in6 in6 = {}; + getIPV6FromMappedAddress(&enet_peer->address, &in6); + m_socket_address.reset(new SocketAddress()); + m_socket_address->setSockAddrIn(AF_INET6, (sockaddr*)&in6, sizeof(in6)); + if (m_socket_address->isIPv6()) + m_ipv6_address = m_socket_address->toString(false/*show_port*/); + } + else +#endif + { + m_socket_address.reset( + new SocketAddress(addr, enet_peer->address.port)); + } m_enet_peer = enet_peer; m_host_id = host_id; m_connected_time = StkTime::getMonoTimeMs(); diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 5796cc3f7..a3c305635 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -43,7 +43,7 @@ class Crypto; class NetworkPlayerProfile; class NetworkString; class STKHost; -class TransportAddress; +class SocketAddress; enum PeerDisconnectInfo : unsigned int { @@ -89,6 +89,8 @@ protected: TransportAddress m_peer_address; + std::unique_ptr m_socket_address; + STKHost* m_host; std::vector > m_players; @@ -293,6 +295,9 @@ public: } // ------------------------------------------------------------------------ int getConsecutiveMessages() const { return m_consecutive_messages; } + // ------------------------------------------------------------------------ + const SocketAddress& getSocketAddress() const + { return *m_socket_address.get(); } }; // STKPeer #endif // STK_PEER_HPP