/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "daemonlocalserverconnection.h" #include #include #include #include #include "daemon.h" #include "leakdetector.h" #include "logger.h" namespace { Logger logger("DaemonLocalServerConnection"); } DaemonLocalServerConnection::DaemonLocalServerConnection(QObject* parent, QLocalSocket* socket) : QObject(parent) { MZ_COUNT_CTOR(DaemonLocalServerConnection); logger.debug() << "Connection created"; Q_ASSERT(socket); m_socket = socket; connect(m_socket, &QLocalSocket::readyRead, this, &DaemonLocalServerConnection::readData); Daemon* daemon = Daemon::instance(); connect(daemon, &Daemon::connected, this, &DaemonLocalServerConnection::connected); connect(daemon, &Daemon::disconnected, this, &DaemonLocalServerConnection::disconnected); connect(daemon, &Daemon::backendFailure, this, &DaemonLocalServerConnection::backendFailure); } DaemonLocalServerConnection::~DaemonLocalServerConnection() { MZ_COUNT_DTOR(DaemonLocalServerConnection); logger.debug() << "Connection released"; } void DaemonLocalServerConnection::readData() { logger.debug() << "Read Data"; Q_ASSERT(m_socket); while (true) { int pos = m_buffer.indexOf("\n"); if (pos == -1) { QByteArray input = m_socket->readAll(); if (input.isEmpty()) { break; } m_buffer.append(input); continue; } QByteArray line = m_buffer.left(pos); m_buffer.remove(0, pos + 1); QByteArray command(line); command = command.trimmed(); if (command.isEmpty()) { continue; } parseCommand(command); } } void DaemonLocalServerConnection::parseCommand(const QByteArray& data) { QJsonDocument json = QJsonDocument::fromJson(data); if (!json.isObject()) { logger.error() << "Invalid input"; return; } QJsonObject obj = json.object(); QJsonValue typeValue = obj.value("type"); if (!typeValue.isString()) { logger.warning() << "No type command. Ignoring request."; return; } QString type = typeValue.toString(); logger.debug() << "Command received:" << type; // It is expected that sometimes the client will request backend logs // before the first authentication. In these cases we just return empty // logs. if (type == "logs") { QJsonObject obj; obj.insert("type", "logs"); obj.insert("logs", ""); write(obj); return; } if (type == "activate") { InterfaceConfig config; if (!Daemon::parseConfig(obj, config)) { logger.error() << "Invalid configuration"; emit disconnected(); return; } if (!Daemon::instance()->activate(config)) { logger.error() << "Failed to activate the interface"; emit disconnected(); } return; } if (type == "deactivate") { Daemon::instance()->deactivate(true); return; } if (type == "status") { QJsonObject obj = Daemon::instance()->getStatus(); obj.insert("type", "status"); write(obj); return; } if (type == "logs") { QJsonObject obj; obj.insert("type", "logs"); obj.insert("logs", Daemon::instance()->logs().replace("\n", "|")); write(obj); return; } if (type == "cleanlogs") { Daemon::instance()->cleanLogs(); return; } logger.warning() << "Invalid command:" << type; } void DaemonLocalServerConnection::connected(const QString& pubkey) { QJsonObject obj; obj.insert("type", "connected"); obj.insert("pubkey", QJsonValue(pubkey)); write(obj); } void DaemonLocalServerConnection::disconnected() { QJsonObject obj; obj.insert("type", "disconnected"); write(obj); } void DaemonLocalServerConnection::backendFailure(DaemonError err) { QJsonObject obj; obj.insert("type", "backendFailure"); obj.insert("errorCode", static_cast(err)); write(obj); } void DaemonLocalServerConnection::write(const QJsonObject& obj) { m_socket->write(QJsonDocument(obj).toJson(QJsonDocument::Compact)); m_socket->write("\n"); }