Qt remote objects IPC

This commit is contained in:
pokamest 2021-02-02 01:47:40 +03:00
parent c4df9c004b
commit 048a673d31
18 changed files with 340 additions and 25 deletions

View file

@ -1,2 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = client service platform

View file

@ -10,9 +10,11 @@ include("3rd/QtSsh/src/ssh/ssh.pri")
include("3rd/QtSsh/src/botan/botan.pri")
HEADERS += \
../ipc/ipc.h \
communicator.h \
core/defs.h \
core/errorstrings.h \
core/ipcclient.h \
core/openvpnconfigurator.h \
core/servercontroller.h \
debug.h \
@ -32,6 +34,7 @@ HEADERS += \
SOURCES += \
communicator.cpp \
core/ipcclient.cpp \
core/openvpnconfigurator.cpp \
core/servercontroller.cpp \
debug.cpp \
@ -101,5 +104,5 @@ macx {
LIBS += -framework Cocoa -framework ApplicationServices -framework CoreServices -framework Foundation -framework AppKit
}
REPC_REPLICA += ../communicator/communicator.rep
REPC_REPLICA += ../ipc/ipcinterface.rep

51
client/core/ipcclient.cpp Normal file
View file

@ -0,0 +1,51 @@
#include "ipcclient.h"
#include <QRemoteObjectNode>
IpcClient &IpcClient::Instance()
{
static IpcClient s;
return s;
}
QSharedPointer<IpcProcessInterfaceReplica> IpcClient::createPrivilegedProcess()
{
if (! Instance().m_ipcClient->isReplicaValid()) return nullptr;
QRemoteObjectPendingReply<int> futureResult = Instance().m_ipcClient->createPrivilegedProcess();
futureResult.waitForFinished(1000);
int pid = futureResult.returnValue();
QSharedPointer<QRemoteObjectNode> replica(new QRemoteObjectNode);
//Instance().m_processNodes.insert(pid, replica);
replica->connectToNode(QUrl(amnezia::getIpcProcessUrl(pid)));
auto ptr = QSharedPointer<IpcProcessInterfaceReplica>(replica->acquire<IpcProcessInterfaceReplica>());
connect(ptr.data(), &IpcProcessInterfaceReplica::destroyed, replica.data(), [replica](){
replica->deleteLater();
});
return ptr;
}
IpcClient::IpcClient(QObject *parent) : QObject(parent)
{
m_ClientNode.connectToNode(QUrl(QStringLiteral(IPC_SERVICE_URL)));
m_ipcClient.reset(m_ClientNode.acquire<IpcInterfaceReplica>());
m_ipcClient->waitForSource(1000);
// connect(m_ipcClient.data(), &IpcInterfaceReplica::stateChanged, [&](QRemoteObjectReplica::State state, QRemoteObjectReplica::State oldState){
//// qDebug() << "state" << state;
//// for (int i = 0; i < 10; ++i) {
//// QRemoteObjectPendingReply<qint64> future = m_ipcClient->createPrivilegedProcess("", QStringList());
//// future.waitForFinished();
//// qDebug() << "QRemoteObjectPendingReply" << QDateTime::currentMSecsSinceEpoch() - future.returnValue();
//// }
// });
}

30
client/core/ipcclient.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef IPCCLIENT_H
#define IPCCLIENT_H
#include <QObject>
#include "ipc.h"
#include "rep_ipcinterface_replica.h"
class IpcClient : public QObject
{
Q_OBJECT
public:
static IpcClient &Instance();
static QSharedPointer<IpcProcessInterfaceReplica> createPrivilegedProcess();
static QSharedPointer<IpcInterfaceReplica> ipcClient() { return Instance().m_ipcClient; }
signals:
private:
explicit IpcClient(QObject *parent = nullptr);
QRemoteObjectNode m_ClientNode; // create remote object node
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
//QMap<int, QSharedPointer<QRemoteObjectNode>> m_processNodes;
};
#endif // IPCCLIENT_H

View file

@ -11,8 +11,8 @@
OpenVpnProtocol::OpenVpnProtocol(const QString& args, QObject* parent) :
VpnProtocol(args, parent),
m_requestFromUserToStop(false)
VpnProtocol(args, parent)
//m_requestFromUserToStop(false)
{
setConfigFile(args);
connect(m_communicator, &Communicator::messageReceived, this, &OpenVpnProtocol::onMessageReceived);
@ -130,14 +130,14 @@ ErrorCode OpenVpnProtocol::start()
{
qDebug() << "Start OpenVPN connection";
m_requestFromUserToStop = false;
//m_requestFromUserToStop = false;
m_openVpnStateSigTermHandlerTimer.stop();
OpenVpnProtocol::stop();
if (communicator() && !communicator()->isConnected()) {
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return lastError();
}
// if (communicator() && !communicator()->isConnected()) {
// setLastError(ErrorCode::AmneziaServiceConnectionFailed);
// return lastError();
// }
if (!QFileInfo::exists(openVpnExecPath())) {
setLastError(ErrorCode::OpenVpnExecutableMissing);
@ -165,7 +165,20 @@ ErrorCode OpenVpnProtocol::start()
}
setConnectionState(ConnectionState::Connecting);
m_communicator->sendMessage(Message(Message::State::StartRequest, args));
QSharedPointer<IpcProcessInterfaceReplica> process = IpcClient::createPrivilegedProcess();
process->waitForSource(1000);
if (!process->isInitialized()) {
return ErrorCode::AmneziaServiceConnectionFailed;
}
process->setProgram(openVpnExecPath());
process->setArguments(QStringList() << "--config" << configPath()<<
"--management"<< m_managementHost<< QString::number(m_managementPort)<<
"--management-client"<<
"--log-append"<< vpnLogFileNamePath);
process->start();
//m_communicator->sendMessage(Message(Message::State::StartRequest, args));
startTimeoutTimer();
return ErrorCode::NoError;

View file

@ -9,6 +9,8 @@
#include "message.h"
#include "vpnprotocol.h"
#include "core/ipcclient.h"
class OpenVpnProtocol : public VpnProtocol
{
Q_OBJECT
@ -45,7 +47,7 @@ protected:
ManagementServer m_managementServer;
QString m_configFileName;
QTimer m_openVpnStateSigTermHandlerTimer;
bool m_requestFromUserToStop;
//bool m_requestFromUserToStop;
private:

View file

@ -5,6 +5,7 @@
#include <core/openvpnconfigurator.h>
#include <core/servercontroller.h>
#include "ipc.h"
#include "protocols/openvpnprotocol.h"
#include "protocols/shadowsocksvpnprotocol.h"
#include "utils.h"

View file

@ -4,6 +4,7 @@
#include <QObject>
#include <QString>
#include <QScopedPointer>
#include <QRemoteObjectNode>
#include "protocols/vpnprotocol.h"
#include "core/defs.h"
@ -45,6 +46,7 @@ protected:
private:
Settings m_settings;
};
#endif // VPNCONNECTION_H

View file

@ -1,6 +0,0 @@
#include <QtCore>
class RpcServer
{
SLOT(executeProcess(const QString &program, const QStringList &args));
SIGNAL(sendMessage(const QByteArray &message));
};

12
ipc/ipc.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef IPC_H
#define IPC_H
#include <QString>
#define IPC_SERVICE_URL "local:AmneziaVpnIpcInterface"
namespace amnezia {
inline QString getIpcProcessUrl(int pid) { return QString("%1_%2").arg(IPC_SERVICE_URL).arg(pid); }
}
#endif // IPC_H

32
ipc/ipcinterface.rep Normal file
View file

@ -0,0 +1,32 @@
#include <QtCore>
class IpcInterface
{
SLOT( int createPrivilegedProcess() ); // return local pid
//SIGNAL(sendMessage(const QByteArray &message));
};
class IpcProcessInterface
{
SLOT( start(const QString &program, const QStringList &args) );
SLOT( start() );
SLOT( close() );
SLOT( setArguments(const QStringList &arguments) );
SLOT( setInputChannelMode(QProcess::InputChannelMode mode) );
SLOT( setNativeArguments(const QString &arguments) );
SLOT( setProcessChannelMode(QProcess::ProcessChannelMode mode) );
SLOT( setProgram(const QString &program) );
SLOT( setWorkingDirectory(const QString &dir) );
SLOT( QByteArray readAllStandardError() );
SLOT( QByteArray readAllStandardOutput() );
SIGNAL( errorOccurred(QProcess::ProcessError error) );
SIGNAL( finished(int exitCode, QProcess::ExitStatus exitStatus) );
SIGNAL( readyReadStandardError() );
SIGNAL( readyReadStandardOutput() );
SIGNAL( started() );
SIGNAL( stateChanged(QProcess::ProcessState newState) );
};

20
ipc/ipcserver.cpp Normal file
View file

@ -0,0 +1,20 @@
#include "ipcserver.h"
#include <QDateTime>
IpcServer::IpcServer(QObject *parent):
IpcInterfaceSource(parent)
{}
int IpcServer::createPrivilegedProcess()
{
m_localpid++;
ProcessDescriptor pd;
pd.serverNode->setHostUrl(QUrl(amnezia::getIpcProcessUrl(m_localpid)));
pd.serverNode->enableRemoting(pd.ipcProcess.data());
m_processes.insert(m_localpid, pd);
return m_localpid;
}

32
ipc/ipcserver.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef IPCSERVER_H
#define IPCSERVER_H
#include <QObject>
#include "ipc.h"
#include "ipcserverprocess.h"
#include "rep_ipcinterface_source.h"
class IpcServer : public IpcInterfaceSource
{
public:
explicit IpcServer(QObject *parent = nullptr);
virtual int createPrivilegedProcess() override;
private:
int m_localpid = 0;
struct ProcessDescriptor {
ProcessDescriptor (QObject *parent = nullptr) {
serverNode = QSharedPointer<QRemoteObjectHost>(new QRemoteObjectHost(parent));
ipcProcess = QSharedPointer<IpcServerProcess>(new IpcServerProcess(parent));
}
QSharedPointer<IpcServerProcess> ipcProcess;
QSharedPointer<QRemoteObjectHost> serverNode;
};
QMap<int, ProcessDescriptor> m_processes;
};
#endif // IPCSERVER_H

71
ipc/ipcserverprocess.cpp Normal file
View file

@ -0,0 +1,71 @@
#include "ipcserverprocess.h"
#include <QProcess>
IpcServerProcess::IpcServerProcess(QObject *parent) :
IpcProcessInterfaceSource(parent),
m_process(QSharedPointer<QProcess>(new QProcess(this)))
{
connect(m_process.data(), &QProcess::errorOccurred, this, &IpcServerProcess::errorOccurred);
connect(m_process.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &IpcServerProcess::finished);
connect(m_process.data(), &QProcess::readyReadStandardError, this, &IpcServerProcess::readyReadStandardError);
connect(m_process.data(), &QProcess::readyReadStandardOutput, this, &IpcServerProcess::readyReadStandardOutput);
connect(m_process.data(), &QProcess::started, this, &IpcServerProcess::started);
connect(m_process.data(), &QProcess::stateChanged, this, &IpcServerProcess::stateChanged);
}
void IpcServerProcess::start(const QString &program, const QStringList &args)
{
m_process->start(program, args);
}
void IpcServerProcess::start()
{
m_process->start();
qDebug() << "IpcServerProcess started, " << m_process->arguments();
}
void IpcServerProcess::close()
{
m_process->close();
}
void IpcServerProcess::setArguments(const QStringList &arguments)
{
m_process->setArguments(arguments);
qDebug() << "IpcServerProcess started, " << arguments;
}
void IpcServerProcess::setInputChannelMode(QProcess::InputChannelMode mode)
{
m_process->setInputChannelMode(mode);
}
void IpcServerProcess::setNativeArguments(const QString &arguments)
{
m_process->setNativeArguments(arguments);
}
void IpcServerProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
{
m_process->setProcessChannelMode(mode);
}
void IpcServerProcess::setProgram(const QString &program)
{
m_process->setProgram(program);
}
void IpcServerProcess::setWorkingDirectory(const QString &dir)
{
m_process->setWorkingDirectory(dir);
}
QByteArray IpcServerProcess::readAllStandardError()
{
return m_process->readAllStandardError();
}
QByteArray IpcServerProcess::readAllStandardOutput()
{
return m_process->readAllStandardOutput();
}

34
ipc/ipcserverprocess.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef IPCSERVERPROCESS_H
#define IPCSERVERPROCESS_H
#include <QObject>
#include "rep_ipcinterface_source.h"
class IpcServerProcess : public IpcProcessInterfaceSource
{
Q_OBJECT
public:
explicit IpcServerProcess(QObject *parent = nullptr);
void start(const QString &program, const QStringList &args) override;
void start() override;
void close() override;
void setArguments(const QStringList &arguments) override;
void setInputChannelMode(QProcess::InputChannelMode mode) override;
void setNativeArguments(const QString &arguments) override;
void setProcessChannelMode(QProcess::ProcessChannelMode mode) override;
void setProgram(const QString &program) override;
void setWorkingDirectory(const QString &dir) override;
QByteArray readAllStandardError() override;
QByteArray readAllStandardOutput() override;
signals:
private:
QSharedPointer<QProcess> m_process;
};
#endif // IPCSERVERPROCESS_H

View file

@ -3,6 +3,7 @@
#include <QLocalServer>
#include <QLocalSocket>
#include "ipc.h"
#include "localserver.h"
#include "utils.h"
@ -14,19 +15,23 @@
LocalServer::LocalServer(QObject *parent) : QObject(parent),
m_clientConnection(nullptr),
m_clientConnected(false)
m_clientConnected(false),
m_ipcServer(this)
{
m_server = QSharedPointer<QLocalServer>(new QLocalServer(this));
m_server->setSocketOptions(QLocalServer::WorldAccessOption);
if (!m_server->listen(Utils::serverName())) {
qDebug() << QString("Unable to start the server: %1.").arg(m_server->errorString());
return;
}
// if (!m_server->listen(Utils::serverName())) {
// qDebug() << QString("Unable to start the server: %1.").arg(m_server->errorString());
// return;
// }
connect(m_server.data(), &QLocalServer::newConnection, this, &LocalServer::onNewConnection);
// connect(m_server.data(), &QLocalServer::newConnection, this, &LocalServer::onNewConnection);
qDebug().noquote() << QString("Local server started on '%1'").arg(m_server->serverName());
// qDebug().noquote() << QString("Local server started on '%1'").arg(m_server->serverName());
m_serverNode.setHostUrl(QUrl(QStringLiteral(IPC_SERVICE_URL))); // create host node without Registry
m_serverNode.enableRemoting(&m_ipcServer); // enable remoting/sharing
}
LocalServer::~LocalServer()
@ -41,7 +46,8 @@ LocalServer::~LocalServer()
bool LocalServer::isRunning() const
{
return m_server->isListening();
return true;
//return m_server->isListening();
}
void LocalServer::onNewConnection()

View file

@ -9,6 +9,7 @@
#include <QVector>
#include "message.h"
#include "ipcserver.h"
class QLocalServer;
class QLocalSocket;
@ -46,6 +47,9 @@ private:
QVector<QProcess*> m_processList;
bool m_clientConnected;
IpcServer m_ipcServer;
QRemoteObjectHost m_serverNode;
};
#endif // LOCALSERVER_H

View file

@ -1,11 +1,14 @@
TARGET = AmneziaVPN-service
TEMPLATE = app
CONFIG += console qt no_batch
QT += core network
QT += core network remoteobjects
HEADERS = \
../../client/message.h \
../../client/utils.h \
../../ipc/ipc.h \
../../ipc/ipcserver.h \
../../ipc/ipcserverprocess.h \
localserver.h \
log.h \
router.h \
@ -14,6 +17,8 @@ HEADERS = \
SOURCES = \
../../client/message.cpp \
../../client/utils.cpp \
../../ipc/ipcserver.cpp \
../../ipc/ipcserverprocess.cpp \
localserver.cpp \
log.cpp \
main.cpp \
@ -47,3 +52,5 @@ include(../src/qtservice.pri)
#}
INCLUDEPATH += "$$PWD/../../client"
REPC_SOURCE += ../../ipc/ipcinterface.rep