SuperTuxKart
Loading...
Searching...
No Matches
stun_detection.hpp
1//
2// SuperTuxKart - a fun racing game with go-kart
3// Copyright (C) 2015 Joerg Henrichs
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 3
8// of the License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19#ifdef ENABLE_IPV6
20
21#ifndef HEADER_STUN_DETECTION
22#define HEADER_STUN_DETECTION
23
24#include "network/socket_address.hpp"
25#include <atomic>
26#include <thread>
27
28#ifdef WIN32
29# include <winsock.h>
30#else
31# include <sys/socket.h>
32#endif
33
34class StunDetection
35{
36private:
38 std::thread m_thread;
39
41#ifdef WIN32
42 SOCKET m_socket;
43#else
44 int m_socket;
45#endif
46
48 std::atomic_bool m_connected;
49
51 std::atomic_bool m_socket_closed;
52public:
53 // ------------------------------------------------------------------------
54 StunDetection(const std::string& addr, bool ipv4)
55 {
56 m_connected = false;
57 m_socket_closed = true;
58 SocketAddress sa(addr.c_str(), 0/*port specified in addr*/,
59 ipv4 ? AF_INET : AF_INET6);
60 if (sa.isUnset() || (ipv4 && sa.getFamily() != AF_INET) ||
61 (!ipv4 && sa.getFamily() != AF_INET6))
62 return;
63 m_socket = socket(ipv4? AF_INET : AF_INET6, SOCK_STREAM, 0);
64#ifdef WIN32
65 if (m_socket == INVALID_SOCKET)
66 return;
67#else
68 if (m_socket == -1)
69 return;
70#endif
71 m_socket_closed = false;
72 m_thread = std::thread([addr, ipv4, sa, this]()
73 {
74 uint64_t t = StkTime::getMonoTimeMs();
75 if (connect(m_socket, sa.getSockaddr(), sa.getSocklen()) == -1)
76 m_connected.store(false);
77 else
78 m_connected.store(true);
79 shutdown(m_socket, 2);
80#ifdef WIN32
81 closesocket(m_socket);
82#else
83 close(m_socket);
84#endif
85 m_socket_closed.store(true);
86 Log::debug("StunDetection", "Took %dms for %s.",
87 (int)(StkTime::getMonoTimeMs() - t),
88 (addr + (ipv4 ? " (IPv4)" : " (IPv6)")).c_str());
89 });
90 }
91 // ------------------------------------------------------------------------
92 ~StunDetection()
93 {
94 if (m_thread.joinable())
95 {
96 if (m_socket_closed)
97 m_thread.join();
98 else
99 m_thread.detach();
100 }
101 }
102 // ------------------------------------------------------------------------
103 bool isConnecting()
104 { return m_thread.joinable() && m_socket_closed == false; }
105 // ------------------------------------------------------------------------
106 bool connectionSucceeded() { return m_connected == true; }
107 // ------------------------------------------------------------------------
108 bool socketClosed() { return m_socket_closed == true; }
109};
110#endif
111
112#endif
Describes a IPv4 or IPv6 address in sockaddr_in(6) format, suitable in using with sendto.
Definition: socket_address.hpp:47
static uint64_t getMonoTimeMs()
Returns a time based since the starting of stk (monotonic clock).
Definition: time.hpp:106