3131#include " network/server.hpp"
3232#include " network/stk_host.hpp"
3333#include " network/stk_peer.hpp"
34+ #include " network/unix_ipv6.hpp"
3435#include " online/xml_request.hpp"
3536#include " states_screens/online/networking_lobby.hpp"
3637#include " utils/time.hpp"
3738#include " utils/log.hpp"
3839#include " utils/string_utils.hpp"
3940#include " utils/translation.hpp"
4041
42+ #ifdef WIN32
43+ # include < ws2tcpip.h>
44+ #else
45+ # include < netdb.h>
46+ #endif
47+
4148#include < algorithm>
4249// ============================================================================
4350std::weak_ptr<bool > ConnectToServer::m_previous_unjoin;
@@ -84,8 +91,14 @@ void ConnectToServer::setup()
8491 Log::info (" ConnectToServer" , " SETUP" );
8592 // In case of LAN or client-server we already have the server's
8693 // and our ip address, so we can immediately start requesting a connection.
87- m_state = NetworkConfig::get ()->isLAN () ?
88- GOT_SERVER_ADDRESS : SET_PUBLIC_ADDRESS;
94+ if (NetworkConfig::get ()->isLAN ())
95+ {
96+ m_state = GOT_SERVER_ADDRESS;
97+ if (m_server->useIPV6Connection ())
98+ setIPV6 (1 );
99+ }
100+ else
101+ m_state = SET_PUBLIC_ADDRESS;
89102} // setup
90103
91104// ----------------------------------------------------------------------------
@@ -211,6 +224,11 @@ void ConnectToServer::asynchronousUpdate()
211224 }
212225 servers.clear ();
213226 }
227+ if (m_server->useIPV6Connection ())
228+ {
229+ // Disable STUN if using ipv6 (check in setPublicAddress)
230+ setIPV6 (1 );
231+ }
214232 if (m_server->supportsEncryption ())
215233 {
216234 STKHost::get ()->setPublicAddress ();
@@ -247,11 +265,19 @@ void ConnectToServer::asynchronousUpdate()
247265 // direct connection to server first, if failed than use the one
248266 // that has stun mapped, the first 8 seconds allow the server to
249267 // start the connect to peer protocol first before the port is
250- // remapped
251- if (tryConnect (2000 , 4 , true /* another_port*/ ))
252- break ;
253- if (!tryConnect (2000 , 11 ))
254- m_state = DONE;
268+ // remapped. IPV6 has no stun so try once with any port
269+ if (isIPV6 ())
270+ {
271+ if (!tryConnect (2000 , 15 , true /* another_port*/ , true /* ipv6*/ ))
272+ m_state = DONE;
273+ }
274+ else
275+ {
276+ if (tryConnect (2000 , 4 , true /* another_port*/ ))
277+ break ;
278+ if (!tryConnect (2000 , 11 ))
279+ m_state = DONE;
280+ }
255281 break ;
256282 }
257283 case DONE:
@@ -337,7 +363,8 @@ int ConnectToServer::interceptCallback(ENetHost* host, ENetEvent* event)
337363} // interceptCallback
338364
339365// ----------------------------------------------------------------------------
340- bool ConnectToServer::tryConnect (int timeout, int retry, bool another_port)
366+ bool ConnectToServer::tryConnect (int timeout, int retry, bool another_port,
367+ bool ipv6)
341368{
342369 m_retry_count = retry;
343370 ENetEvent event;
@@ -352,20 +379,51 @@ bool ConnectToServer::tryConnect(int timeout, int retry, bool another_port)
352379
353380 m_done_intecept = false ;
354381 nw->getENetHost ()->intercept = ConnectToServer::interceptCallback;
382+
383+ std::string connecting_address = m_server_address.toString ();
384+ if (ipv6)
385+ {
386+ struct addrinfo hints;
387+ struct addrinfo * res = NULL ;
388+ memset (&hints, 0 , sizeof (hints));
389+ hints.ai_family = AF_INET6;
390+ hints.ai_socktype = SOCK_STREAM;
391+ if (getaddrinfo (m_server->getIPV6Address ().c_str (),
392+ StringUtils::toString (m_server->getAddress ().getPort ()).c_str (),
393+ &hints, &res) != 0 || res == NULL )
394+ return false ;
395+ for (const struct addrinfo * addr = res; addr != NULL ;
396+ addr = addr->ai_next )
397+ {
398+ if (addr->ai_family == AF_INET6)
399+ {
400+ struct sockaddr_in6 * ipv6 =
401+ (struct sockaddr_in6 *)addr->ai_addr ;
402+ ENetAddress addr = m_server_address.toEnetAddress ();
403+ connecting_address = std::string (" [" ) +
404+ m_server->getIPV6Address () + " ]:" +
405+ StringUtils::toString (addr.port );
406+ addMappedAddress (&addr, ipv6);
407+ break ;
408+ }
409+ }
410+ freeaddrinfo (res);
411+ }
412+
355413 while (--m_retry_count >= 0 && !ProtocolManager::lock ()->isExiting ())
356414 {
357415 ENetPeer* p = nw->connectTo (m_server_address);
358416 if (!p)
359417 break ;
360418 Log::info (" ConnectToServer" , " Trying connecting to %s from port %d, "
361- " retry remain: %d" , m_server_address. toString () .c_str (),
419+ " retry remain: %d" , connecting_address .c_str (),
362420 nw->getENetHost ()->address .port , m_retry_count);
363421 while (enet_host_service (nw->getENetHost (), &event, timeout) != 0 )
364422 {
365423 if (event.type == ENET_EVENT_TYPE_CONNECT)
366424 {
367425 Log::info (" ConnectToServer" , " Connected to %s" ,
368- m_server_address. toString () .c_str ());
426+ connecting_address .c_str ());
369427 nw->getENetHost ()->intercept = NULL ;
370428 STKHost::get ()->initClientNetwork (event, nw);
371429 m_state = DONE;
0 commit comments