fix(websocket): try connecting to all hosts (#6631)
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
- Bugfix: Fixed settings occasionally not opening when clicking on "Manage Accounts" in the account switcher. (#6543)
|
||||
- Bugfix: Fixed font change not resulting in forced layout update. (#6536)
|
||||
- Bugfix: Fixed scrollbar rect computation potentially resulting in overflows. (#6547)
|
||||
- Bugfix: Fixed websocket connections failing if the DNS resolving gave bad hosts. (#6631)
|
||||
- Bugfix: Forward query params to websocket URLs. (#6141)
|
||||
- Bugfix: Fixed Lua errors from handlers of HTTP requests not being logged. (#6452)
|
||||
- Bugfix: Fixed restore button not showing on Windows. (#6565)
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <boost/beast/core/bind_handler.hpp>
|
||||
#include <boost/beast/websocket/ssl.hpp>
|
||||
|
||||
using namespace std::literals::string_view_literals;
|
||||
|
||||
namespace chatterino::ws::detail {
|
||||
|
||||
namespace asio = boost::asio;
|
||||
@@ -93,30 +95,61 @@ void WebSocketConnectionHelper<Derived, Inner>::onResolve(
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(chatterinoWebsocket) << *this << "Resolved host";
|
||||
this->resolvedEndpoints = results;
|
||||
|
||||
this->tryConnect(this->resolvedEndpoints.begin());
|
||||
}
|
||||
|
||||
template <typename Derived, typename Inner>
|
||||
void WebSocketConnectionHelper<Derived, Inner>::tryConnect(
|
||||
boost::asio::ip::tcp::resolver::results_type::const_iterator
|
||||
endpointIterator)
|
||||
{
|
||||
if (endpointIterator == this->resolvedEndpoints.end())
|
||||
{
|
||||
this->fail("Ran out of resolved endpoints"sv, u"connect");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &endpoint = endpointIterator->endpoint();
|
||||
|
||||
qCDebug(chatterinoWebsocket)
|
||||
<< *this << "connect to" << endpoint.address().to_string();
|
||||
|
||||
beast::get_lowest_layer(this->stream)
|
||||
.expires_after(std::chrono::seconds{30});
|
||||
|
||||
beast::get_lowest_layer(this->stream)
|
||||
.async_connect(results, beast::bind_front_handler(
|
||||
&WebSocketConnectionHelper::onTcpHandshake,
|
||||
this->shared_from_this()));
|
||||
.async_connect(endpoint,
|
||||
beast::bind_front_handler(
|
||||
&WebSocketConnectionHelper::onTcpHandshake,
|
||||
this->shared_from_this(), endpointIterator));
|
||||
}
|
||||
|
||||
template <typename Derived, typename Inner>
|
||||
void WebSocketConnectionHelper<Derived, Inner>::onTcpHandshake(
|
||||
boost::system::error_code ec,
|
||||
const asio::ip::tcp::resolver::endpoint_type &ep)
|
||||
boost::asio::ip::tcp::resolver::results_type::const_iterator
|
||||
endpointIterator,
|
||||
boost::system::error_code ec)
|
||||
{
|
||||
const auto &ep = endpointIterator->endpoint();
|
||||
|
||||
if (ec)
|
||||
{
|
||||
this->fail(ec, u"TCP handshake");
|
||||
qCDebug(chatterinoWebsocket)
|
||||
<< *this << "error in tcp handshake" << ep.address().to_string()
|
||||
<< ec.message();
|
||||
this->tryConnect(++endpointIterator);
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(chatterinoWebsocket) << *this << "TCP handshake done";
|
||||
qCDebug(chatterinoWebsocket)
|
||||
<< *this << "TCP handshake done" << ep.address().to_string();
|
||||
this->options.url.setPort(ep.port());
|
||||
|
||||
// We are done with the endpoints, we can clear the range.
|
||||
this->resolvedEndpoints = {};
|
||||
|
||||
this->derived()->afterTcpHandshake();
|
||||
}
|
||||
|
||||
@@ -319,9 +352,16 @@ void WebSocketConnectionHelper<Derived, Inner>::closeImpl()
|
||||
template <typename Derived, typename Inner>
|
||||
void WebSocketConnectionHelper<Derived, Inner>::fail(
|
||||
boost::system::error_code ec, QStringView op)
|
||||
{
|
||||
this->fail(ec.message(), op);
|
||||
}
|
||||
|
||||
template <typename Derived, typename Inner>
|
||||
void WebSocketConnectionHelper<Derived, Inner>::fail(std::string_view ec,
|
||||
QStringView op)
|
||||
{
|
||||
qCWarning(chatterinoWebsocket)
|
||||
<< *this << "Failed:" << op << QUtf8StringView(ec.message());
|
||||
<< *this << "Failed:" << op << QUtf8StringView(ec);
|
||||
if (this->stream.is_open())
|
||||
{
|
||||
this->closeImpl();
|
||||
|
||||
@@ -41,6 +41,7 @@ protected:
|
||||
Derived *derived();
|
||||
|
||||
void fail(boost::system::error_code ec, QStringView op);
|
||||
void fail(std::string_view ec, QStringView op);
|
||||
void doWsHandshake();
|
||||
|
||||
void closeImpl();
|
||||
@@ -57,15 +58,31 @@ private:
|
||||
|
||||
void onResolve(boost::system::error_code ec,
|
||||
const boost::asio::ip::tcp::resolver::results_type &results);
|
||||
|
||||
/// Initialize a TCP connection to the given endpoint iterator in `resolvedEndpoints`.
|
||||
///
|
||||
/// If we failed to connect, try the next iterator.
|
||||
///
|
||||
/// If the iterator is invalid, we have run out of endpoints to try, and deem this
|
||||
/// connection a failure.
|
||||
void tryConnect(boost::asio::ip::tcp::resolver::results_type::const_iterator
|
||||
endpointIterator);
|
||||
void onTcpHandshake(
|
||||
boost::system::error_code ec,
|
||||
const boost::asio::ip::tcp::resolver::endpoint_type &ep);
|
||||
boost::asio::ip::tcp::resolver::results_type::const_iterator
|
||||
endpointIterator,
|
||||
boost::system::error_code ec);
|
||||
void onWsHandshake(boost::system::error_code ec);
|
||||
|
||||
void onReadDone(boost::system::error_code ec, size_t bytesRead);
|
||||
void onWriteDone(boost::system::error_code ec, size_t bytesWritten);
|
||||
|
||||
friend Derived;
|
||||
|
||||
/// A range of endpoints from the `onResolve` function.
|
||||
///
|
||||
/// When we successfully resolve the host, we try to connect by
|
||||
/// iterating over these results.
|
||||
boost::asio::ip::tcp::resolver::results_type resolvedEndpoints;
|
||||
};
|
||||
|
||||
/// A WebSocket connection over TLS (wss://).
|
||||
|
||||
Reference in New Issue
Block a user