Feat: Support multiple server IP addresses (#3665)
This commit is contained in:
parent
e5e53c02b5
commit
50e7b3aadf
4 changed files with 87 additions and 25 deletions
|
|
@ -79,6 +79,11 @@ Client::~Client()
|
||||||
delete m_socketFactory;
|
delete m_socketFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::setServerAddress(const NetworkAddress &address)
|
||||||
|
{
|
||||||
|
m_serverAddress = address;
|
||||||
|
}
|
||||||
|
|
||||||
void Client::connect(size_t addressIndex)
|
void Client::connect(size_t addressIndex)
|
||||||
{
|
{
|
||||||
if (m_stream != nullptr) {
|
if (m_stream != nullptr) {
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ public:
|
||||||
the client is trying to connect or is already connected.
|
the client is trying to connect or is already connected.
|
||||||
*/
|
*/
|
||||||
void connect(size_t addressIndex = 0);
|
void connect(size_t addressIndex = 0);
|
||||||
|
void setServerAddress(const NetworkAddress &address);
|
||||||
|
|
||||||
//! Disconnect
|
//! Disconnect
|
||||||
/*!
|
/*!
|
||||||
|
|
|
||||||
|
|
@ -54,21 +54,44 @@ ClientApp::ClientApp(IEventQueue *events, const QString &processName) : App(even
|
||||||
|
|
||||||
void ClientApp::parseArgs()
|
void ClientApp::parseArgs()
|
||||||
{
|
{
|
||||||
// save server address
|
// save server addresses (comma-separated list supported)
|
||||||
if (const auto address = Settings::value(Settings::Client::RemoteHost).toString(); !address.isEmpty()) {
|
if (const auto addressList = Settings::value(Settings::Client::RemoteHost).toString(); !addressList.isEmpty()) {
|
||||||
try {
|
const int port = Settings::value(Settings::Core::Port).toInt();
|
||||||
*m_serverAddress = NetworkAddress(address.toStdString(), Settings::value(Settings::Core::Port).toInt());
|
const QStringList addresses = addressList.split(',', Qt::SkipEmptyParts);
|
||||||
m_serverAddress->resolve();
|
|
||||||
} catch (SocketAddressException &e) {
|
for (const QString &addr : addresses) {
|
||||||
// allow an address that we can't look up if we're restartable.
|
const QString trimmedAddr = addr.trimmed();
|
||||||
// we'll try to resolve the address each time we connect to the
|
if (trimmedAddr.isEmpty()) {
|
||||||
// server. a bad port will never get better. patch by Brent
|
continue;
|
||||||
// Priddy.
|
}
|
||||||
if (e.getError() == SocketAddressException::SocketError::BadPort) {
|
|
||||||
LOG_CRIT("%s: %s" BYE, qPrintable(processName()), e.what(), qPrintable(processName()));
|
try {
|
||||||
bye(s_exitFailed);
|
NetworkAddress netAddr(trimmedAddr.toStdString(), port);
|
||||||
|
netAddr.resolve();
|
||||||
|
m_serverAddresses.push_back(std::move(netAddr));
|
||||||
|
LOG_DEBUG("added server address: %s", qPrintable(trimmedAddr));
|
||||||
|
} catch (SocketAddressException &e) {
|
||||||
|
// allow an address that we can't look up if we're restartable.
|
||||||
|
// we'll try to resolve the address each time we connect to the
|
||||||
|
// server. a bad port will never get better.
|
||||||
|
if (e.getError() == SocketAddressException::SocketError::BadPort) {
|
||||||
|
LOG_CRIT("%s: %s" BYE, qPrintable(processName()), e.what(), qPrintable(processName()));
|
||||||
|
bye(s_exitFailed);
|
||||||
|
} else {
|
||||||
|
// Still add it - we'll try to resolve later
|
||||||
|
NetworkAddress netAddr(trimmedAddr.toStdString(), port);
|
||||||
|
m_serverAddresses.push_back(std::move(netAddr));
|
||||||
|
LOG_WARN("could not resolve address '%s': %s (will retry later)", qPrintable(trimmedAddr), e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_serverAddresses.isEmpty()) {
|
||||||
|
LOG_CRIT("%s: no valid server addresses specified" BYE, qPrintable(processName()), qPrintable(processName()));
|
||||||
|
bye(s_exitFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_NOTE("configured %zu server address(es)", static_cast<size_t>(m_serverAddresses.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,23 +181,39 @@ void ClientApp::scheduleClientRestart(double retryTime)
|
||||||
getEvents()->addHandler(EventTypes::Timer, timer, [this, timer](const auto &e) { handleClientRestart(e, timer); });
|
getEvents()->addHandler(EventTypes::Timer, timer, [this, timer](const auto &e) { handleClientRestart(e, timer); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientApp::handleClientConnected() const
|
void ClientApp::handleClientConnected()
|
||||||
{
|
{
|
||||||
LOG_IPC("connected to server");
|
LOG_IPC("connected to server");
|
||||||
|
// Reset server index on successful connection
|
||||||
|
m_currentServerIndex = 0;
|
||||||
|
m_lastServerAddressIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientApp::handleClientFailed(const Event &e)
|
void ClientApp::handleClientFailed(const Event &e)
|
||||||
{
|
{
|
||||||
if ((++m_lastServerAddressIndex) < m_client->getLastResolvedAddressesCount()) {
|
if ((++m_lastServerAddressIndex) < m_client->getLastResolvedAddressesCount()) {
|
||||||
|
// Try next resolved address for current hostname
|
||||||
std::unique_ptr<Client::FailInfo> info(static_cast<Client::FailInfo *>(e.getData()));
|
std::unique_ptr<Client::FailInfo> info(static_cast<Client::FailInfo *>(e.getData()));
|
||||||
|
|
||||||
LOG_WARN("failed to connect to server=%s, trying next address", info->m_what.c_str());
|
LOG_WARN("failed to connect to server=%s, trying next resolved address", info->m_what.c_str());
|
||||||
if (!m_suspended) {
|
if (!m_suspended) {
|
||||||
scheduleClientRestart(s_retryTime);
|
scheduleClientRestart(s_retryTime);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// All resolved addresses exhausted, try next server in list
|
||||||
m_lastServerAddressIndex = 0;
|
m_lastServerAddressIndex = 0;
|
||||||
handleClientRefused(e);
|
tryNextServer();
|
||||||
|
|
||||||
|
if (m_currentServerIndex == 0) {
|
||||||
|
// We've cycled through all servers, treat as refused
|
||||||
|
handleClientRefused(e);
|
||||||
|
} else {
|
||||||
|
std::unique_ptr<Client::FailInfo> info(static_cast<Client::FailInfo *>(e.getData()));
|
||||||
|
LOG_WARN("failed to connect to server=%s, trying next server in list", info->m_what.c_str());
|
||||||
|
if (!m_suspended) {
|
||||||
|
scheduleClientRestart(s_retryTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,12 +287,13 @@ bool ClientApp::startClient()
|
||||||
if (m_clientScreen == nullptr) {
|
if (m_clientScreen == nullptr) {
|
||||||
clientScreen = openClientScreen();
|
clientScreen = openClientScreen();
|
||||||
m_client = openClient(
|
m_client = openClient(
|
||||||
Settings::value(Settings::Core::ScreenName).toString().toStdString(), *m_serverAddress, clientScreen
|
Settings::value(Settings::Core::ScreenName).toString().toStdString(), getCurrentServerAddress(), clientScreen
|
||||||
);
|
);
|
||||||
m_clientScreen = clientScreen;
|
m_clientScreen = clientScreen;
|
||||||
LOG_NOTE("started client");
|
LOG_NOTE("started client");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_client->setServerAddress(getCurrentServerAddress());
|
||||||
m_client->connect(m_lastServerAddressIndex);
|
m_client->connect(m_lastServerAddressIndex);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -325,22 +365,33 @@ int ClientApp::start()
|
||||||
|
|
||||||
int ClientApp::runInner(StartupFunc startup)
|
int ClientApp::runInner(StartupFunc startup)
|
||||||
{
|
{
|
||||||
// general initialization
|
|
||||||
m_serverAddress = new NetworkAddress;
|
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
try {
|
try {
|
||||||
// run
|
// run
|
||||||
result = startup();
|
result = startup();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
delete m_serverAddress;
|
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkAddress &ClientApp::getCurrentServerAddress()
|
||||||
|
{
|
||||||
|
if (m_serverAddresses.isEmpty()) {
|
||||||
|
throw std::runtime_error("No server addresses configured");
|
||||||
|
}
|
||||||
|
return m_serverAddresses[m_currentServerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientApp::tryNextServer()
|
||||||
|
{
|
||||||
|
if (m_serverAddresses.size() > 1) {
|
||||||
|
m_currentServerIndex = (m_currentServerIndex + 1) % m_serverAddresses.size();
|
||||||
|
LOG_DEBUG("switching to server %zu of %zu", m_currentServerIndex + 1, m_serverAddresses.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClientApp::startNode()
|
void ClientApp::startNode()
|
||||||
{
|
{
|
||||||
// start the client. if this return false then we've failed and
|
// start the client. if this return false then we've failed and
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "deskflow/App.h"
|
#include "deskflow/App.h"
|
||||||
|
#include "net/NetworkAddress.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
namespace deskflow {
|
namespace deskflow {
|
||||||
class Screen;
|
class Screen;
|
||||||
|
|
@ -17,7 +20,6 @@ class ClientArgs;
|
||||||
|
|
||||||
class Event;
|
class Event;
|
||||||
class Client;
|
class Client;
|
||||||
class NetworkAddress;
|
|
||||||
class Thread;
|
class Thread;
|
||||||
class ISocketFactory;
|
class ISocketFactory;
|
||||||
|
|
||||||
|
|
@ -54,7 +56,7 @@ public:
|
||||||
void closeClientScreen(deskflow::Screen *screen);
|
void closeClientScreen(deskflow::Screen *screen);
|
||||||
void handleClientRestart(const Event &, EventQueueTimer *vtimer);
|
void handleClientRestart(const Event &, EventQueueTimer *vtimer);
|
||||||
void scheduleClientRestart(double retryTime);
|
void scheduleClientRestart(double retryTime);
|
||||||
void handleClientConnected() const;
|
void handleClientConnected();
|
||||||
void handleClientFailed(const Event &e);
|
void handleClientFailed(const Event &e);
|
||||||
void handleClientRefused(const Event &e);
|
void handleClientRefused(const Event &e);
|
||||||
void handleClientDisconnected();
|
void handleClientDisconnected();
|
||||||
|
|
@ -78,10 +80,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISocketFactory *getSocketFactory() const;
|
ISocketFactory *getSocketFactory() const;
|
||||||
|
NetworkAddress &getCurrentServerAddress();
|
||||||
|
void tryNextServer();
|
||||||
|
|
||||||
bool m_suspended = false;
|
bool m_suspended = false;
|
||||||
Client *m_client = nullptr;
|
Client *m_client = nullptr;
|
||||||
deskflow::Screen *m_clientScreen = nullptr;
|
deskflow::Screen *m_clientScreen = nullptr;
|
||||||
NetworkAddress *m_serverAddress = nullptr;
|
QList<NetworkAddress> m_serverAddresses;
|
||||||
|
size_t m_currentServerIndex = 0;
|
||||||
size_t m_lastServerAddressIndex = 0;
|
size_t m_lastServerAddressIndex = 0;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue