diff options
author | Patric Stout <truebrain@openttd.org> | 2021-05-06 23:13:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-06 23:13:35 +0200 |
commit | f7e390bdc084a20462fe833373087fd9106c5972 (patch) | |
tree | 26122beb7a783b37132bbe60ba13966ac87843b1 /src/network/core/tcp.h | |
parent | f1dfa661a1898cde06a38ab4cb230c95912b245b (diff) | |
download | openttd-f7e390bdc084a20462fe833373087fd9106c5972.tar.xz |
Feature: use Happy Eyeballs to make network connections (TCP-only) (#9199)
Hostnames like "content.openttd.org" resolve into multiple IPv4 and IPv6.
It is possible that either of the IPs is not working, either due to
a poorly configured OS (having IPv6 but no valid route), broken network
paths, or a service that is temporary unavailable.
Instead of trying the IPs one by one, waiting for a 3s timeout between
each, be a bit more like browsers, and stack attempts on top of each
other with slight delays. This is called Happy Eyebells.
Initially, try the first IPv6 address. If within 250ms there is no
connection yet, try the first IPv4 address. 250ms later, try the
second IPv6 address, etc, till all addresses are tried.
If any connection is created, abort all the other (pending) connections
and use the one that is created. If all fail 3s after the last connect(),
trigger a timeout for all.
Diffstat (limited to 'src/network/core/tcp.h')
-rw-r--r-- | src/network/core/tcp.h | 28 |
1 files changed, 17 insertions, 11 deletions
diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index 5acf9d12e..b90ce0232 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -15,6 +15,7 @@ #include "address.h" #include "packet.h" +#include <chrono> #include <atomic> /** The states of sending the packets. */ @@ -63,23 +64,28 @@ public: */ class TCPConnecter { private: - std::atomic<bool> connected;///< Whether we succeeded in making the connection - std::atomic<bool> aborted; ///< Whether we bailed out (i.e. connection making failed) - bool killed; ///< Whether we got killed - SOCKET sock; ///< The socket we're connecting with + addrinfo *ai = nullptr; ///< getaddrinfo() allocated linked-list of resolved addresses. + std::vector<addrinfo *> addresses; ///< Addresses we can connect to. + size_t current_address = 0; ///< Current index in addresses we are trying. - void Connect(); + std::vector<SOCKET> sockets; ///< Pending connect() attempts. + std::chrono::steady_clock::time_point last_attempt; ///< Time we last tried to connect. - static void ThreadEntry(TCPConnecter *param); + std::atomic<bool> is_resolved = false; ///< Whether resolving is done. -protected: - /** Address we're connecting to */ - NetworkAddress address; + void Resolve(); + void OnResolved(addrinfo *ai); + bool TryNextAddress(); + void Connect(addrinfo *address); + bool CheckActivity(); + + static void ResolveThunk(TCPConnecter *connecter); public: + std::string connection_string; ///< Current address we are connecting to (before resolving). + TCPConnecter(const std::string &connection_string, uint16 default_port); - /** Silence the warnings */ - virtual ~TCPConnecter() {} + virtual ~TCPConnecter(); /** * Callback when the connection succeeded. |