summaryrefslogtreecommitdiffstats
path: root/qdb
diff options
context:
space:
mode:
authorKari Oikarinen <kari.oikarinen@qt.io>2016-11-11 15:47:51 +0200
committerKari Oikarinen <kari.oikarinen@qt.io>2016-11-21 11:24:30 +0000
commit539ae0096ebd6123632685a69fc554ec6ba8c33b (patch)
treeea5038a1da62c24dbafd3cafc7962d80e9f63c1c /qdb
parent9f8a4a7898e6de5ab53d496bb322170c57605835 (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.cpp126
-rw-r--r--qdb/client/client.h28
-rw-r--r--qdb/main.cpp15
-rw-r--r--qdb/qdb.pro2
-rw-r--r--qdb/server/hostserver.cpp26
-rw-r--r--qdb/server/hostserver.h3
-rw-r--r--qdb/server/logging.cpp102
-rw-r--r--qdb/server/logging.h26
-rw-r--r--qdb/server/usb-host/usbdeviceenumerator.cpp1
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()