diff options
author | Kari Oikarinen <kari.oikarinen@qt.io> | 2016-11-11 15:47:51 +0200 |
---|---|---|
committer | Kari Oikarinen <kari.oikarinen@qt.io> | 2016-11-21 11:24:30 +0000 |
commit | 539ae0096ebd6123632685a69fc554ec6ba8c33b (patch) | |
tree | ea5038a1da62c24dbafd3cafc7962d80e9f63c1c /qdb | |
parent | 9f8a4a7898e6de5ab53d496bb322170c57605835 (diff) |
Start host server automatically from qdb
Log to a file from the host server process. This can be prevented by
setting the environment variable QDB_LOGGING_TO_CONSOLE=1.
Add `qdb stop-server` for shutting down a host server process.
Task-number: QTBUG-56070
Change-Id: Ie6455c7a2517df90a3e7c42f0256cbbdd31b6cff
Reviewed-by: Samuli Piippo <samuli.piippo@qt.io>
Diffstat (limited to 'qdb')
-rw-r--r-- | qdb/client/client.cpp | 126 | ||||
-rw-r--r-- | qdb/client/client.h | 28 | ||||
-rw-r--r-- | qdb/main.cpp | 15 | ||||
-rw-r--r-- | qdb/qdb.pro | 2 | ||||
-rw-r--r-- | qdb/server/hostserver.cpp | 26 | ||||
-rw-r--r-- | qdb/server/hostserver.h | 3 | ||||
-rw-r--r-- | qdb/server/logging.cpp | 102 | ||||
-rw-r--r-- | qdb/server/logging.h | 26 | ||||
-rw-r--r-- | qdb/server/usb-host/usbdeviceenumerator.cpp | 1 |
9 files changed, 306 insertions, 23 deletions
diff --git a/qdb/client/client.cpp b/qdb/client/client.cpp index cbb698f..bcb7ac0 100644 --- a/qdb/client/client.cpp +++ b/qdb/client/client.cpp @@ -20,36 +20,136 @@ ******************************************************************************/ #include "client.h" +#include "libqdb/make_unique.h" #include "libqdb/qdbconstants.h" #include <QtCore/qcoreapplication.h> #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> +#include <QtCore/qprocess.h> #include <QtCore/qtimer.h> #include <QtNetwork/qlocalsocket.h> #include <iostream> -int askDevices(QCoreApplication &app) +void forkHostServer() { - QLocalSocket socket; - socket.connectToServer(qdbSocketName); - if (!socket.waitForConnected()) { - std::cerr << "Could not connect to QDB host server\n"; - return 1; + QStringList arguments; + arguments << "server"; + if (!QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments)) + std::cerr << "Could not start QDB host server\n"; +} + +int execClient(const QCoreApplication &app, const QString &command) +{ + Client client; + if (command == "devices") + client.askDevices(); + else if (command == "stop-server") + client.stopServer(); + else + qFatal("Unknown command %s in execClient", qUtf8Printable(command)); + return app.exec(); +} + +Client::Client() + : m_socket{nullptr}, + m_triedToStart{false} +{ + +} + +void Client::askDevices() +{ + m_socket = make_unique<QLocalSocket>(); + connect(m_socket.get(), &QLocalSocket::connected, this, &Client::handleDevicesConnection); + connect(m_socket.get(), QOverload<QLocalSocket::LocalSocketError>::of(&QLocalSocket::error), + this, &Client::handleDevicesError); + m_socket->connectToServer(qdbSocketName); +} + +void Client::stopServer() +{ + m_socket = make_unique<QLocalSocket>(); + connect(m_socket.get(), &QLocalSocket::connected, this, &Client::handleStopConnection); + connect(m_socket.get(), QOverload<QLocalSocket::LocalSocketError>::of(&QLocalSocket::error), + this, &Client::handleStopError); + m_socket->connectToServer(qdbSocketName); +} + +void Client::handleDevicesConnection() +{ + m_socket->write("{\"request\":\"devices\"}"); + if (!m_socket->waitForReadyRead()) { + std::cerr << "Could not read response from QDB host server\n"; + shutdown(1); + return; + } + + const auto response = m_socket->readLine(); + const auto document = QJsonDocument::fromJson(response); + + std::cout << document.toJson().data() << std::endl; + + shutdown(0); +} + +void Client::handleDevicesError(QLocalSocket::LocalSocketError error) +{ + if (error == QLocalSocket::PeerClosedError) + return; + if (error != QLocalSocket::ServerNotFoundError && + error != QLocalSocket::ConnectionRefusedError) { + std::cerr << "Unexpected QLocalSocket error:" << qUtf8Printable(m_socket->errorString()) + << std::endl; + shutdown(1); + return; } - socket.write("{\"request\":\"devices\"}"); - if (!socket.waitForReadyRead()) { + if (m_triedToStart) { + std::cerr << "Could not connect QDB host server even after trying to start it\n"; + shutdown(1); + return; + } + std::cout << "Starting QDB host server\n"; + m_triedToStart = true; + forkHostServer(); + QTimer::singleShot(500, this, &Client::askDevices); +} + +void Client::handleStopConnection() +{ + m_socket->write("{\"request\":\"stop-server\"}"); + if (!m_socket->waitForReadyRead()) { std::cerr << "Could not read response from QDB host server\n"; - return 1; + shutdown(1); + return; } - const auto response = socket.readLine(); + + const auto response = m_socket->readLine(); const auto document = QJsonDocument::fromJson(response); - std::cout << "Response: " << document.toJson().data() << std::endl; + if (document.object()["response"] == "stopping") { + std::cout << "Stopped server\n"; + shutdown(0); + } else { + std::cerr << "Unexpected response: " << document.toJson().data() << std::endl; + shutdown(1); + } +} - QTimer::singleShot(0, &app, &QCoreApplication::quit); +void Client::handleStopError(QLocalSocket::LocalSocketError error) +{ + if (error == QLocalSocket::PeerClosedError) + return; - return app.exec(); + std::cerr << "Could not connect to QDB host server, perhaps no server was running?\n"; + shutdown(1); +} + +void Client::shutdown(int exitCode) +{ + QTimer::singleShot(0, [=]() { + QCoreApplication::instance()->exit(exitCode); + }); } diff --git a/qdb/client/client.h b/qdb/client/client.h index 04b009f..ce5ef1d 100644 --- a/qdb/client/client.h +++ b/qdb/client/client.h @@ -21,12 +21,34 @@ #ifndef CLIENT_H #define CLIENT_H -#include <QtGlobal> - +#include <QtNetwork/qlocalsocket.h> QT_BEGIN_NAMESPACE class QCoreApplication; QT_END_NAMESPACE -int askDevices(QCoreApplication &app); +#include <memory> + +int execClient(const QCoreApplication &app, const QString &command); + +class Client : public QObject +{ + Q_OBJECT +public: + Client(); + +public slots: + void askDevices(); + void stopServer(); + +private: + void handleDevicesConnection(); + void handleDevicesError(QLocalSocket::LocalSocketError error); + void handleStopConnection(); + void handleStopError(QLocalSocket::LocalSocketError error); + void shutdown(int exitCode); + + std::unique_ptr<QLocalSocket> m_socket; + bool m_triedToStart; +}; #endif // CLIENT_H diff --git a/qdb/main.cpp b/qdb/main.cpp index e8645fc..2ba5db4 100644 --- a/qdb/main.cpp +++ b/qdb/main.cpp @@ -31,13 +31,18 @@ int main(int argc, char *argv[]) { QCoreApplication app{argc, argv}; + QStringList clientCommands = {"devices", "stop-server"}; + QCommandLineParser parser; parser.addHelpOption(); parser.addOption({"debug-transport", "Print each message that is sent. (Only server process)"}); parser.addOption({"debug-connection", "Show enqueued messages. (Only server process)"}); + auto commandList = clientCommands; + commandList << "server"; + std::sort(commandList.begin(), commandList.end()); parser.addPositionalArgument("command", "Subcommand of qdb to run. Possible commands are: " - "devices, server"); + + commandList.join(", ")); parser.process(app); const QStringList arguments = parser.positionalArguments(); @@ -45,10 +50,10 @@ int main(int argc, char *argv[]) parser.showHelp(1); const QString command = arguments[0]; - if (command == "devices") { - return askDevices(app); - } else if (command == "server") { - return hostServer(app, parser); + if (command == "server") { + return execHostServer(app, parser); + } else if (clientCommands.contains(command)) { + return execClient(app, command); } else { std::cerr << "Unrecognized command: " << qUtf8Printable(command) << std::endl; return 1; diff --git a/qdb/qdb.pro b/qdb/qdb.pro index bdc4041..5379961 100644 --- a/qdb/qdb.pro +++ b/qdb/qdb.pro @@ -25,6 +25,7 @@ HEADERS += \ server/echoservice.h \ server/handshakeservice.h \ server/hostserver.h \ + server/logging.h \ server/networkmanagercontrol.h \ server/service.h \ server/usb-host/usbcommon.h \ @@ -42,6 +43,7 @@ SOURCES += \ server/echoservice.cpp \ server/handshakeservice.cpp \ server/hostserver.cpp \ + server/logging.cpp \ server/networkmanagercontrol.cpp \ server/service.cpp \ server/usb-host/libusbcontext.cpp \ diff --git a/qdb/server/hostserver.cpp b/qdb/server/hostserver.cpp index f70a3e3..36898f0 100644 --- a/qdb/server/hostserver.cpp +++ b/qdb/server/hostserver.cpp @@ -22,6 +22,7 @@ #include "libqdb/interruptsignalhandler.h" #include "libqdb/qdbconstants.h" +#include "logging.h" #include <QtCore/qcoreapplication.h> #include <QtCore/qcommandlineparser.h> @@ -36,8 +37,10 @@ #include <QtNetwork/qlocalserver.h> #include <QtNetwork/qlocalsocket.h> -int hostServer(QCoreApplication &app, const QCommandLineParser &parser) +int execHostServer(const QCoreApplication &app, const QCommandLineParser &parser) { + setupLogging(); + QString filterRules; if (!parser.isSet("debug-transport")) filterRules.append("transport=false\n"); @@ -86,6 +89,7 @@ void HostServer::listen() void HostServer::close() { + qDebug() << "Shutting QDB host server down"; m_localServer.close(); emit closed(); } @@ -127,6 +131,8 @@ void HostServer::handleRequest() if (requestObject["request"] == "devices") { replyDeviceInformation(); + } else if (requestObject["request"] == "stop-server") { + stopServer(); } else { qWarning() << "Got invalid request from client:" << requestBytes; m_client->disconnectFromServer(); @@ -158,3 +164,21 @@ void HostServer::replyDeviceInformation() m_client->disconnectFromServer(); qDebug() << "Replied device information to the client"; } + +void HostServer::stopServer() +{ + QJsonObject obj; + obj["response"] = "stopping"; + + const QByteArray response = QJsonDocument{obj}.toJson(QJsonDocument::Compact); + + if (!m_client || !m_client->isWritable()) { + qWarning() << "Could not reply to the client"; + return; + } + m_client->write(response); + m_client->waitForBytesWritten(); + m_client->disconnectFromServer(); + qDebug() << "Acknowledged stopping"; + close(); +} diff --git a/qdb/server/hostserver.h b/qdb/server/hostserver.h index 007c8ff..d6b161e 100644 --- a/qdb/server/hostserver.h +++ b/qdb/server/hostserver.h @@ -31,7 +31,7 @@ class QCoreApplication; class QCommandLineParser; QT_END_NAMESPACE -int hostServer(QCoreApplication &app, const QCommandLineParser &parser); +int execHostServer(const QCoreApplication &app, const QCommandLineParser &parser); class HostServer : public QObject { @@ -55,6 +55,7 @@ private slots: private: void replyDeviceInformation(); + void stopServer(); QLocalServer m_localServer; QLocalSocket *m_client; // owned by this class, deleted in handleDisconnection() diff --git a/qdb/server/logging.cpp b/qdb/server/logging.cpp new file mode 100644 index 0000000..6566537 --- /dev/null +++ b/qdb/server/logging.cpp @@ -0,0 +1,102 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Debug Bridge. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ +#include "logging.h" + +#include <QtCore/qdatetime.h> +#include <QtCore/qdebug.h> +#include <QtCore/qdir.h> +#include <QtCore/qfile.h> +#include <QtCore/qstandardpaths.h> +#include <QtGlobal> + +static QFile logFile; + +void hostServerMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + Q_UNUSED(context); + if (!logFile.isWritable()) { + if (!logFile.open(QFile::WriteOnly | QIODevice::Unbuffered)) { + // Fall back to default handler + qInstallMessageHandler(nullptr); + qCritical() << "Could not open log file" << logFile.fileName(); + return; + } else { + QString startMessage{"-- Starting QDB host server log on %1 --\n"}; + startMessage = startMessage.arg(QDateTime::currentDateTime().toString(Qt::ISODate)); + logFile.write(startMessage.toUtf8()); + } + } + + QString prefix; + switch (type) { + case QtDebugMsg: + prefix = "D:"; + break; + case QtInfoMsg: + prefix = "I:"; + break; + case QtWarningMsg: + prefix = "W:"; + break; + case QtCriticalMsg: + prefix = "C:"; + break; + case QtFatalMsg: + prefix = "F:"; + break; + } + + auto fullMsg = QString{"%1 %2\n"}.arg(prefix).arg(msg).toUtf8(); + auto written = logFile.write(fullMsg); + if (written != fullMsg.size()) { + qInstallMessageHandler(nullptr); + qCritical() << "Could not write into log file" << logFile.fileName() + << ":" << logFile.errorString(); + } + + if (type == QtFatalMsg) + abort(); +} + +void setupLogging() +{ + if (qgetenv("QDB_LOGGING_TO_CONSOLE") != "1") { + auto dataLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + if (!dataLocation.isEmpty()) { + QDir dataDir{dataLocation}; + bool dirAvailable; + if (dataDir.exists()) + dirAvailable = true; + else + dirAvailable = dataDir.mkpath("."); + + if (dirAvailable) { + logFile.setFileName(dataLocation + "/qdb.log"); + qInstallMessageHandler(hostServerMessageHandler); + } else { + qWarning() << "Application data location" << dataLocation + << "was not possible to log in, logging to console"; + } + } else { + qWarning() << "Could not find writable application data location, logging to console"; + } + } +} diff --git a/qdb/server/logging.h b/qdb/server/logging.h new file mode 100644 index 0000000..dfcb23b --- /dev/null +++ b/qdb/server/logging.h @@ -0,0 +1,26 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Debug Bridge. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ +#ifndef QDB_LOGGING_H +#define QDB_LOGGING_H + +void setupLogging(); + +#endif // QDB_LOGGING_H diff --git a/qdb/server/usb-host/usbdeviceenumerator.cpp b/qdb/server/usb-host/usbdeviceenumerator.cpp index 8a6d823..7095db8 100644 --- a/qdb/server/usb-host/usbdeviceenumerator.cpp +++ b/qdb/server/usb-host/usbdeviceenumerator.cpp @@ -184,6 +184,7 @@ void UsbDeviceEnumerator::startMonitoring() { QObject::connect(&m_pollTimer, &QTimer::timeout, this, &UsbDeviceEnumerator::pollQdbDevices); m_pollTimer.start(1000); + pollQdbDevices(); } void UsbDeviceEnumerator::stopMonitoring() |