#include "proxyconnection.h" #include "proxyjsonrpcclient.h" #include "websocketconnection.h" #include "remoteproxyconnection.h" Q_LOGGING_CATEGORY(dcRemoteProxyClientConnection, "RemoteProxyClientConnection") Q_LOGGING_CATEGORY(dcRemoteProxyClientConnectionTraffic, "RemoteProxyClientConnectionTraffic") namespace remoteproxyclient { RemoteProxyConnection::RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, QObject *parent) : QObject(parent), m_clientUuid(clientUuid), m_clientName(clientName) { } RemoteProxyConnection::~RemoteProxyConnection() { } RemoteProxyConnection::State RemoteProxyConnection::state() const { return m_state; } RemoteProxyConnection::Error RemoteProxyConnection::error() const { return m_error; } QString RemoteProxyConnection::errorString() const { QString errorString; switch (m_error) { case ErrorNoError: errorString = ""; break; case ErrorSocketError: errorString = "Socket connection error occured."; break; case ErrorSslError: errorString = "SSL error occured."; break; case ErrorProxyNotResponding: errorString = "The proxy server does not respond."; break; case ErrorProxyAuthenticationFailed: errorString = "The authentication on the proxy server failed."; break; } return errorString; } bool RemoteProxyConnection::isConnected() const { return m_state == StateConnected || m_state == StateInitializing || m_state == StateReady || m_state == StateAuthenticating || m_state == StateWaitTunnel || m_state == StateRemoteConnected; } bool RemoteProxyConnection::isAuthenticated() const { return m_state == StateWaitTunnel || m_state == StateRemoteConnected; } bool RemoteProxyConnection::isRemoteConnected() const { return m_state == StateRemoteConnected; } RemoteProxyConnection::ConnectionType RemoteProxyConnection::connectionType() const { return m_connectionType; } void RemoteProxyConnection::setConnectionType(RemoteProxyConnection::ConnectionType connectionType) { m_connectionType = connectionType; } QHostAddress RemoteProxyConnection::serverAddress() const { return m_serverAddress; } quint16 RemoteProxyConnection::serverPort() const { return m_serverPort; } QString RemoteProxyConnection::serverName() const { return m_serverName; } QString RemoteProxyConnection::proxyServerName() const { return m_proxyServerName; } QString RemoteProxyConnection::proxyServerVersion() const { return m_proxyServerVersion; } QString RemoteProxyConnection::proxyServerApiVersion() const { return m_proxyServerApiVersion; } bool RemoteProxyConnection::insecureConnection() const { return m_insecureConnection; } void RemoteProxyConnection::setInsecureConnection(bool insecureConnection) { m_insecureConnection = insecureConnection; } bool RemoteProxyConnection::sendData(const QByteArray &data) { if (!isConnected()) { qCWarning(dcRemoteProxyClientConnection()) << "Could not send data. Not connected."; return false; } if (!isRemoteConnected()) { qCWarning(dcRemoteProxyClientConnection()) << "Could not send data. The remote client is not connected yet."; return false; } m_connection->sendData(data); return true; } void RemoteProxyConnection::cleanUp() { if (m_jsonClient) { m_jsonClient->deleteLater(); m_jsonClient = nullptr; } if (m_connection) { m_connection->deleteLater(); m_connection = nullptr; } m_serverName = QString(); m_proxyServerName = QString(); m_proxyServerVersion = QString(); m_proxyServerApiVersion = QString(); setState(StateDisconnected); } void RemoteProxyConnection::setState(RemoteProxyConnection::State state) { if (m_state == state) return; m_state = state; qCDebug(dcRemoteProxyClientConnection()) << "State changed" << m_state; emit stateChanged(m_state); } void RemoteProxyConnection::setError(RemoteProxyConnection::Error error) { if (m_error == error) return; m_error = error; qCDebug(dcRemoteProxyClientConnection()) << "Error occured" << m_error << errorString(); emit errorOccured(m_error); } void RemoteProxyConnection::onConnectionChanged(bool isConnected) { if (isConnected) { qCDebug(dcRemoteProxyClientConnection()) << "Connected from proxy server."; setState(StateConnected); emit connected(); setState(StateInitializing); JsonReply *reply = m_jsonClient->callHello(); connect(reply, &JsonReply::finished, this, &RemoteProxyConnection::onHelloFinished); } else { qCDebug(dcRemoteProxyClientConnection()) << "Disconnected from proxy server."; emit disconnected(); setState(StateDisconnected); cleanUp(); } } void RemoteProxyConnection::onConnectionDataAvailable(const QByteArray &data) { switch (m_state) { case StateConnecting: case StateConnected: case StateInitializing: case StateReady: case StateAuthenticating: case StateWaitTunnel: m_jsonClient->processData(data); break; case StateRemoteConnected: // Remote data arrived emit dataReady(data); break; default: qCWarning(dcRemoteProxyClientConnection()) << "Unhandled: Data reviced" << data; break; } } void RemoteProxyConnection::onConnectionSocketError() { setError(ErrorSocketError); } void RemoteProxyConnection::onConnectionSslError() { setError(ErrorSslError); } void RemoteProxyConnection::onHelloFinished() { JsonReply *reply = static_cast(sender()); reply->deleteLater(); QVariantMap response = reply->response(); qCDebug(dcRemoteProxyClientConnectionTraffic()) << "Hello response ready" << reply->commandId() << response; if (response.value("status").toString() != "success") { qCWarning(dcRemoteProxyClientConnection()) << "Could not get initial information from proxy server."; m_connection->disconnectServer(); return; } QVariantMap responseParams = response.value("params").toMap(); // TODO: verify success m_serverName = responseParams.value("server").toString(); m_proxyServerName = responseParams.value("name").toString(); m_proxyServerVersion = responseParams.value("version").toString(); m_proxyServerApiVersion = responseParams.value("apiVersion").toString(); setState(StateReady); emit ready(); } void RemoteProxyConnection::onAuthenticateFinished() { JsonReply *reply = static_cast(sender()); reply->deleteLater(); QVariantMap response = reply->response(); qCDebug(dcRemoteProxyClientConnectionTraffic()) << "Authentication response ready" << reply->commandId() << response; QVariantMap responseParams = response.value("params").toMap(); if (responseParams.value("authenticationError").toString() != "AuthenticationErrorNoError") { qCWarning(dcRemoteProxyClientConnection()) << "Authentication request finished with error" << responseParams.value("authenticationError").toString(); setError(RemoteProxyConnection::ErrorProxyAuthenticationFailed); m_connection->disconnectServer(); } else { qCDebug(dcRemoteProxyClientConnection()) << "Successfully authenticated."; setState(StateWaitTunnel); emit authenticated(); } } void RemoteProxyConnection::onTunnelEstablished(const QString &clientName, const QString &clientUuid) { qCDebug(dcRemoteProxyClientConnection()) << "####### Remote connection established with" << clientName << clientUuid; setState(StateRemoteConnected); emit remoteConnectionEstablished(); } bool RemoteProxyConnection::connectServer(const QHostAddress &serverAddress, quint16 port) { m_serverAddress = serverAddress; m_serverPort = port; m_error = ErrorNoError; cleanUp(); switch (m_connectionType) { case ConnectionTypeWebSocket: m_connection = qobject_cast(new WebSocketConnection(this)); } m_connection->setAllowSslErrors(m_insecureConnection); connect(m_connection, &ProxyConnection::connectedChanged, this, &RemoteProxyConnection::onConnectionChanged); connect(m_connection, &ProxyConnection::dataReceived, this, &RemoteProxyConnection::onConnectionDataAvailable); connect(m_connection, &ProxyConnection::errorOccured, this, &RemoteProxyConnection::onConnectionSocketError); connect(m_connection, &ProxyConnection::sslErrorOccured, this, &RemoteProxyConnection::onConnectionSslError); m_jsonClient = new JsonRpcClient(m_connection, this); connect(m_jsonClient, &JsonRpcClient::tunnelEstablished, this, &RemoteProxyConnection::onTunnelEstablished); qCDebug(dcRemoteProxyClientConnection()) << "Connecting to" << QString("%1:%2").arg(serverAddress.toString()).arg(port); m_connection->connectServer(serverAddress, port); setState(StateConnecting); return true; } bool RemoteProxyConnection::authenticate(const QString &token) { if (m_state != StateReady) { qCWarning(dcRemoteProxyClientConnection()) << "Could not authenticate. The connection is not ready"; return false; } setState(StateAuthenticating); qCDebug(dcRemoteProxyClientConnection()) << "Start authentication using token" << token; JsonReply *reply = m_jsonClient->callAuthenticate(m_clientUuid, m_clientName, token); connect(reply, &JsonReply::finished, this, &RemoteProxyConnection::onAuthenticateFinished); return true; } void RemoteProxyConnection::disconnectServer() { if (m_connection) { qCDebug(dcRemoteProxyClientConnection()) << "Disconnecting from" << m_connection->serverUrl().toString(); m_connection->disconnectServer(); } } }