2009-08-21 22:21:05 +02:00
|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* OpenTTD 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, version 2.
|
|
|
|
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2009-01-20 12:28:18 +01:00
|
|
|
/**
|
|
|
|
* @file tcp_connect.cpp Basic functions to create connections without blocking.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "../../stdafx.h"
|
2019-03-17 01:59:46 +01:00
|
|
|
#include "../../thread.h"
|
2009-01-20 12:28:18 +01:00
|
|
|
|
|
|
|
#include "tcp.h"
|
2021-05-05 23:21:14 +02:00
|
|
|
#include "../network_internal.h"
|
2009-01-20 12:28:18 +01:00
|
|
|
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
#include <deque>
|
|
|
|
|
2014-04-23 22:13:33 +02:00
|
|
|
#include "../../safeguards.h"
|
|
|
|
|
2009-01-20 12:28:18 +01:00
|
|
|
/** List of connections that are currently being created */
|
2019-03-03 18:30:09 +01:00
|
|
|
static std::vector<TCPConnecter *> _tcp_connecters;
|
2009-01-20 12:28:18 +01:00
|
|
|
|
2011-01-22 10:53:15 +01:00
|
|
|
/**
|
|
|
|
* Create a new connecter for the given address
|
2021-05-05 23:21:14 +02:00
|
|
|
* @param connection_string the address to connect to
|
2011-01-22 10:53:15 +01:00
|
|
|
*/
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port)
|
2009-01-20 12:28:18 +01:00
|
|
|
{
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
this->connection_string = NormalizeConnectionString(connection_string, default_port);
|
2021-05-05 23:21:14 +02:00
|
|
|
|
2019-02-18 23:39:06 +01:00
|
|
|
_tcp_connecters.push_back(this);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TCPConnecter::~TCPConnecter()
|
|
|
|
{
|
2021-05-08 14:45:23 +02:00
|
|
|
if (this->resolve_thread.joinable()) {
|
|
|
|
this->resolve_thread.join();
|
|
|
|
}
|
|
|
|
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
for (const auto &socket : this->sockets) {
|
2021-05-08 11:57:41 +02:00
|
|
|
closesocket(socket);
|
2009-01-20 12:28:18 +01:00
|
|
|
}
|
2021-05-08 11:57:41 +02:00
|
|
|
this->sockets.clear();
|
|
|
|
this->sock_to_address.clear();
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
2021-06-29 23:02:25 +02:00
|
|
|
if (this->ai != nullptr) freeaddrinfo(this->ai);
|
2009-01-20 12:28:18 +01:00
|
|
|
}
|
|
|
|
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
/**
|
|
|
|
* Start a connection to the indicated address.
|
|
|
|
* @param address The address to connection to.
|
|
|
|
*/
|
|
|
|
void TCPConnecter::Connect(addrinfo *address)
|
2009-01-20 12:28:18 +01:00
|
|
|
{
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
SOCKET sock = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
|
|
|
|
if (sock == INVALID_SOCKET) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 0, "Could not create {} {} socket: {}", NetworkAddress::SocketTypeAsString(address->ai_socktype), NetworkAddress::AddressFamilyAsString(address->ai_family), NetworkError::GetLast().AsString());
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-10 13:40:28 +02:00
|
|
|
if (!SetNoDelay(sock)) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 1, "Setting TCP_NODELAY failed: {}", NetworkError::GetLast().AsString());
|
2021-05-10 13:40:28 +02:00
|
|
|
}
|
|
|
|
if (!SetNonBlocking(sock)) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 0, "Setting non-blocking mode failed: {}", NetworkError::GetLast().AsString());
|
2021-05-10 13:40:28 +02:00
|
|
|
}
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
|
|
|
NetworkAddress network_address = NetworkAddress(address->ai_addr, (int)address->ai_addrlen);
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 5, "Attempting to connect to {}", network_address.GetAddressAsString());
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
|
|
|
int err = connect(sock, address->ai_addr, (int)address->ai_addrlen);
|
|
|
|
if (err != 0 && !NetworkError::GetLast().IsConnectInProgress()) {
|
|
|
|
closesocket(sock);
|
|
|
|
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 1, "Could not connect to {}: {}", network_address.GetAddressAsString(), NetworkError::GetLast().AsString());
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-08 11:57:41 +02:00
|
|
|
this->sock_to_address[sock] = network_address;
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
this->sockets.push_back(sock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start the connect() for the next address in the list.
|
|
|
|
* @return True iff a new connect() is attempted.
|
|
|
|
*/
|
|
|
|
bool TCPConnecter::TryNextAddress()
|
|
|
|
{
|
|
|
|
if (this->current_address >= this->addresses.size()) return false;
|
|
|
|
|
|
|
|
this->last_attempt = std::chrono::steady_clock::now();
|
|
|
|
this->Connect(this->addresses[this->current_address++]);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-05-13 08:13:48 +02:00
|
|
|
/**
|
|
|
|
* Callback when resolving is done.
|
|
|
|
* @param ai A linked-list of address information.
|
|
|
|
*/
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
void TCPConnecter::OnResolved(addrinfo *ai)
|
|
|
|
{
|
|
|
|
std::deque<addrinfo *> addresses_ipv4, addresses_ipv6;
|
|
|
|
|
|
|
|
/* Apply "Happy Eyeballs" if it is likely IPv6 is functional. */
|
|
|
|
|
|
|
|
/* Detect if IPv6 is likely to succeed or not. */
|
|
|
|
bool seen_ipv6 = false;
|
|
|
|
bool resort = true;
|
|
|
|
for (addrinfo *runp = ai; runp != nullptr; runp = runp->ai_next) {
|
|
|
|
if (runp->ai_family == AF_INET6) {
|
|
|
|
seen_ipv6 = true;
|
|
|
|
} else if (!seen_ipv6) {
|
|
|
|
/* We see an IPv4 before an IPv6; this most likely means there is
|
|
|
|
* no IPv6 available on the system, so keep the order of this
|
|
|
|
* list. */
|
|
|
|
resort = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the addrinfo into NetworkAddresses. */
|
|
|
|
for (addrinfo *runp = ai; runp != nullptr; runp = runp->ai_next) {
|
|
|
|
if (resort) {
|
|
|
|
if (runp->ai_family == AF_INET6) {
|
|
|
|
addresses_ipv6.emplace_back(runp);
|
|
|
|
} else {
|
|
|
|
addresses_ipv4.emplace_back(runp);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this->addresses.emplace_back(runp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we want to resort, make the list like IPv6 / IPv4 / IPv6 / IPv4 / ..
|
|
|
|
* for how ever many (round-robin) DNS entries we have. */
|
|
|
|
if (resort) {
|
|
|
|
while (!addresses_ipv4.empty() || !addresses_ipv6.empty()) {
|
|
|
|
if (!addresses_ipv6.empty()) {
|
|
|
|
this->addresses.push_back(addresses_ipv6.front());
|
|
|
|
addresses_ipv6.pop_front();
|
|
|
|
}
|
|
|
|
if (!addresses_ipv4.empty()) {
|
|
|
|
this->addresses.push_back(addresses_ipv4.front());
|
|
|
|
addresses_ipv4.pop_front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-12 16:34:02 +02:00
|
|
|
if (_debug_net_level >= 6) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 6, "{} resolved in:", this->connection_string);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
for (const auto &address : this->addresses) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 6, "- {}", NetworkAddress(address->ai_addr, (int)address->ai_addrlen).GetAddressAsString());
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this->current_address = 0;
|
|
|
|
}
|
|
|
|
|
2021-05-13 08:13:48 +02:00
|
|
|
/**
|
|
|
|
* Start resolving the hostname.
|
|
|
|
*
|
|
|
|
* This function must change "status" to either Status::FAILURE
|
|
|
|
* or Status::CONNECTING before returning.
|
|
|
|
*/
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
void TCPConnecter::Resolve()
|
|
|
|
{
|
|
|
|
/* Port is already guaranteed part of the connection_string. */
|
|
|
|
NetworkAddress address = ParseConnectionString(this->connection_string, 0);
|
|
|
|
|
|
|
|
addrinfo hints;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
hints.ai_flags = AI_ADDRCONFIG;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
|
|
|
char port_name[6];
|
|
|
|
seprintf(port_name, lastof(port_name), "%u", address.GetPort());
|
|
|
|
|
|
|
|
static bool getaddrinfo_timeout_error_shown = false;
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
addrinfo *ai;
|
2021-06-13 21:05:15 +02:00
|
|
|
int error = getaddrinfo(address.GetHostname().c_str(), port_name, &hints, &ai);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
|
|
|
auto end = std::chrono::steady_clock::now();
|
|
|
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
|
|
|
|
if (!getaddrinfo_timeout_error_shown && duration >= std::chrono::seconds(5)) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 0, "getaddrinfo() for address \"{}\" took {} seconds", this->connection_string, duration.count());
|
|
|
|
Debug(net, 0, " This is likely an issue in the DNS name resolver's configuration causing it to time out");
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
getaddrinfo_timeout_error_shown = true;
|
2009-01-20 12:28:18 +01:00
|
|
|
}
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
2021-05-13 08:13:48 +02:00
|
|
|
if (error != 0) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 0, "Failed to resolve DNS for {}", this->connection_string);
|
2021-05-13 08:13:48 +02:00
|
|
|
this->status = Status::FAILURE;
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->ai = ai;
|
|
|
|
this->OnResolved(ai);
|
2021-05-08 14:45:23 +02:00
|
|
|
|
2021-05-13 08:13:48 +02:00
|
|
|
this->status = Status::CONNECTING;
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
}
|
|
|
|
|
2021-05-13 08:13:48 +02:00
|
|
|
/**
|
|
|
|
* Thunk to start Resolve() on the right instance.
|
|
|
|
*/
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
/* static */ void TCPConnecter::ResolveThunk(TCPConnecter *connecter)
|
|
|
|
{
|
|
|
|
connecter->Resolve();
|
2009-01-20 12:28:18 +01:00
|
|
|
}
|
|
|
|
|
2011-01-22 10:53:15 +01:00
|
|
|
/**
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
* Check if there was activity for this connecter.
|
|
|
|
* @return True iff the TCPConnecter is done and can be cleaned up.
|
2011-01-22 10:53:15 +01:00
|
|
|
*/
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
bool TCPConnecter::CheckActivity()
|
2009-01-20 12:28:18 +01:00
|
|
|
{
|
2021-05-13 08:13:48 +02:00
|
|
|
switch (this->status.load()) {
|
|
|
|
case Status::INIT:
|
|
|
|
/* Start the thread delayed, so the vtable is loaded. This allows classes
|
|
|
|
* to overload functions used by Resolve() (in case threading is disabled). */
|
|
|
|
if (StartNewThread(&this->resolve_thread, "ottd:resolve", &TCPConnecter::ResolveThunk, this)) {
|
|
|
|
this->status = Status::RESOLVING;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No threads, do a blocking resolve. */
|
|
|
|
this->Resolve();
|
|
|
|
|
|
|
|
/* Continue as we are either failed or can start the first
|
|
|
|
* connection. The rest of this function handles exactly that. */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Status::RESOLVING:
|
|
|
|
/* Wait till Resolve() comes back with an answer (in case it runs threaded). */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case Status::FAILURE:
|
|
|
|
/* Ensure the OnFailure() is called from the game-thread instead of the
|
|
|
|
* resolve-thread, as otherwise we can get into some threading issues. */
|
|
|
|
this->OnFailure();
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case Status::CONNECTING:
|
|
|
|
break;
|
|
|
|
}
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
|
|
|
/* If there are no attempts pending, connect to the next. */
|
|
|
|
if (this->sockets.empty()) {
|
|
|
|
if (!this->TryNextAddress()) {
|
|
|
|
/* There were no more addresses to try, so we failed. */
|
|
|
|
this->OnFailure();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd_set write_fd;
|
|
|
|
FD_ZERO(&write_fd);
|
|
|
|
for (const auto &socket : this->sockets) {
|
|
|
|
FD_SET(socket, &write_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
timeval tv;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
tv.tv_sec = 0;
|
2021-06-16 21:12:08 +02:00
|
|
|
int n = select(FD_SETSIZE, nullptr, &write_fd, nullptr, &tv);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
/* select() failed; hopefully next try it doesn't. */
|
|
|
|
if (n < 0) {
|
|
|
|
/* select() normally never fails; so hopefully it works next try! */
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 1, "select() failed: {}", NetworkError::GetLast().AsString());
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No socket updates. */
|
|
|
|
if (n == 0) {
|
|
|
|
/* Wait 250ms between attempting another address. */
|
|
|
|
if (std::chrono::steady_clock::now() < this->last_attempt + std::chrono::milliseconds(250)) return false;
|
|
|
|
|
|
|
|
/* Try the next address in the list. */
|
|
|
|
if (this->TryNextAddress()) return false;
|
|
|
|
|
|
|
|
/* Wait up to 3 seconds since the last connection we started. */
|
|
|
|
if (std::chrono::steady_clock::now() < this->last_attempt + std::chrono::milliseconds(3000)) return false;
|
|
|
|
|
|
|
|
/* More than 3 seconds no socket reported activity, and there are no
|
|
|
|
* more address to try. Timeout the attempt. */
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 0, "Timeout while connecting to {}", this->connection_string);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
|
|
|
for (const auto &socket : this->sockets) {
|
|
|
|
closesocket(socket);
|
|
|
|
}
|
2021-05-08 11:57:41 +02:00
|
|
|
this->sockets.clear();
|
|
|
|
this->sock_to_address.clear();
|
|
|
|
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
this->OnFailure();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for errors on any of the sockets. */
|
|
|
|
for (auto it = this->sockets.begin(); it != this->sockets.end(); /* nothing */) {
|
|
|
|
NetworkError socket_error = GetSocketError(*it);
|
|
|
|
if (socket_error.HasError()) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 1, "Could not connect to {}: {}", this->sock_to_address[*it].GetAddressAsString(), socket_error.AsString());
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
closesocket(*it);
|
2021-05-08 11:57:41 +02:00
|
|
|
this->sock_to_address.erase(*it);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
it = this->sockets.erase(it);
|
|
|
|
} else {
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In case all sockets had an error, queue a new one. */
|
|
|
|
if (this->sockets.empty()) {
|
|
|
|
if (!this->TryNextAddress()) {
|
|
|
|
/* There were no more addresses to try, so we failed. */
|
|
|
|
this->OnFailure();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* At least one socket is connected. The first one that does is the one
|
|
|
|
* we will be using, and we close all other sockets. */
|
|
|
|
SOCKET connected_socket = INVALID_SOCKET;
|
|
|
|
for (auto it = this->sockets.begin(); it != this->sockets.end(); /* nothing */) {
|
|
|
|
if (connected_socket == INVALID_SOCKET && FD_ISSET(*it, &write_fd)) {
|
|
|
|
connected_socket = *it;
|
|
|
|
} else {
|
|
|
|
closesocket(*it);
|
|
|
|
}
|
2021-05-08 11:57:41 +02:00
|
|
|
this->sock_to_address.erase(*it);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
it = this->sockets.erase(it);
|
|
|
|
}
|
|
|
|
assert(connected_socket != INVALID_SOCKET);
|
|
|
|
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 3, "Connected to {}", this->connection_string);
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
if (_debug_net_level >= 5) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(net, 5, "- using {}", NetworkAddress::GetPeerName(connected_socket));
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this->OnConnect(connected_socket);
|
|
|
|
return true;
|
2009-01-20 12:28:18 +01:00
|
|
|
}
|
|
|
|
|
2011-01-22 10:53:15 +01:00
|
|
|
/**
|
|
|
|
* Check whether we need to call the callback, i.e. whether we
|
|
|
|
* have connected or aborted and call the appropriate callback
|
|
|
|
* for that. It's done this way to ease on the locking that
|
|
|
|
* would otherwise be needed everywhere.
|
|
|
|
*/
|
2009-01-20 12:28:18 +01:00
|
|
|
/* static */ void TCPConnecter::CheckCallbacks()
|
|
|
|
{
|
2018-09-25 23:01:05 +02:00
|
|
|
for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) {
|
2009-01-20 12:28:18 +01:00
|
|
|
TCPConnecter *cur = *iter;
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
|
|
|
|
if (cur->CheckActivity()) {
|
2018-09-25 23:01:05 +02:00
|
|
|
iter = _tcp_connecters.erase(iter);
|
2009-01-20 12:28:18 +01:00
|
|
|
delete cur;
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
} else {
|
|
|
|
iter++;
|
2009-01-20 12:28:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-22 10:53:15 +01:00
|
|
|
/** Kill all connection attempts. */
|
2009-01-20 12:28:18 +01:00
|
|
|
/* static */ void TCPConnecter::KillAll()
|
|
|
|
{
|
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.
2021-05-06 23:13:35 +02:00
|
|
|
for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) {
|
|
|
|
TCPConnecter *cur = *iter;
|
|
|
|
iter = _tcp_connecters.erase(iter);
|
|
|
|
delete cur;
|
|
|
|
}
|
2009-01-20 12:28:18 +01:00
|
|
|
}
|