WIP: main

This commit is contained in:
driftingsun 2020-12-26 15:03:51 +03:00
parent f25f34565a
commit 15730b470e
52 changed files with 2438 additions and 208 deletions

View file

@ -0,0 +1,168 @@
#include <QCoreApplication>
#include <QFileInfo>
#include <QLocalServer>
#include <QLocalSocket>
#include "localserver.h"
#include "utils.h"
LocalServer::LocalServer(const QString& name, QObject *parent) : QObject(parent),
m_clientConnected(false),
m_clientConnection(nullptr)
{
m_server = new QLocalServer(this);
m_server->setSocketOptions(QLocalServer::WorldAccessOption);
if (!m_server->listen(name)) {
qDebug() << QString("Unable to start the server: %1.").arg(m_server->errorString());
return;
}
connect(m_server, &QLocalServer::newConnection, this, &LocalServer::onNewConnection);
qDebug() << "Local server started";
}
LocalServer::~LocalServer()
{
m_clientConnected = false;
m_server->disconnect();
qDebug() << "Local server stopped";
}
bool LocalServer::isRunning() const
{
return m_server->isListening();
}
void LocalServer::onNewConnection()
{
if (m_clientConnection) {
m_clientConnection->deleteLater();
}
m_clientConnection = m_server->nextPendingConnection();
connect(m_clientConnection, &QLocalSocket::disconnected, this, &LocalServer::onDisconnected);
m_clientConnected = true;
qDebug() << "On new connection";
for(;;) {
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
if (!m_clientConnected || !m_clientConnection) {
break;
}
if (m_clientConnection->waitForReadyRead() && m_clientConnection->canReadLine()) {
char buf[1024];
qint64 lineLength = m_clientConnection->readLine(buf, sizeof(buf));
if (lineLength != -1) {
QString line = buf;
line = line.simplified();
qDebug().noquote() << QString("Readed line: '%1'").arg(line);
Message icomingMessage(line);
if (!icomingMessage.isValid()) {
qWarning().noquote() << "Message is not valid!";
continue;
}
switch (icomingMessage.state()) {
case Message::State::Initialize:
sendMessage(Message(Message::State::Initialize, QStringList({"Pong"})));
break;
case Message::State::StartRequest:
startProcess(icomingMessage.args());
break;
case Message::State::FinishRequest:
finishProcess(icomingMessage.args());
break;
default:
;
}
}
}
}
qDebug() << "Released";
}
void LocalServer::finishProcess(const QStringList& args)
{
Q_UNUSED(args)
}
void LocalServer::startProcess(const QStringList& messageArgs)
{
if (messageArgs.size() < 1) {
return;
}
QProcess* process = new QProcess();
connect(process, SIGNAL(started()), this, SLOT(onStarted()));
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished(int, QProcess::ExitStatus)));
const QString program = messageArgs.at(0);
QStringList args;
for (int i = 1; i < messageArgs.size(); i++) {
args.append(messageArgs.at(i));
}
QFileInfo fi(program);
const QString baseName = fi.baseName();
if (!fi.exists()) {
qWarning() << "This program does not exist";
sendMessage(Message(Message::State::Started, QStringList({baseName})));
sendMessage(Message(Message::State::Finished, QStringList({baseName, QString::number(-1)})));
return;
}
process->setObjectName(baseName);
qDebug().noquote() << QString("Start process '%1' - '%2' with args '%3'")
.arg(baseName).arg(program).arg(args.join(","));
process->start(program, args);
m_processList.append(process);
}
void LocalServer::onFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
Q_UNUSED(exitStatus)
QProcess* process = (QProcess*)sender();
sendMessage(Message(Message::State::Finished, QStringList({process->objectName(), QString::number(exitCode)})));
}
void LocalServer::onStarted()
{
QProcess* process = (QProcess*)sender();
sendMessage(Message(Message::State::Started, QStringList({process->objectName()})));
}
void LocalServer::onDisconnected()
{
if (!m_clientConnected) {
return;
}
m_clientConnected = false;
QLocalSocket* clientConnection = (QLocalSocket*)sender();
clientConnection->deleteLater();
qDebug() << "Diconnected";
}
void LocalServer::sendMessage(const Message& message)
{
if (!m_clientConnection || !m_clientConnected) {
qDebug()<< "Cannot send data, remote peer is not connected";
return;
}
const QString data = message.toString();
bool status = m_clientConnection->write(QString(data + "\n").toLocal8Bit());
qDebug().noquote() << QString("Send message '%1', status '%2'").arg(data).arg(Utils::toString(status));
}

View file

@ -0,0 +1,43 @@
#ifndef LOCALSERVER_H
#define LOCALSERVER_H
#include <QObject>
#include <QProcess>
#include <QStringList>
#include <QVector>
#include "message.h"
class QLocalServer;
class QLocalSocket;
class QProcess;
class LocalServer : public QObject
{
Q_OBJECT
public:
explicit LocalServer(const QString& name, QObject* parent = nullptr);
~LocalServer();
bool isRunning() const;
protected slots:
void onDisconnected();
void onNewConnection();
void onFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onStarted();
private:
void finishProcess(const QStringList& messageArgs);
void sendMessage(const Message& message);
void startProcess(const QStringList& messageArgs);
QLocalServer* m_server;
QLocalSocket* m_clientConnection;
QVector<QProcess*> m_processList;
bool m_clientConnected;
};
#endif // LOCALSERVER_H

53
service/server/log.cpp Normal file
View file

@ -0,0 +1,53 @@
#include <QDir>
#include <QStandardPaths>
#include <iostream>
#include "log.h"
#include "defines.h"
#include "utils.h"
QFile Log::m_file;
QTextStream Log::m_textStream;
QString Log::m_logFileName;
void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
if (msg.simplified().isEmpty()) {
return;
}
Log::m_textStream << qFormatLogMessage(type, context, msg) << endl << flush;
std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush;
}
bool Log::initialize()
{
QString path = Utils::systemLogPath();
QDir appDir(path);
if (!appDir.mkpath(path)) {
return false;
}
m_logFileName = QString("%1.log").arg(SERVICE_NAME);
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}");
m_file.setFileName(appDir.filePath(m_logFileName));
if (!m_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qWarning() << "Cannot open log file:" << m_logFileName;
return false;
}
m_file.setTextModeEnabled(true);
m_textStream.setDevice(&m_file);
qInstallMessageHandler(debugMessageHandler);
return true;
}
QString Log::serviceLogFileNamePath()
{
return m_file.fileName();
}

23
service/server/log.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef LOG_H
#define LOG_H
#include <QDebug>
#include <QFile>
#include <QString>
#include <QTextStream>
class Log
{
public:
static bool initialize();
static QString serviceLogFileNamePath();
private:
friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
static QFile m_file;
static QString m_logFileName;
static QTextStream m_textStream;
};
#endif // LOG_H

View file

@ -1,7 +1,10 @@
#include <QSettings>
#include <QDir>
#include "server.h"
#include "systemservice.h"
#include "log.h"
#include "defines.h"
#include "localserver.h"
int main(int argc, char **argv)
{
@ -11,6 +14,20 @@ int main(int argc, char **argv)
QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope, QDir::tempPath());
qWarning("(Example uses dummy settings file: %s/QtSoftware.conf)", QDir::tempPath().toLatin1().constData());
#endif
HttpService service(argc, argv);
return service.exec();
Log::initialize();
if (argc == 2) {
qInfo() << "Started as console application";
QCoreApplication app(argc,argv);
LocalServer localServer(SERVICE_NAME);
if (!localServer.isRunning()) {
return -1;
}
return app.exec();
} else {
qInfo() << "Started as system service";
SystemService systemService(argc, argv);
return systemService.exec();
}
}

View file

@ -1,112 +0,0 @@
#include <QDateTime>
#include <QDebug>
#include <QTcpSocket>
#include "server.h"
HttpDaemon::HttpDaemon(quint16 port, QObject* parent)
: QTcpServer(parent), disabled(false)
{
listen(QHostAddress::Any, port);
qDebug() << "Listen on port: " << port;
connect(this, &QTcpServer::newConnection, this, &HttpDaemon::sendFortune);
}
void HttpDaemon::sendFortune()
{
qDebug() << "New connection: ";
QTcpSocket *clientConnection = this->nextPendingConnection();
connect(clientConnection, &QAbstractSocket::disconnected,
clientConnection, &QObject::deleteLater);
connect(clientConnection, SIGNAL(readyRead()), this, SLOT(readClient()));
connect(clientConnection, SIGNAL(disconnected()), this, SLOT(discardClient()));
//->setSocketDescriptor(socket);
}
void HttpDaemon::pause()
{
disabled = true;
}
void HttpDaemon::resume()
{
disabled = false;
}
void HttpDaemon::readClient()
{
qDebug() << "readClient";
// if (disabled)
// return;
//
// This slot is called when the client sent data to the server. The
// server looks if it was a get request and sends a very simple HTML
// document back.
QTcpSocket* socket = (QTcpSocket*)sender();
if (socket->canReadLine()) {
QStringList tokens = QString(socket->readLine()).split(QRegExp("[ \r\n][ \r\n]*"));
if (tokens[0] == "GET") {
QTextStream os(socket);
os.setAutoDetectUnicode(true);
os << "HTTP/1.0 200 Ok\r\n"
"Content-Type: text/html; charset=\"utf-8\"\r\n"
"\r\n"
"<h1>Nothing to see here</h1>\n"
<< QDateTime::currentDateTime().toString() << "\n";
socket->close();
QtServiceBase::instance()->logMessage("Wrote to client");
if (socket->state() == QTcpSocket::UnconnectedState) {
delete socket;
QtServiceBase::instance()->logMessage("Connection closed");
}
}
}
}
void HttpDaemon::discardClient()
{
QTcpSocket* socket = (QTcpSocket*)sender();
socket->deleteLater();
QtServiceBase::instance()->logMessage("Connection closed");
}
HttpService::HttpService(int argc, char **argv)
: QtService<QCoreApplication>(argc, argv, "Qt HTTP Daemon")
{
setServiceDescription("A dummy HTTP service implemented with Qt");
setServiceFlags(QtServiceBase::CanBeSuspended);
}
void HttpService::start()
{
QCoreApplication *app = application();
daemon = new HttpDaemon(8989, app);
if (!daemon->isListening()) {
logMessage(QString("Failed to bind to port %1").arg(daemon->serverPort()), QtServiceBase::Error);
app->quit();
}
}
void HttpService::pause()
{
daemon->pause();
}
void HttpService::resume()
{
daemon->resume();
}

View file

@ -1,43 +0,0 @@
#ifndef SERVER_H
#define SERVER_H
#include <QCoreApplication>
#include <QTcpServer>
#include "qtservice.h"
class HttpDaemon : public QTcpServer
{
Q_OBJECT
public:
HttpDaemon(quint16 port, QObject* parent = 0);
void sendFortune();
void pause();
void resume();
private slots:
void readClient();
void discardClient();
private:
bool disabled;
};
class HttpService : public QtService<QCoreApplication>
{
public:
HttpService(int argc, char **argv);
protected:
void pause();
void resume();
void start();
private:
HttpDaemon *daemon;
};
#endif // SERVER_H

View file

@ -1,13 +1,22 @@
TARGET = AmneziaVPN-service
TEMPLATE = app
CONFIG += console qt
QT = core network
CONFIG += console qt no_batch
QT += core network
HEADERS = \
server.h
../../client/message.h \
../../client/utils.h \
localserver.h \
log.h \
systemservice.h
SOURCES = \
server.cpp \
main.cpp
../../client/message.cpp \
../../client/utils.cpp \
localserver.cpp \
log.cpp \
main.cpp \
systemservice.cpp
include(../src/qtservice.pri)
@ -17,3 +26,5 @@ CONFIG(release, debug|release) {
OBJECTS_DIR = $$DESTDIR
RCC_DIR = $$DESTDIR
}
INCLUDEPATH += "$$PWD/../../client"

View file

@ -0,0 +1,24 @@
#include "defines.h"
#include "localserver.h"
#include "systemservice.h"
SystemService::SystemService(int argc, char **argv)
: QtService<QCoreApplication>(argc, argv, SERVICE_NAME)
{
setServiceDescription("Service for AmneziaVPN");
}
void SystemService::start()
{
QCoreApplication* app = application();
m_localServer = new LocalServer(SERVICE_NAME);
if (!m_localServer->isRunning()) {
app->quit();
}
}
void SystemService::stop()
{
delete m_localServer;
}

View file

@ -0,0 +1,24 @@
#ifndef SYSTEMSERVICE_H
#define SYSTEMSERVICE_H
#include <QCoreApplication>
#include "qtservice.h"
class LocalServer;
class SystemService : public QtService<QCoreApplication>
{
public:
SystemService(int argc, char** argv);
protected:
void start() override;
void stop() override;
private:
LocalServer* m_localServer;
};
#endif // SYSTEMSERVICE_H