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 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 font change not resulting in forced layout update. (#6536)
|
||||||
- Bugfix: Fixed scrollbar rect computation potentially resulting in overflows. (#6547)
|
- 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: Forward query params to websocket URLs. (#6141)
|
||||||
- Bugfix: Fixed Lua errors from handlers of HTTP requests not being logged. (#6452)
|
- Bugfix: Fixed Lua errors from handlers of HTTP requests not being logged. (#6452)
|
||||||
- Bugfix: Fixed restore button not showing on Windows. (#6565)
|
- Bugfix: Fixed restore button not showing on Windows. (#6565)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include <boost/beast/core/bind_handler.hpp>
|
#include <boost/beast/core/bind_handler.hpp>
|
||||||
#include <boost/beast/websocket/ssl.hpp>
|
#include <boost/beast/websocket/ssl.hpp>
|
||||||
|
|
||||||
|
using namespace std::literals::string_view_literals;
|
||||||
|
|
||||||
namespace chatterino::ws::detail {
|
namespace chatterino::ws::detail {
|
||||||
|
|
||||||
namespace asio = boost::asio;
|
namespace asio = boost::asio;
|
||||||
@@ -93,30 +95,61 @@ void WebSocketConnectionHelper<Derived, Inner>::onResolve(
|
|||||||
return;
|
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)
|
beast::get_lowest_layer(this->stream)
|
||||||
.expires_after(std::chrono::seconds{30});
|
.expires_after(std::chrono::seconds{30});
|
||||||
|
|
||||||
beast::get_lowest_layer(this->stream)
|
beast::get_lowest_layer(this->stream)
|
||||||
.async_connect(results, beast::bind_front_handler(
|
.async_connect(endpoint,
|
||||||
&WebSocketConnectionHelper::onTcpHandshake,
|
beast::bind_front_handler(
|
||||||
this->shared_from_this()));
|
&WebSocketConnectionHelper::onTcpHandshake,
|
||||||
|
this->shared_from_this(), endpointIterator));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Derived, typename Inner>
|
template <typename Derived, typename Inner>
|
||||||
void WebSocketConnectionHelper<Derived, Inner>::onTcpHandshake(
|
void WebSocketConnectionHelper<Derived, Inner>::onTcpHandshake(
|
||||||
boost::system::error_code ec,
|
boost::asio::ip::tcp::resolver::results_type::const_iterator
|
||||||
const asio::ip::tcp::resolver::endpoint_type &ep)
|
endpointIterator,
|
||||||
|
boost::system::error_code ec)
|
||||||
{
|
{
|
||||||
|
const auto &ep = endpointIterator->endpoint();
|
||||||
|
|
||||||
if (ec)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(chatterinoWebsocket) << *this << "TCP handshake done";
|
qCDebug(chatterinoWebsocket)
|
||||||
|
<< *this << "TCP handshake done" << ep.address().to_string();
|
||||||
this->options.url.setPort(ep.port());
|
this->options.url.setPort(ep.port());
|
||||||
|
|
||||||
|
// We are done with the endpoints, we can clear the range.
|
||||||
|
this->resolvedEndpoints = {};
|
||||||
|
|
||||||
this->derived()->afterTcpHandshake();
|
this->derived()->afterTcpHandshake();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,9 +352,16 @@ void WebSocketConnectionHelper<Derived, Inner>::closeImpl()
|
|||||||
template <typename Derived, typename Inner>
|
template <typename Derived, typename Inner>
|
||||||
void WebSocketConnectionHelper<Derived, Inner>::fail(
|
void WebSocketConnectionHelper<Derived, Inner>::fail(
|
||||||
boost::system::error_code ec, QStringView op)
|
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)
|
qCWarning(chatterinoWebsocket)
|
||||||
<< *this << "Failed:" << op << QUtf8StringView(ec.message());
|
<< *this << "Failed:" << op << QUtf8StringView(ec);
|
||||||
if (this->stream.is_open())
|
if (this->stream.is_open())
|
||||||
{
|
{
|
||||||
this->closeImpl();
|
this->closeImpl();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ protected:
|
|||||||
Derived *derived();
|
Derived *derived();
|
||||||
|
|
||||||
void fail(boost::system::error_code ec, QStringView op);
|
void fail(boost::system::error_code ec, QStringView op);
|
||||||
|
void fail(std::string_view ec, QStringView op);
|
||||||
void doWsHandshake();
|
void doWsHandshake();
|
||||||
|
|
||||||
void closeImpl();
|
void closeImpl();
|
||||||
@@ -57,15 +58,31 @@ private:
|
|||||||
|
|
||||||
void onResolve(boost::system::error_code ec,
|
void onResolve(boost::system::error_code ec,
|
||||||
const boost::asio::ip::tcp::resolver::results_type &results);
|
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(
|
void onTcpHandshake(
|
||||||
boost::system::error_code ec,
|
boost::asio::ip::tcp::resolver::results_type::const_iterator
|
||||||
const boost::asio::ip::tcp::resolver::endpoint_type &ep);
|
endpointIterator,
|
||||||
|
boost::system::error_code ec);
|
||||||
void onWsHandshake(boost::system::error_code ec);
|
void onWsHandshake(boost::system::error_code ec);
|
||||||
|
|
||||||
void onReadDone(boost::system::error_code ec, size_t bytesRead);
|
void onReadDone(boost::system::error_code ec, size_t bytesRead);
|
||||||
void onWriteDone(boost::system::error_code ec, size_t bytesWritten);
|
void onWriteDone(boost::system::error_code ec, size_t bytesWritten);
|
||||||
|
|
||||||
friend Derived;
|
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://).
|
/// A WebSocket connection over TLS (wss://).
|
||||||
|
|||||||
Reference in New Issue
Block a user