summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Vrátil <dvratil@kde.org>2016-01-21 01:19:11 (GMT)
committerDaniel Vrátil <dvratil@kde.org>2016-08-15 19:50:58 (GMT)
commit0e478e2b0fb7ed01ddf1fd4f856c3157ed9076c9 (patch)
tree9fe6f0ae2ba24e4380eec700d18e7eb1384f53fd
parentd7a64c888753c3f0bca6cc598ffe58a7bbf9d0da (diff)
Make AkonadiServer QObject, manage multiple QLocalServers for different purposes
This creates so called CommandServer and NotificationServer, both QLocalServer listening using named pipes (this is a move away from a socket file to avoid having multiple files). Each new connection on CommandServer makes AkonadiServer to instantiate new Connection object as normally. For NotificationServer each new connection is handed over to NotificationManager, which will deal with it.
-rw-r--r--autotests/server/fakeakonadiserver.cpp18
-rw-r--r--autotests/server/fakeakonadiserver.h5
-rw-r--r--autotests/server/fakeclient.cpp2
-rw-r--r--src/server/CMakeLists.txt1
-rw-r--r--src/server/aklocalserver.cpp33
-rw-r--r--src/server/aklocalserver.h45
-rw-r--r--src/server/akonadi.cpp93
-rw-r--r--src/server/akonadi.h23
8 files changed, 170 insertions, 50 deletions
diff --git a/autotests/server/fakeakonadiserver.cpp b/autotests/server/fakeakonadiserver.cpp
index b3f5375..3a766e6 100644
--- a/autotests/server/fakeakonadiserver.cpp
+++ b/autotests/server/fakeakonadiserver.cpp
@@ -37,6 +37,7 @@
#include <private/standarddirs_p.h>
#include <shared/akapplication.h>
+#include "aklocalserver.h"
#include "storage/dbconfig.h"
#include "storage/datastore.h"
#include "preprocessormanager.h"
@@ -127,9 +128,9 @@ QString FakeAkonadiServer::basePath()
return QString::fromLatin1("/tmp/akonadiserver-test-%1").arg(QCoreApplication::instance()->applicationPid());
}
-QString FakeAkonadiServer::socketFile()
+QString FakeAkonadiServer::namedPipe()
{
- return basePath() % QLatin1String("/local/share/akonadi/akonadiserver.socket");
+ return QStringLiteral("FakeAkonadiServer-%1").arg(qApp->applicationPid());
}
QString FakeAkonadiServer::instanceName()
@@ -249,7 +250,9 @@ bool FakeAkonadiServer::quit()
qDebug() << "==== Fake Akonadi Server shutting down ====";
// Stop listening for connections
- close();
+ if (mCmdServer) {
+ mCmdServer->close();
+ }
const QCommandLineParser &args = AkApplicationBase::instance()->commandLineArguments();
if (!args.isSet(QLatin1String("no-cleanup"))) {
@@ -275,7 +278,7 @@ void FakeAkonadiServer::setScenarios(const TestScenario::List &scenarios)
mClient->setScenarios(scenarios);
}
-void FakeAkonadiServer::incomingConnection(quintptr socketDescriptor)
+void FakeAkonadiServer::newCmdConnection(quintptr socketDescriptor)
{
mConnection = new FakeConnection(socketDescriptor);
NotificationCollector *ntfCollector = Q_NULLPTR;
@@ -291,7 +294,10 @@ void FakeAkonadiServer::incomingConnection(quintptr socketDescriptor)
void FakeAkonadiServer::runTest()
{
- QVERIFY(listen(socketFile()));
+ mCmdServer = new AkLocalServer(this);
+ connect(mCmdServer, static_cast<void(AkLocalServer::*)(quintptr)>(&AkLocalServer::newConnection),
+ this, &FakeAkonadiServer::newCmdConnection);
+ QVERIFY(mCmdServer->listen(namedPipe()));
mServerLoop = new QEventLoop(this);
connect(mClient, &QThread::finished, mServerLoop, &QEventLoop::quit);
@@ -306,7 +312,7 @@ void FakeAkonadiServer::runTest()
mServerLoop->deleteLater();
mServerLoop = 0;
- close();
+ mCmdServer->close();
}
QSignalSpy *FakeAkonadiServer::notificationSpy() const
diff --git a/autotests/server/fakeakonadiserver.h b/autotests/server/fakeakonadiserver.h
index b0b917c..d9214e8 100644
--- a/autotests/server/fakeakonadiserver.h
+++ b/autotests/server/fakeakonadiserver.h
@@ -94,7 +94,7 @@ public:
bool quit() Q_DECL_OVERRIDE;
static QString basePath();
- static QString socketFile();
+ static QString namedPipe();
static QString instanceName();
static TestScenario::List loginScenario(const QByteArray &sessionId = QByteArray());
@@ -110,8 +110,7 @@ public:
void setPopulateDb(bool populate);
protected:
- /* Reimpl */
- void incomingConnection(quintptr socketDescriptor) Q_DECL_OVERRIDE;
+ void newCmdConnection(quintptr socketDescriptor) Q_DECL_OVERRIDE;
private:
explicit FakeAkonadiServer();
diff --git a/autotests/server/fakeclient.cpp b/autotests/server/fakeclient.cpp
index 7142a67..ce7cd4a 100644
--- a/autotests/server/fakeclient.cpp
+++ b/autotests/server/fakeclient.cpp
@@ -159,7 +159,7 @@ void FakeClient::writeClientPart()
void FakeClient::run()
{
mSocket = new QLocalSocket();
- mSocket->connectToServer(FakeAkonadiServer::socketFile());
+ mSocket->connectToServer(FakeAkonadiServer::namedPipe());
connect(mSocket, &QIODevice::readyRead, this, &FakeClient::dataAvailable);
connect(mSocket, &QLocalSocket::disconnected, this, &FakeClient::connectionLost);
if (!mSocket->waitForConnected()) {
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
index 3d5841b..853e732 100644
--- a/src/server/CMakeLists.txt
+++ b/src/server/CMakeLists.txt
@@ -39,6 +39,7 @@ akonadi_generate_schema(${AKONADI_DB_SCHEME} AkonadiSchema akonadischema)
set(libakonadiserver_SRCS
akonadi.cpp
+ aklocalserver.cpp
akthread.cpp
commandcontext.cpp
connection.cpp
diff --git a/src/server/aklocalserver.cpp b/src/server/aklocalserver.cpp
new file mode 100644
index 0000000..6d2824b
--- /dev/null
+++ b/src/server/aklocalserver.cpp
@@ -0,0 +1,33 @@
+/*
+ Copyright (c) 2016 Daniel Vrátil <dvratil@kde.org>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#include "aklocalserver.h"
+
+using namespace Akonadi::Server;
+
+AkLocalServer::AkLocalServer(QObject* parent)
+ : QLocalServer(parent)
+{
+}
+
+void AkLocalServer::incomingConnection(quintptr socketDescriptor)
+{
+ Q_EMIT newConnection(socketDescriptor);
+}
+
diff --git a/src/server/aklocalserver.h b/src/server/aklocalserver.h
new file mode 100644
index 0000000..37ba4a1
--- /dev/null
+++ b/src/server/aklocalserver.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2016 Daniel Vrátil <dvratil@kde.org>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#ifndef AKLOCALSERVER_H
+#define AKLOCALSERVER_H
+
+#include <QLocalServer>
+
+namespace Akonadi {
+namespace Server {
+
+class AkLocalServer : public QLocalServer
+{
+ Q_OBJECT
+public:
+ AkLocalServer(QObject *parent = Q_NULLPTR);
+
+Q_SIGNALS:
+ void newConnection(quintptr socketDescriptor);
+
+protected:
+ void incomingConnection(quintptr socketDescriptor) Q_DECL_OVERRIDE;
+};
+
+
+} // namespace Server
+} // namespace Akonadi
+
+#endif
diff --git a/src/server/akonadi.cpp b/src/server/akonadi.cpp
index f660b59..8683264 100644
--- a/src/server/akonadi.cpp
+++ b/src/server/akonadi.cpp
@@ -37,6 +37,7 @@
#include "preprocessormanager.h"
#include "search/searchmanager.h"
#include "search/searchtaskmanager.h"
+#include "aklocalserver.h"
#include "collectionreferencemanager.h"
@@ -44,6 +45,7 @@
#include <private/standarddirs_p.h>
#include <private/protocol_p.h>
#include <private/dbus_p.h>
+#include <private/instance_p.h>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
@@ -53,6 +55,7 @@
#include <QtCore/QSettings>
#include <QtCore/QTimer>
#include <QtDBus/QDBusServiceWatcher>
+#include <QtNetwork/QLocalServer>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
@@ -70,7 +73,10 @@ using namespace Akonadi::Server;
AkonadiServer *AkonadiServer::s_instance = 0;
AkonadiServer::AkonadiServer(QObject *parent)
- : QLocalServer(parent)
+ : QObject(parent)
+ , mCmdServer(Q_NULLPTR)
+ , mNtfServer(Q_NULLPTR)
+ , mNotificationManager(Q_NULLPTR)
, mCacheCleaner(Q_NULLPTR)
, mIntervalCheck(Q_NULLPTR)
, mStorageJanitor(Q_NULLPTR)
@@ -117,9 +123,23 @@ bool AkonadiServer::init()
s_instance = this;
+ mCmdServer = new AkLocalServer(this);
+ connect(mCmdServer, static_cast<void(AkLocalServer::*)(quintptr)>(&AkLocalServer::newConnection),
+ this, &AkonadiServer::newCmdConnection);
+
+ mNotificationManager = new NotificationManager();
+ mNtfServer = new AkLocalServer(this);
+ // Note: this is a queued connection, as NotificationManager lives in its
+ // own thread
+ connect(mNtfServer, static_cast<void(AkLocalServer::*)(quintptr)>(&AkLocalServer::newConnection),
+ mNotificationManager, &NotificationManager::registerConnection);
+
+
+
const QString connectionSettingsFile = StandardDirs::connectionConfigFile(XdgBaseDirs::WriteOnly);
QSettings connectionSettings(connectionSettingsFile, QSettings::IniFormat);
+ QString pipeName;
#ifdef Q_OS_WIN
HANDLE hToken = NULL;
PSID sid;
@@ -152,30 +172,37 @@ bool AkonadiServer::init()
}
free(sid);
}
- QString defaultPipe = QLatin1String("Akonadi-") + userID;
- QString namedPipe = settings.value(QLatin1String("Connection/NamedPipe"), defaultPipe).toString();
- if (!listen(namedPipe)) {
- qCCritical(AKONADISERVER_LOG) << "Unable to listen on Named Pipe" << namedPipe;
+ pipeName = QStringLiteral("Akonadi-%1").arg(userID);
+#else
+ uid_t uid = getuid();
+ pipeName = QStringLiteral("Akonadi-%1").arg(uid);
+#endif
+
+ if (Instance::hasIdentifier()) {
+ pipeName += QStringLiteral("-") % Instance::identifier();
+ }
+
+ const QString cmdPipeName = pipeName + QStringLiteral("-Cmd");
+ if (!mCmdServer->listen(cmdPipeName)) {
+ qCCritical(AKONADISERVER_LOG) << "Unable to listen on named pipe" << cmdPipeName;
quit();
return false;
}
- connectionSettings.setValue(QLatin1String("Data/Method"), QLatin1String("NamedPipe"));
- connectionSettings.setValue(QLatin1String("Data/NamedPipe"), namedPipe);
-#else
- const QString socketDir = Utils::preferredSocketDirectory(StandardDirs::saveDir("data"));
- const QString socketFile = socketDir + QLatin1String("/akonadiserver.socket");
- QFile::remove(socketFile);
- if (!listen(socketFile)) {
- qCCritical(AKONADISERVER_LOG) << "Unable to listen on Unix socket" << socketFile;
+ const QString ntfPipeName = pipeName + QStringLiteral("-Ntf");
+ if (!mNtfServer->listen(ntfPipeName)) {
+ qCCritical(AKONADISERVER_LOG) << "Unable to listen on named pipe" << ntfPipeName;
quit();
return false;
}
- connectionSettings.setValue(QStringLiteral("Data/Method"), QLatin1String("UnixPath"));
- connectionSettings.setValue(QStringLiteral("Data/UnixPath"), socketFile);
-#endif
+ connectionSettings.setValue(QStringLiteral("Data/Method"), QStringLiteral("NamedPipe"));
+ connectionSettings.setValue(QStringLiteral("Data/NamedPipe"), cmdPipeName);
+
+ connectionSettings.setValue(QStringLiteral("Notifications/Method"), QStringLiteral("NamedPipe"));
+ connectionSettings.setValue(QStringLiteral("Nottifications/NamedPipe"), ntfPipeName);
+
// initialize the database
DataStore *db = DataStore::self();
@@ -190,7 +217,6 @@ bool AkonadiServer::init()
return false;
}
- NotificationManager::self();
Tracer::self();
new DebugInterface(this);
ResourceManager::self();
@@ -276,6 +302,12 @@ bool AkonadiServer::quit()
}
mAlreadyShutdown = true;
+ qCDebug(AKONADISERVER_LOG) << "terminating connection threads";
+ for (int i = 0; i < mConnections.count(); ++i) {
+ delete mConnections[i];
+ }
+ mConnections.clear();
+
qCDebug(AKONADISERVER_LOG) << "terminating service threads";
delete mCacheCleaner;
delete mIntervalCheck;
@@ -283,12 +315,7 @@ bool AkonadiServer::quit()
delete mItemRetrieval;
delete mAgentSearchManager;
delete mSearchManager;
-
- qCDebug(AKONADISERVER_LOG) << "terminating connection threads";
- for (int i = 0; i < mConnections.count(); ++i) {
- delete mConnections[i];
- }
- mConnections.clear();
+ delete mNotificationManager;
// Terminate the preprocessor manager before the database but after all connections are gone
PreprocessorManager::done();
@@ -325,11 +352,12 @@ void AkonadiServer::doQuit()
QCoreApplication::exit();
}
-void AkonadiServer::incomingConnection(quintptr socketDescriptor)
+void AkonadiServer::newCmdConnection(quintptr socketDescriptor)
{
if (mAlreadyShutdown) {
return;
}
+
QPointer<Connection> connection = new Connection(socketDescriptor);
connect(connection.data(), &Connection::disconnected,
this, [connection]() {
@@ -422,23 +450,22 @@ void AkonadiServer::serviceOwnerChanged(const QString &name, const QString &oldO
CacheCleaner *AkonadiServer::cacheCleaner()
{
- if (mCacheCleaner) {
- return mCacheCleaner;
- }
-
- return Q_NULLPTR;
+ return mCacheCleaner;
}
IntervalCheck *AkonadiServer::intervalChecker()
{
- if (mIntervalCheck) {
- return mIntervalCheck;
- }
+ return mIntervalCheck;
+}
- return Q_NULLPTR;
+NotificationManager *AkonadiServer::notificationManager()
+{
+ return mNotificationManager;
}
QString AkonadiServer::serverPath() const
{
return XdgBaseDirs::homePath("config");
}
+
+#include "akonadi.moc"
diff --git a/src/server/akonadi.h b/src/server/akonadi.h
index 5ea7112..9c3e19d 100644
--- a/src/server/akonadi.h
+++ b/src/server/akonadi.h
@@ -20,11 +20,10 @@
#ifndef AKONADISERVER_H
#define AKONADISERVER_H
+#include <QtCore/QObject>
#include <QtCore/QPointer>
#include <QtCore/QVector>
-#include <QtNetwork/QLocalServer>
-
class QProcess;
namespace Akonadi {
@@ -38,8 +37,10 @@ class SearchManager;
class StorageJanitor;
class CacheCleaner;
class IntervalCheck;
+class AkLocalServer;
+class NotificationManager;
-class AkonadiServer : public QLocalServer
+class AkonadiServer : public QObject
{
Q_OBJECT
@@ -59,6 +60,11 @@ public:
QString serverPath() const;
+ /**
+ * Can return a nullptr
+ */
+ NotificationManager *notificationManager();
+
public Q_SLOTS:
/**
* Triggers a clean server shutdown.
@@ -67,14 +73,13 @@ public Q_SLOTS:
virtual bool init();
+protected Q_SLOTS:
+ virtual void newCmdConnection(quintptr socketDescriptor);
+
private Q_SLOTS:
void doQuit();
void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
-protected:
- /** reimpl */
- void incomingConnection(quintptr socketDescriptor) Q_DECL_OVERRIDE;
-
private:
bool startDatabaseProcess();
bool createDatabase();
@@ -83,6 +88,10 @@ private:
protected:
AkonadiServer(QObject *parent = Q_NULLPTR);
+ AkLocalServer *mCmdServer;
+ AkLocalServer *mNtfServer;
+
+ NotificationManager *mNotificationManager;
CacheCleaner *mCacheCleaner;
IntervalCheck *mIntervalCheck;
StorageJanitor *mStorageJanitor;