Adds q2 repos to migrate
This commit is contained in:
1 parent
ad1f62c4ee
commit
17f1c61c9e
991 files changed
+178451
No files matched your search
Executable
+56
@@ -0,0 +1,56 @@
|
||||
# tcpserver
|
||||
SET(tcp_SRCS
|
||||
commandinterface.cpp
|
||||
commandinterface.h
|
||||
cbi_help.cpp
|
||||
cbi_help.h
|
||||
cbi_quit.cpp
|
||||
cbi_quit.h
|
||||
cbi_shutdown.cpp
|
||||
cbi_shutdown.h
|
||||
tcpserver.cpp
|
||||
tcpserver.h
|
||||
tcpserver_export.h
|
||||
tcpserver_logger.h
|
||||
workerbase.cpp
|
||||
workerbase.h
|
||||
)
|
||||
|
||||
SET(tcp_HDRS
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(tcpserver AAR SV SHARED ${tcp_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(tcpserver
|
||||
PRIVATE
|
||||
Qt5::Network
|
||||
ngltools
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
NGLLogger
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(tcpserver
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
)
|
||||
NGL_INSTALL_TARGET(tcpserver)
|
||||
|
||||
IF(BUILD_TESTING AND BUILD_SV AND NOT WIN32)
|
||||
LIST(APPEND tcp_test_SRCS
|
||||
cbi_pingpong.cpp
|
||||
cbi_pingpong.h
|
||||
cbi_recvfile.cpp
|
||||
cbi_recvfile.h
|
||||
cbi_sendfile.cpp
|
||||
cbi_sendfile.h
|
||||
tcpserver_test.cpp
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(tcpserver_test ${tcp_test_SRCS})
|
||||
TARGET_LINK_LIBRARIES(tcpserver_test
|
||||
Qt5::Core
|
||||
Qt5::Network
|
||||
tcpserver
|
||||
NGLLogger
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
|
||||
#include "cbi_help.h"
|
||||
#include "workerbase.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
CBI_Help::CBI_Help(unsigned short port)
|
||||
: CommandInterface(port, "HELP")
|
||||
{}
|
||||
|
||||
void CBI_Help::handleCommandInternal(const QVector<QByteArray> &)
|
||||
{
|
||||
const auto commands = workerBase()->getCommands();
|
||||
QStringList list;
|
||||
list.reserve(commands.size());
|
||||
for (const CommandInterface *i : commands)
|
||||
list += i->help();
|
||||
|
||||
std::sort(list.begin(), list.end());
|
||||
writeData(list.join(QLatin1Char('\n')));
|
||||
}
|
||||
|
||||
QString CBI_Help::help() const
|
||||
{
|
||||
return QLatin1String("HELP - prints out help informations");
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
|
||||
|
||||
class TCPSERVER_EXPORT CBI_Help : public CommandInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CBI_Help(unsigned short port);
|
||||
|
||||
void handleCommandInternal(const QVector<QByteArray> &args) override;
|
||||
QString help() const override;
|
||||
};
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
|
||||
#include "cbi_pingpong.h"
|
||||
|
||||
CBI_PingPong::CBI_PingPong(unsigned short port)
|
||||
: CommandInterface(port, "PING")
|
||||
{}
|
||||
|
||||
void CBI_PingPong::handleCommandInternal(const QVector<QByteArray> &args)
|
||||
{
|
||||
writeData("PONG");
|
||||
for (const QByteArray &ba : args)
|
||||
{
|
||||
writeData(" ");
|
||||
writeData(quote(ba.constData()));
|
||||
}
|
||||
}
|
||||
|
||||
QString CBI_PingPong::help() const
|
||||
{
|
||||
return QString::fromUtf8("PING <input> - mirror the Input and send the data back");
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
|
||||
|
||||
class CBI_PingPong : public CommandInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CBI_PingPong(unsigned short port);
|
||||
|
||||
void handleCommandInternal(const QVector<QByteArray> &args) override;
|
||||
QString help() const override;
|
||||
};
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
|
||||
#include "cbi_quit.h"
|
||||
|
||||
CBI_Quit::CBI_Quit(unsigned short port)
|
||||
: CommandInterface(port, "QUIT")
|
||||
{}
|
||||
|
||||
void CBI_Quit::handleCommandInternal(const QVector<QByteArray> &)
|
||||
{
|
||||
writeOk(QLatin1String("Bye!"));
|
||||
closeConnection();
|
||||
}
|
||||
|
||||
QString CBI_Quit::help() const
|
||||
{
|
||||
return QLatin1String("QUIT - close the current connection");
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
|
||||
|
||||
class TCPSERVER_EXPORT CBI_Quit : public CommandInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CBI_Quit(unsigned short port);
|
||||
|
||||
void handleCommandInternal(const QVector<QByteArray> &args) override;
|
||||
QString help() const override;
|
||||
};
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
|
||||
|
||||
|
||||
#include "cbi_recvfile.h"
|
||||
#include "workerbase.h"
|
||||
|
||||
#include <QtNetwork/QAbstractSocket>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QFile>
|
||||
#include <stdio.h>
|
||||
|
||||
CBI_Recvfile::CBI_Recvfile(unsigned short port)
|
||||
: CommandInterface(port, "RECV_FILE")
|
||||
{}
|
||||
|
||||
void CBI_Recvfile::handleCommandInternal(const QVector<QByteArray> &args)
|
||||
{
|
||||
if (args.count() != 2)
|
||||
{
|
||||
writeError(QLatin1String("Invalid arg count: RECV_FILE <filename> <filesize>"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString fn = QString::fromUtf8(args[0]);
|
||||
int size;
|
||||
getValue(args[1], size);
|
||||
|
||||
QFile *f = new QFile(fn);
|
||||
if (!f->open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
{
|
||||
writeError(QStringLiteral("Could not open %1 for writing").arg(fn));
|
||||
return;
|
||||
}
|
||||
m_wbMap.insert(workerBase(), QPair<QIODevice *, int>(f, size));
|
||||
workerBase()->redirectDataHandling(true, this);
|
||||
}
|
||||
|
||||
void CBI_Recvfile::newPlainData()
|
||||
{
|
||||
WorkerBase *wb = workerBase();
|
||||
QAbstractSocket *in = socket();
|
||||
QIODevice *out = m_wbMap[ wb ].first;
|
||||
if (!out)
|
||||
{
|
||||
in->write("ERROR\n");
|
||||
|
||||
wb->redirectDataHandling(false);
|
||||
return;
|
||||
}
|
||||
int size = m_wbMap[ wb ].second;
|
||||
|
||||
|
||||
QByteArray ba(10, 0);
|
||||
do
|
||||
{
|
||||
qint64 bytesRead = in->read(ba.data(), ba.size() < size ? ba.size() : size);
|
||||
if (bytesRead < 0)
|
||||
{
|
||||
in->write("ERROR\n");
|
||||
|
||||
m_wbMap.remove(wb);
|
||||
wb->redirectDataHandling(false);
|
||||
return;
|
||||
}
|
||||
size -= bytesRead;
|
||||
out->write(ba.constData(), bytesRead);
|
||||
}
|
||||
while (size > 0 && in->bytesAvailable());
|
||||
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
m_wbMap[ wb ].second = size;
|
||||
return;
|
||||
}
|
||||
out->close();
|
||||
delete out;
|
||||
|
||||
m_wbMap.remove(wb);
|
||||
wb->redirectDataHandling(false);
|
||||
}
|
||||
|
||||
QString CBI_Recvfile::help() const
|
||||
{
|
||||
return QLatin1String("RECV_FILE <filename> <filesize>");
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "tcpserver_export.h"
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
|
||||
class QIODevice;
|
||||
class CBI_Recvfile : public CommandInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CBI_Recvfile(unsigned short port);
|
||||
|
||||
void handleCommandInternal(const QVector<QByteArray> &args) override;
|
||||
QString help() const override;
|
||||
void newPlainData() override;
|
||||
protected:
|
||||
QMap<WorkerBase*, QPair<QIODevice*, int> > m_wbMap;
|
||||
};
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
|
||||
|
||||
|
||||
#include "cbi_sendfile.h"
|
||||
#include "workerbase.h"
|
||||
|
||||
#include <QtCore/QIODevice>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QFile>
|
||||
#include <stdio.h>
|
||||
|
||||
CBI_Sendfile::CBI_Sendfile(unsigned short port)
|
||||
: CommandInterface(port, "SEND_FILE")
|
||||
{}
|
||||
|
||||
void CBI_Sendfile::handleCommandInternal(const QVector<QByteArray> &args)
|
||||
{
|
||||
if (args.count() != 1)
|
||||
{
|
||||
writeError(QLatin1String("Invalid arg count: SEND_FILE <filename>"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString fn = QString::fromUtf8(args[0]);
|
||||
QFile f(fn);
|
||||
if (!f.exists())
|
||||
{
|
||||
writeError(QStringLiteral("File %1 does not exist").arg(fn));
|
||||
return;
|
||||
}
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
{
|
||||
writeError(QStringLiteral("Could not open file %1 for reading").arg(fn));
|
||||
return;
|
||||
}
|
||||
writeOk(QString::number(f.size()));
|
||||
writeEOL();
|
||||
setAutoWriteEOL(false);
|
||||
writeData(f.readAll());
|
||||
}
|
||||
|
||||
QString CBI_Sendfile::help() const
|
||||
{
|
||||
return QLatin1String("SEND_FILE <filename>");
|
||||
}
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
class CBI_Sendfile : public CommandInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CBI_Sendfile(unsigned short port);
|
||||
|
||||
void handleCommandInternal(const QVector<QByteArray> &args) override;
|
||||
QString help() const override;
|
||||
};
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
|
||||
#include "cbi_shutdown.h"
|
||||
#include "tcpserver.h"
|
||||
|
||||
CBI_Shutdown::CBI_Shutdown(unsigned short port)
|
||||
: CommandInterface(port, "SHUTDOWN")
|
||||
{
|
||||
connect(this, &CBI_Shutdown::shutdownRequest,
|
||||
TcpServer::instance(port), &TcpServer::shutdownRequest);
|
||||
}
|
||||
|
||||
void CBI_Shutdown::handleCommandInternal(const QVector<QByteArray> &)
|
||||
{
|
||||
writeOk(QLatin1String("Shutting down server - bye!"));
|
||||
closeConnection();
|
||||
emit shutdownRequest();
|
||||
}
|
||||
|
||||
QString CBI_Shutdown::help() const
|
||||
{
|
||||
return QLatin1String("SHUTDOWN - shut down the server");
|
||||
}
|
||||
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
|
||||
|
||||
class TCPSERVER_EXPORT CBI_Shutdown : public CommandInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CBI_Shutdown(unsigned short port);
|
||||
|
||||
void handleCommandInternal(const QVector<QByteArray> &args) override;
|
||||
QString help() const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
|
||||
void shutdownRequest();
|
||||
private:
|
||||
};
|
||||
Executable
+329
@@ -0,0 +1,329 @@
|
||||
|
||||
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "workerbase.h"
|
||||
#include "tcpserver.h"
|
||||
#include "tcpserver_logger.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtNetwork/QAbstractSocket>
|
||||
|
||||
class CommandInterface::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(unsigned short port_, const QByteArray &command_)
|
||||
: command(command_)
|
||||
, port(port_)
|
||||
{}
|
||||
|
||||
QByteArray m_connString;
|
||||
QByteArray command;
|
||||
QAbstractSocket *dev = nullptr;
|
||||
WorkerBase *wb = nullptr;
|
||||
int writeTimeout = 1000;
|
||||
unsigned short port;
|
||||
bool autoWriteEOL = true;
|
||||
bool bWriteError = false;
|
||||
bool closeConnection = false;
|
||||
|
||||
static QByteArray defaultSuccessMessage;
|
||||
static QByteArray defaultErrorMessage;
|
||||
};
|
||||
QByteArray CommandInterface::Private::defaultSuccessMessage("OK");
|
||||
QByteArray CommandInterface::Private::defaultErrorMessage("ERROR");
|
||||
|
||||
CommandInterface::CommandInterface(unsigned short port, const QByteArray &command)
|
||||
: d(new Private(port, command))
|
||||
{}
|
||||
|
||||
CommandInterface::~CommandInterface()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void CommandInterface::handleCommand(const QVector<QByteArray> &args)
|
||||
{
|
||||
Q_ASSERT(d->dev);
|
||||
d->bWriteError = false;
|
||||
d->closeConnection = false;
|
||||
d->m_connString = WorkerBase::formatForDebug(d->dev);
|
||||
handleCommandInternal(args);
|
||||
if (d->autoWriteEOL)
|
||||
writeEOL();
|
||||
d->dev->flush();
|
||||
if (d->closeConnection)
|
||||
{
|
||||
|
||||
d->dev->disconnectFromHost();
|
||||
|
||||
d->dev = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CommandInterface::newPlainData()
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
TCPSERVER_ERROR("CommandInterface::newData called which should never happen!");
|
||||
}
|
||||
|
||||
void CommandInterface::writeData(const char *payload)
|
||||
{
|
||||
writeData(QByteArray::fromRawData(payload, strlen(payload)));
|
||||
}
|
||||
|
||||
void CommandInterface::writeData(const QByteArray &payload)
|
||||
{
|
||||
Q_ASSERT(d->dev);
|
||||
|
||||
if (!d->dev->isOpen())
|
||||
return;
|
||||
|
||||
if (!payload.size())
|
||||
return;
|
||||
|
||||
TCPSERVER_DEBUG("Sending \'" << WorkerBase::formatForDebug(payload).constData()
|
||||
<< "\' (" << payload.size() << " Bytes) to "
|
||||
<< d->m_connString.constData())
|
||||
|
||||
qint64 bytesToWrite = payload.size();
|
||||
qint64 bytesWritten = 0;
|
||||
do
|
||||
{
|
||||
bytesWritten += d->dev->write(&payload.data()[bytesWritten], bytesToWrite - bytesWritten);
|
||||
if (!d->dev->waitForBytesWritten(d->writeTimeout))
|
||||
{
|
||||
TCPSERVER_ERROR("waitForBytesWritten returned false for connection "
|
||||
<< d->m_connString.constData()
|
||||
<< " "
|
||||
<< d->dev->error()
|
||||
<< " "
|
||||
<< d->dev->errorString())
|
||||
d->bWriteError = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (bytesToWrite != bytesWritten);
|
||||
}
|
||||
|
||||
void CommandInterface::writeData(const QString &payload)
|
||||
{
|
||||
writeData(payload.toUtf8());
|
||||
}
|
||||
|
||||
void CommandInterface::writeData(const QList<QByteArray> &payload)
|
||||
{
|
||||
QByteArray cmd;
|
||||
for (QByteArray s : payload)
|
||||
{
|
||||
s.replace('\"', "\\\"");
|
||||
if (s.contains(' '))
|
||||
s = '"' + s + '"';
|
||||
cmd += s + ' ';
|
||||
}
|
||||
writeData(cmd);
|
||||
}
|
||||
|
||||
void CommandInterface::writeData(const QStringList &payload)
|
||||
{
|
||||
QList<QByteArray> baList;
|
||||
baList.reserve(payload.size());
|
||||
for (const QString &ba : payload)
|
||||
baList += ba.toUtf8();
|
||||
writeData(baList);
|
||||
}
|
||||
|
||||
void CommandInterface::writeOk(const QString &additionalMsg)
|
||||
{
|
||||
writeData(Private::defaultSuccessMessage);
|
||||
if (!additionalMsg.isEmpty())
|
||||
{
|
||||
writeData(" ");
|
||||
writeData(additionalMsg);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandInterface::writeError(const QString &additionalMsg)
|
||||
{
|
||||
writeData(Private::defaultErrorMessage);
|
||||
if (!additionalMsg.isEmpty())
|
||||
{
|
||||
writeData(" ");
|
||||
writeData(additionalMsg);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandInterface::writeEOL()
|
||||
{
|
||||
writeData("\n");
|
||||
|
||||
Q_ASSERT(d->dev);
|
||||
d->dev->flush();
|
||||
}
|
||||
|
||||
QByteArray CommandInterface::quote(const QByteArray &payload)
|
||||
{
|
||||
static const QByteArray escapedQuote("\"");
|
||||
int idx = payload.indexOf(' ');
|
||||
if (idx < 0)
|
||||
return payload;
|
||||
QByteArray ret = payload;
|
||||
return escapedQuote + ret.replace('\"', "\\\"") + escapedQuote;
|
||||
}
|
||||
|
||||
QAbstractSocket *CommandInterface::socket()
|
||||
{
|
||||
return d->dev;
|
||||
}
|
||||
void CommandInterface::setSocket(QAbstractSocket *socket)
|
||||
{
|
||||
d->dev = socket;
|
||||
}
|
||||
|
||||
WorkerBase *CommandInterface::workerBase()
|
||||
{
|
||||
return d->wb;
|
||||
}
|
||||
|
||||
void CommandInterface::setWorkerBase(WorkerBase *wb)
|
||||
{
|
||||
d->wb = wb;
|
||||
}
|
||||
|
||||
QByteArray CommandInterface::command() const
|
||||
{
|
||||
return d->command;
|
||||
}
|
||||
|
||||
void CommandInterface::setWriteTimeout(int iMS)
|
||||
{
|
||||
d->writeTimeout = iMS < 0 ? 1000 : iMS;
|
||||
}
|
||||
|
||||
void CommandInterface::setAutoWriteEOL(bool newAutoWriteEOL)
|
||||
{
|
||||
d->autoWriteEOL = newAutoWriteEOL;
|
||||
}
|
||||
|
||||
bool CommandInterface::autoWriteEOL() const
|
||||
{
|
||||
return d->autoWriteEOL;
|
||||
}
|
||||
|
||||
bool CommandInterface::errorOccured() const
|
||||
{
|
||||
return d->bWriteError;
|
||||
}
|
||||
|
||||
void CommandInterface::setDefaultSuccessMessage(const QString &msg)
|
||||
{
|
||||
Private::defaultSuccessMessage = msg.isEmpty() ? "OK" : msg.toUtf8();
|
||||
}
|
||||
|
||||
void CommandInterface::setDefaultErrorMessage(const QString &msg)
|
||||
{
|
||||
Private::defaultErrorMessage = msg.isEmpty() ? "ERROR" : msg.toUtf8();
|
||||
}
|
||||
|
||||
unsigned short CommandInterface::port() const
|
||||
{
|
||||
return d->port;
|
||||
}
|
||||
|
||||
void CommandInterface::closeConnection()
|
||||
{
|
||||
d->closeConnection = true;
|
||||
}
|
||||
|
||||
bool CommandInterface::socketIsOpen() const
|
||||
{
|
||||
return d->dev && d->dev->isOpen();
|
||||
}
|
||||
|
||||
void CommandInterface::conversionError(const QByteArray &arg, const QByteArray &type)
|
||||
{
|
||||
writeError(QLatin1String("Can not convert ") + QString::fromUtf8(arg) +
|
||||
QLatin1String(" to ") + QString::fromUtf8(type));
|
||||
}
|
||||
|
||||
bool CommandInterface::getValue(const QByteArray &arg, bool &value)
|
||||
{
|
||||
bool bOk;
|
||||
int intValue;
|
||||
|
||||
if (arg.startsWith("0x"))
|
||||
intValue = arg.mid(2).toInt(&bOk, 16);
|
||||
else
|
||||
intValue = arg.toInt(&bOk);
|
||||
if (!bOk)
|
||||
conversionError(arg, "bool");
|
||||
value = (intValue != 0);
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool CommandInterface::getValue(const QByteArray &arg, long &value)
|
||||
{
|
||||
bool bOk;
|
||||
if (arg.startsWith("0x"))
|
||||
value = arg.mid(2).toLong(&bOk, 16);
|
||||
else
|
||||
value = arg.toLong(&bOk);
|
||||
if (!bOk)
|
||||
conversionError(arg, "long");
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool CommandInterface::getValue(const QByteArray &arg, unsigned long &value)
|
||||
{
|
||||
bool bOk;
|
||||
if (arg.startsWith("0x"))
|
||||
value = arg.mid(2).toULong(&bOk, 16);
|
||||
else
|
||||
value = arg.toUInt(&bOk);
|
||||
if (!bOk)
|
||||
conversionError(arg, "unsigned long");
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool CommandInterface::getValue(const QByteArray &arg, int &value)
|
||||
{
|
||||
bool bOk;
|
||||
if (arg.startsWith("0x"))
|
||||
value = arg.mid(2).toInt(&bOk, 16);
|
||||
else
|
||||
value = arg.toInt(&bOk);
|
||||
if (!bOk)
|
||||
conversionError(arg, "int");
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool CommandInterface::getValue(const QByteArray &arg, unsigned int &value)
|
||||
{
|
||||
bool bOk;
|
||||
if (arg.startsWith("0x"))
|
||||
value = arg.mid(2).toUInt(&bOk, 16);
|
||||
else
|
||||
value = arg.toUInt(&bOk);
|
||||
if (!bOk)
|
||||
conversionError(arg, "unsigned int");
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool CommandInterface::getValue(const QByteArray &arg, float &value)
|
||||
{
|
||||
bool bOk;
|
||||
value = arg.toFloat(&bOk);
|
||||
if (!bOk)
|
||||
conversionError(arg, "float");
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool CommandInterface::getValue(const QByteArray &arg, double &value)
|
||||
{
|
||||
bool bOk;
|
||||
value = arg.toDouble(&bOk);
|
||||
if (!bOk)
|
||||
conversionError(arg, "double");
|
||||
return bOk;
|
||||
}
|
||||
Executable
+158
@@ -0,0 +1,158 @@
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
class QAbstractSocket;
|
||||
class QByteArray;
|
||||
class WorkerBase;
|
||||
|
||||
|
||||
class TCPSERVER_EXPORT CommandInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
|
||||
explicit CommandInterface(unsigned short port, const QByteArray &command = QByteArray());
|
||||
|
||||
|
||||
|
||||
virtual ~CommandInterface();
|
||||
|
||||
|
||||
void handleCommand(const QVector<QByteArray> &args);
|
||||
|
||||
|
||||
virtual void newPlainData();
|
||||
|
||||
|
||||
virtual QString help() const = 0;
|
||||
|
||||
|
||||
QByteArray command() const;
|
||||
|
||||
|
||||
|
||||
void setAutoWriteEOL(bool newAutoWriteEOL);
|
||||
|
||||
|
||||
|
||||
bool autoWriteEOL() const;
|
||||
|
||||
|
||||
|
||||
bool errorOccured() const;
|
||||
|
||||
|
||||
|
||||
static void setDefaultSuccessMessage(const QString &msg);
|
||||
|
||||
|
||||
|
||||
static void setDefaultErrorMessage(const QString &msg);
|
||||
|
||||
template<class T>
|
||||
static CommandInterface *factory(unsigned short port) { return new T(port); }
|
||||
|
||||
|
||||
|
||||
virtual void aboutToDestroy() {}
|
||||
protected:
|
||||
|
||||
|
||||
virtual void handleCommandInternal(const QVector<QByteArray> &args) = 0;
|
||||
|
||||
|
||||
void setWriteTimeout(int iMS);
|
||||
|
||||
|
||||
void writeData(const QByteArray &payload);
|
||||
|
||||
|
||||
void writeData(const char *payload);
|
||||
|
||||
|
||||
void writeData(const QString &payload);
|
||||
|
||||
|
||||
void writeData(const QStringList &payload);
|
||||
|
||||
|
||||
void writeData(const QList<QByteArray> &payload);
|
||||
|
||||
|
||||
void writeOk(const QString &additionalMsg = QString());
|
||||
|
||||
|
||||
void writeError(const QString &additionalMsg = QString());
|
||||
|
||||
|
||||
void writeEOL();
|
||||
|
||||
|
||||
QByteArray quote(const QByteArray &payload);
|
||||
|
||||
|
||||
QAbstractSocket *socket();
|
||||
|
||||
|
||||
void setSocket(QAbstractSocket *socket);
|
||||
|
||||
|
||||
WorkerBase *workerBase();
|
||||
|
||||
|
||||
void setWorkerBase(WorkerBase *wb);
|
||||
|
||||
|
||||
void conversionError(const QByteArray &arg, const QByteArray &type);
|
||||
|
||||
|
||||
bool getValue(const QByteArray &arg, bool &value);
|
||||
|
||||
|
||||
bool getValue(const QByteArray &arg, long &value);
|
||||
|
||||
|
||||
bool getValue(const QByteArray &arg, unsigned long &value);
|
||||
|
||||
|
||||
bool getValue(const QByteArray &arg, int &value);
|
||||
|
||||
|
||||
bool getValue(const QByteArray &arg, unsigned int &value);
|
||||
|
||||
|
||||
bool getValue(const QByteArray &arg, float &value);
|
||||
|
||||
|
||||
bool getValue(const QByteArray &arg, double &value);
|
||||
|
||||
|
||||
|
||||
unsigned short port() const;
|
||||
|
||||
|
||||
|
||||
void closeConnection();
|
||||
|
||||
|
||||
|
||||
bool socketIsOpen() const;
|
||||
|
||||
private:
|
||||
friend class WorkerBase;
|
||||
|
||||
class Private;
|
||||
|
||||
|
||||
Private *const d;
|
||||
};
|
||||
Executable
+209
@@ -0,0 +1,209 @@
|
||||
|
||||
|
||||
|
||||
#include "tcpserver.h"
|
||||
#include "tcpserver_logger.h"
|
||||
#include "workerbase.h"
|
||||
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
NGL::INGLLogger &getTcpServerLogger()
|
||||
{
|
||||
static NGL::INGLLogger *tcpserver_logger_ptr = nullptr;
|
||||
if (!tcpserver_logger_ptr)
|
||||
tcpserver_logger_ptr = &NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("tcpserver");
|
||||
return *tcpserver_logger_ptr;
|
||||
}
|
||||
|
||||
typedef QHash< unsigned short, TcpServer::CommandInterfaceList > CommandFactory;
|
||||
class TcpServer::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(unsigned short port_)
|
||||
: mUserData(nullptr)
|
||||
, port(port_)
|
||||
, bUseThreads(false)
|
||||
{}
|
||||
~Private()
|
||||
{
|
||||
const auto copy(workers);
|
||||
for (WorkerInstance *worker : copy)
|
||||
{
|
||||
|
||||
QThread *workerThread = worker->thread();
|
||||
if (workerThread != qApp->thread())
|
||||
{
|
||||
QTimer::singleShot(0, worker, &WorkerInstance::deleteLater);
|
||||
workerThread->wait();
|
||||
}
|
||||
else
|
||||
delete worker;
|
||||
}
|
||||
workers.clear();
|
||||
}
|
||||
|
||||
QVector<WorkerInstance *> workers;
|
||||
void *mUserData;
|
||||
unsigned short port;
|
||||
bool bUseThreads;
|
||||
|
||||
static QHash<int, TcpServer *> s_servers;
|
||||
static CommandFactory s_cbFactory;
|
||||
};
|
||||
QHash<int, TcpServer *> TcpServer::Private::s_servers;
|
||||
CommandFactory TcpServer::Private::s_cbFactory;
|
||||
|
||||
TcpServer::TcpServer(unsigned short port)
|
||||
: QTcpServer()
|
||||
, d(new Private(port))
|
||||
{
|
||||
TCPSERVER_TRACE2("Port: " << port);
|
||||
}
|
||||
|
||||
TcpServer::~TcpServer()
|
||||
{
|
||||
TCPSERVER_TRACE
|
||||
Private::s_servers.remove(d->port);
|
||||
delete d;
|
||||
}
|
||||
|
||||
TcpServer *TcpServer::instance(unsigned short port)
|
||||
{
|
||||
if (!Private::s_servers.contains(port))
|
||||
Private::s_servers.insert(port, new TcpServer(port));
|
||||
|
||||
return Private::s_servers[ port ];
|
||||
}
|
||||
|
||||
bool TcpServer::listen(const QHostAddress &address)
|
||||
{
|
||||
TCPSERVER_TRACE2("address: " << address);
|
||||
return QTcpServer::listen(address, d->port);
|
||||
}
|
||||
|
||||
void TcpServer::setUseWorkerThreads(bool bEnable)
|
||||
{
|
||||
TCPSERVER_TRACE2("bEnable: " << bEnable);
|
||||
d->bUseThreads = bEnable;
|
||||
}
|
||||
|
||||
bool TcpServer::useWorkerThreads() const
|
||||
{
|
||||
return d->bUseThreads;
|
||||
}
|
||||
|
||||
QVector<WorkerInstance *> TcpServer::workers() const
|
||||
{
|
||||
return d->workers;
|
||||
}
|
||||
|
||||
unsigned short TcpServer::getListenPort() const
|
||||
{
|
||||
return d->port;
|
||||
}
|
||||
|
||||
bool TcpServer::registerCommand(unsigned short port, CommandInterface * (*factory)(unsigned short))
|
||||
{
|
||||
CommandInterfaceList &factoryList = Private::s_cbFactory[port];
|
||||
if (factoryList.contains(factory))
|
||||
{
|
||||
TCPSERVER_ERROR("Factory " << (void *)factory << " already registered!")
|
||||
return false;
|
||||
}
|
||||
factoryList.append(factory);
|
||||
TCPSERVER_DEBUG("Added Factory " << (void *)factory << " for port " << port)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TcpServer::unregisterCommand(unsigned short port, CommandInterface * (*factory)(unsigned short))
|
||||
{
|
||||
CommandInterfaceList &factoryList = Private::s_cbFactory[port];
|
||||
if (!factoryList.contains(factory))
|
||||
{
|
||||
TCPSERVER_WARN("Trying to unregister factory " << (void *)factory << " for port " << port << " which is not registered!")
|
||||
return false;
|
||||
}
|
||||
TCPSERVER_INFO("Removed Factory " << (void *)factory << " for port " << port)
|
||||
factoryList.removeAll(factory);
|
||||
return true;
|
||||
}
|
||||
|
||||
TcpServer::CommandInterfaceList TcpServer::registeredCommands(unsigned short port)
|
||||
{
|
||||
return Private::s_cbFactory[port];
|
||||
}
|
||||
|
||||
void TcpServer::incomingConnection(qintptr socketDescriptor)
|
||||
{
|
||||
|
||||
WorkerInstance *worker = new WorkerInstance(socketDescriptor, d->port);
|
||||
connect(worker, &WorkerInstance::finished, this, &TcpServer::workerFinished);
|
||||
d->workers += worker;
|
||||
|
||||
if (d->bUseThreads)
|
||||
{
|
||||
QThread *workerThread = new QThread(this);
|
||||
|
||||
connect(workerThread, &QThread::started, worker, &WorkerInstance::doWork);
|
||||
connect(workerThread, &QThread::finished, worker, &WorkerInstance::quit);
|
||||
worker->moveToThread(workerThread);
|
||||
|
||||
workerThread->start();
|
||||
|
||||
|
||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||
TCPSERVER_DEBUG("Created new WorkerThread " << worker)
|
||||
}
|
||||
else
|
||||
{
|
||||
QTimer::singleShot(0, worker, &WorkerInstance::doWork);
|
||||
TCPSERVER_DEBUG("Created new WorkerInstance " << worker)
|
||||
}
|
||||
}
|
||||
|
||||
void TcpServer::workerFinished()
|
||||
{
|
||||
WorkerInstance *wi = qobject_cast<WorkerInstance *>(sender());
|
||||
if (wi)
|
||||
{
|
||||
if (!d->workers.removeAll(wi))
|
||||
TCPSERVER_WARN("Got a signal that a worker exited, but could not find it in our list!")
|
||||
wi->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
TCPSERVER_WARN("Got a signal that a worker exited, but it's neither a WorkerInstance nor WorkerThread!")
|
||||
}
|
||||
}
|
||||
|
||||
void TcpServer::shutdownRequest()
|
||||
{
|
||||
emit aboutToQuit(d->port);
|
||||
for (WorkerBase *worker : qAsConst(d->workers))
|
||||
{
|
||||
WorkerInstance *wi = dynamic_cast<WorkerInstance *>(worker);
|
||||
if (wi)
|
||||
{
|
||||
wi->quit();
|
||||
while (!wi->isFinished())
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
close();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void TcpServer::setUserData(void *userData)
|
||||
{
|
||||
d->mUserData = userData;
|
||||
}
|
||||
|
||||
void *TcpServer::userData() const
|
||||
{
|
||||
return d->mUserData;
|
||||
}
|
||||
Executable
+96
@@ -0,0 +1,96 @@
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTcpServer>
|
||||
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
class WorkerInstance;
|
||||
class CommandInterface;
|
||||
|
||||
|
||||
|
||||
class TCPSERVER_EXPORT TcpServer : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QVector<CommandInterface*(*)(unsigned short) > CommandInterfaceList;
|
||||
public:
|
||||
|
||||
|
||||
virtual ~TcpServer();
|
||||
|
||||
|
||||
static TcpServer *instance(unsigned short port);
|
||||
|
||||
|
||||
|
||||
bool listen(const QHostAddress &address = QHostAddress::Any);
|
||||
|
||||
|
||||
|
||||
void setUseWorkerThreads(bool bEnable);
|
||||
|
||||
|
||||
|
||||
bool useWorkerThreads() const;
|
||||
|
||||
|
||||
|
||||
QVector<WorkerInstance *> workers() const;
|
||||
|
||||
|
||||
|
||||
unsigned short getListenPort() const;
|
||||
|
||||
|
||||
|
||||
static bool registerCommand(unsigned short port, CommandInterface * (*factory)(unsigned short));
|
||||
|
||||
|
||||
|
||||
static bool unregisterCommand(unsigned short port, CommandInterface * (*factory)(unsigned short));
|
||||
|
||||
|
||||
|
||||
static CommandInterfaceList registeredCommands(unsigned short port);
|
||||
|
||||
|
||||
|
||||
void setUserData(void *userData);
|
||||
|
||||
|
||||
|
||||
void *userData() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
|
||||
void aboutToQuit(unsigned short port);
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
|
||||
void shutdownRequest();
|
||||
|
||||
|
||||
void workerFinished();
|
||||
|
||||
protected:
|
||||
void incomingConnection(qintptr socketDescriptor);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
||||
|
||||
Private *const d;
|
||||
|
||||
explicit TcpServer(unsigned short port);
|
||||
|
||||
|
||||
|
||||
bool listen(const QHostAddress &address, quint16 port);
|
||||
};
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
#ifndef TCPSERVER_EXPORT_H
|
||||
#define TCPSERVER_EXPORT_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#define TCPSERVER_VERSION_MAJ 0
|
||||
#define TCPSERVER_VERSION_MIN 0
|
||||
#define TCPSERVER_VERSION_REL 3
|
||||
#define TCPSERVER_VERSION (((TCPSERVER_VERSION_MAJ) << 16) | ((TCPSERVER_VERSION_MIN) << 8) | (TCPSERVER_VERSION_REL))
|
||||
|
||||
#ifndef TCPSERVER_STATIC
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define TCPSERVER_EXPORT
|
||||
# else
|
||||
# ifdef MAKE_TCPSERVER_LIB
|
||||
# define TCPSERVER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define TCPSERVER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# define TCPSERVER_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <ostream>
|
||||
|
||||
#ifdef Q_CC_GNU
|
||||
#define TCPSERVER_TRACE_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define TCPSERVER_TRACE_FUNCTION __FUNCTION__
|
||||
#endif
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
NGL::INGLLogger &getTcpServerLogger();
|
||||
|
||||
#ifdef TCPSERVER_ENABLE_TRACE
|
||||
#define TCPSERVER_TRACE { TRACE_LOG(getTcpServerLogger()) << TCPSERVER_TRACE_FUNCTION; }
|
||||
#define TCPSERVER_TRACE2(x) { TRACE_LOG(getTcpServerLogger()) << TCPSERVER_TRACE_FUNCTION << x; }
|
||||
#else
|
||||
#define TCPSERVER_TRACE
|
||||
#define TCPSERVER_TRACE2(x)
|
||||
#endif
|
||||
#define TCPSERVER_DEBUG(y) { DEBUG_LOG (getTcpServerLogger()) << y; }
|
||||
#define TCPSERVER_INFO(y) { INFO_LOG (getTcpServerLogger()) << y; }
|
||||
#define TCPSERVER_WARN(y) { WARNING_LOG (getTcpServerLogger()) << y; }
|
||||
#define TCPSERVER_ERROR(y) { ERROR_LOG (getTcpServerLogger()) << y; }
|
||||
#define TCPSERVER_FATAL(y) { FATAL_LOG (getTcpServerLogger()) << y; }
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
#include "tcpserver.h"
|
||||
#include "cbi_help.h"
|
||||
#include "cbi_pingpong.h"
|
||||
#include "cbi_quit.h"
|
||||
#include "cbi_recvfile.h"
|
||||
#include "cbi_sendfile.h"
|
||||
#include "cbi_shutdown.h"
|
||||
#include "workerbase.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGL::NGLLoggerBootstrap::createNGLRootLogger("tcpserver_test.props", false);
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
QSettings settings(QLatin1String("./settings.ini"), QSettings::IniFormat);
|
||||
unsigned int port = settings.value(QLatin1String("port"), 4711).toInt();
|
||||
|
||||
TcpServer::registerCommand(port, CommandInterface::factory<CBI_Help>);
|
||||
TcpServer::registerCommand(port, CommandInterface::factory<CBI_PingPong>);
|
||||
TcpServer::registerCommand(port, CommandInterface::factory<CBI_Quit>);
|
||||
TcpServer::registerCommand(port, CommandInterface::factory<CBI_Recvfile>);
|
||||
TcpServer::registerCommand(port, CommandInterface::factory<CBI_Sendfile>);
|
||||
TcpServer::registerCommand(port, CommandInterface::factory<CBI_Shutdown>);
|
||||
|
||||
TcpServer *tcpServer = TcpServer::instance(port);
|
||||
tcpServer->setUseWorkerThreads(true);
|
||||
|
||||
if (!tcpServer->listen(QHostAddress::LocalHost))
|
||||
{
|
||||
qFatal("Error listening on port %d, error: %d", port, tcpServer->serverError());
|
||||
delete tcpServer;
|
||||
return 1;
|
||||
}
|
||||
QObject::connect(tcpServer, &TcpServer::destroyed, &app, &QCoreApplication::quit);
|
||||
|
||||
int ret = app.exec();
|
||||
return ret;
|
||||
}
|
||||
Executable
+304
@@ -0,0 +1,304 @@
|
||||
|
||||
|
||||
|
||||
#include "workerbase.h"
|
||||
|
||||
#include "commandinterface.h"
|
||||
#include "tcpserver.h"
|
||||
#include "tcpserver_logger.h"
|
||||
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <QtNetwork/QAbstractSocket>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <ngltools/ngltools_convert.h>
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
WorkerBase::WorkerBase(qintptr sd, unsigned short port)
|
||||
: m_socketDescriptor(sd)
|
||||
, m_connection(nullptr)
|
||||
, m_port(port)
|
||||
, m_bRedirectIncomingData(false)
|
||||
, m_bRedirectDataHandler(nullptr)
|
||||
{}
|
||||
|
||||
QAbstractSocket *WorkerBase::connection()
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
const QAbstractSocket *WorkerBase::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void WorkerBase::newDataInternal()
|
||||
{
|
||||
|
||||
if (m_bRedirectIncomingData)
|
||||
{
|
||||
if (m_bRedirectDataHandler)
|
||||
m_bRedirectDataHandler->newPlainData();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_connection || !m_connection->isOpen())
|
||||
return;
|
||||
|
||||
while (m_connection && m_connection->canReadLine())
|
||||
{
|
||||
QByteArray ba(2048, '\0');
|
||||
bool bGotEOL = false;
|
||||
int iOffset = 0;
|
||||
do
|
||||
{
|
||||
qint64 length = m_connection->readLine(ba.data() + iOffset, ba.size());
|
||||
if (length < 0)
|
||||
{
|
||||
TCPSERVER_ERROR("Error reading data from " << m_connString.constData()
|
||||
<< qPrintable(m_connection->errorString()))
|
||||
return;
|
||||
}
|
||||
bGotEOL = ba.contains('\n');
|
||||
if (bGotEOL)
|
||||
{
|
||||
|
||||
ba.resize(iOffset + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
iOffset = ba.size();
|
||||
ba.resize(ba.size() * 2);
|
||||
|
||||
memset(ba.data() + iOffset, 0, ba.size() - iOffset);
|
||||
}
|
||||
}
|
||||
while (!bGotEOL);
|
||||
|
||||
|
||||
while (ba.endsWith('\r') || ba.endsWith('\n'))
|
||||
{
|
||||
ba.data() [ba.size() - 1] = '\0';
|
||||
ba.resize(ba.size() - 1);
|
||||
}
|
||||
|
||||
int idx = ba.indexOf(' ');
|
||||
if (idx == -1)
|
||||
idx = ba.size();
|
||||
|
||||
QByteArray command = ba.left(idx);
|
||||
if (command.isEmpty())
|
||||
{
|
||||
TCPSERVER_DEBUG("Got empty command from connection " << m_connString.constData())
|
||||
continue;
|
||||
}
|
||||
|
||||
CommandMap::ConstIterator it = m_registeredCommands.constFind(command.toLower());
|
||||
if (it == m_registeredCommands.constEnd())
|
||||
{
|
||||
TCPSERVER_WARN("Got unknown command " << formatForDebug(command).constData()
|
||||
<< " from connection "
|
||||
<< m_connString.constData())
|
||||
m_connection->write("UNKNOWN COMMAND ");
|
||||
m_connection->write(command);
|
||||
m_connection->write("\n");
|
||||
if (!m_connection->waitForBytesWritten(1000))
|
||||
{
|
||||
TCPSERVER_WARN("waitForBytesWritten returned false for connection "
|
||||
<< m_connString.constData()
|
||||
<< " "
|
||||
<< m_connection->error()
|
||||
<< " "
|
||||
<< m_connection->errorString())
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TCPSERVER_DEBUG("Got command " << formatForDebug(command).constData()
|
||||
<< " from connection "
|
||||
<< m_connString.constData())
|
||||
|
||||
CommandInterface *interface = *it;
|
||||
const QVector<QByteArray> args = NGL::parseFromTelnet(ba, idx + 1);
|
||||
interface->handleCommand(args);
|
||||
if (interface->errorOccured())
|
||||
{
|
||||
TCPSERVER_ERROR("Write error occured on connection " << m_connString.constData())
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bRedirectIncomingData && m_connection && m_connection->bytesAvailable())
|
||||
{
|
||||
if (m_bRedirectDataHandler)
|
||||
m_bRedirectDataHandler->newPlainData();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerBase::redirectDataHandling(bool bDoRedirect, CommandInterface *newDataHandler)
|
||||
{
|
||||
m_bRedirectIncomingData = bDoRedirect;
|
||||
m_bRedirectDataHandler = newDataHandler;
|
||||
|
||||
if (!bDoRedirect)
|
||||
newDataInternal();
|
||||
}
|
||||
|
||||
QByteArray WorkerBase::formatForDebug(const QByteArray &data)
|
||||
{
|
||||
const int size = data.size();
|
||||
QByteArray ret;
|
||||
ret.reserve(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
const unsigned char c = data[i];
|
||||
if (c < ' ' || c >= 0x7f)
|
||||
ret += "\\x" + QByteArray::number(c, 16);
|
||||
else
|
||||
ret += c;
|
||||
if (i > 31)
|
||||
{
|
||||
ret += "...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WorkerBase::CommandMap WorkerBase::getCommands() const
|
||||
{
|
||||
return m_registeredCommands;
|
||||
}
|
||||
|
||||
QByteArray WorkerBase::formatForDebug(const QAbstractSocket *dev)
|
||||
{
|
||||
const QAbstractSocket *socket = qobject_cast<const QAbstractSocket *>(dev);
|
||||
if (socket)
|
||||
return socket->peerAddress().toString().toUtf8() + ":" + QByteArray::number(socket->peerPort());
|
||||
try
|
||||
{
|
||||
return typeid(*dev).name();
|
||||
}
|
||||
catch (std::bad_typeid &e)
|
||||
{
|
||||
TCPSERVER_ERROR("TcpSocket null? - " << e.what())
|
||||
}
|
||||
return "<NULL>";
|
||||
}
|
||||
|
||||
int WorkerBase::initCommands(unsigned short port)
|
||||
{
|
||||
const TcpServer::CommandInterfaceList cbList = TcpServer::registeredCommands(port);
|
||||
TcpServer::CommandInterfaceList::ConstIterator it = cbList.begin();
|
||||
TcpServer::CommandInterfaceList::ConstIterator end = cbList.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
CommandInterface *(*factory)(unsigned short) = *it;
|
||||
CommandInterface *cbi = factory(port);
|
||||
cbi->setWorkerBase(this);
|
||||
cbi->setSocket(m_connection);
|
||||
m_registeredCommands.insert(cbi->command().toLower(), cbi);
|
||||
}
|
||||
return m_registeredCommands.count();
|
||||
}
|
||||
|
||||
void WorkerBase::cleanupCommands()
|
||||
{
|
||||
CommandMap::ConstIterator it = m_registeredCommands.constBegin();
|
||||
CommandMap::ConstIterator end = m_registeredCommands.constEnd();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (*it)
|
||||
{
|
||||
(*it)->aboutToDestroy();
|
||||
(*it)->deleteLater();
|
||||
}
|
||||
}
|
||||
m_registeredCommands.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
WorkerInstance::WorkerInstance(qintptr sd, unsigned short port, QObject *parent)
|
||||
: QObject(parent)
|
||||
, WorkerBase(sd, port)
|
||||
, m_bFinished(false)
|
||||
{}
|
||||
|
||||
WorkerInstance::~WorkerInstance()
|
||||
{
|
||||
if (m_connection && m_connection->state() != QAbstractSocket::UnconnectedState)
|
||||
{
|
||||
m_connection->disconnectFromHost();
|
||||
if (m_connection)
|
||||
m_connection->waitForDisconnected();
|
||||
}
|
||||
cleanupCommands();
|
||||
|
||||
delete m_connection;
|
||||
m_connection = nullptr;
|
||||
}
|
||||
|
||||
void WorkerInstance::doWork()
|
||||
{
|
||||
m_connection = new QTcpSocket(this);
|
||||
initCommands(m_port);
|
||||
if (!m_connection->setSocketDescriptor(m_socketDescriptor))
|
||||
{
|
||||
m_connString = formatForDebug(m_connection);
|
||||
TCPSERVER_ERROR("Connection to " << m_connString.constData()
|
||||
<< " failed - Aborting ("
|
||||
<< m_connection->error() << ")")
|
||||
return;
|
||||
}
|
||||
m_connString = formatForDebug(m_connection);
|
||||
TCPSERVER_DEBUG("New incoming connection from "
|
||||
<< m_connString.constData()
|
||||
<< " to " << m_connection->localAddress().toString().toUtf8().constData()
|
||||
<< ":" << m_connection->localPort());
|
||||
connect(m_connection.data(), &QTcpSocket::readyRead, this, &WorkerInstance::newData);
|
||||
connect(m_connection.data(), &QTcpSocket::disconnected, this, &WorkerInstance::connectionDisconnected);
|
||||
}
|
||||
|
||||
void WorkerInstance::newData()
|
||||
{
|
||||
WorkerBase::newDataInternal();
|
||||
}
|
||||
|
||||
void WorkerInstance::connectionDisconnected()
|
||||
{
|
||||
TCPSERVER_DEBUG(m_connString.constData() << " closed - exiting instance " << this);
|
||||
if (m_connection)
|
||||
m_connection->deleteLater();
|
||||
m_connection = nullptr;
|
||||
m_bFinished = true;
|
||||
|
||||
QThread *workerThread = QThread::currentThread();
|
||||
if (workerThread != qApp->thread())
|
||||
{
|
||||
workerThread->disconnect(this);
|
||||
workerThread->quit();
|
||||
}
|
||||
emit finished();
|
||||
}
|
||||
|
||||
bool WorkerInstance::isRunning() const
|
||||
{
|
||||
return m_connection && m_connection->isOpen();
|
||||
}
|
||||
|
||||
bool WorkerInstance::isFinished() const
|
||||
{
|
||||
return m_bFinished;
|
||||
}
|
||||
|
||||
void WorkerInstance::quit()
|
||||
{
|
||||
if (m_connection)
|
||||
m_connection->close();
|
||||
}
|
||||
Executable
+127
@@ -0,0 +1,127 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMap>
|
||||
#include <QPointer>
|
||||
|
||||
#include "tcpserver_export.h"
|
||||
|
||||
class QAbstractSocket;
|
||||
class CommandInterface;
|
||||
|
||||
|
||||
|
||||
class TCPSERVER_EXPORT WorkerBase
|
||||
{
|
||||
public:
|
||||
typedef QMap< QByteArray, CommandInterface *> CommandMap;
|
||||
public:
|
||||
|
||||
|
||||
WorkerBase(qintptr sd, unsigned short port);
|
||||
|
||||
|
||||
virtual ~WorkerBase() = default;
|
||||
|
||||
|
||||
QAbstractSocket *connection();
|
||||
|
||||
|
||||
|
||||
const QAbstractSocket *connection() const;
|
||||
|
||||
|
||||
|
||||
void redirectDataHandling(bool bDoRedirect, CommandInterface *newDataHandler = nullptr);
|
||||
|
||||
|
||||
|
||||
static QByteArray formatForDebug(const QByteArray &data);
|
||||
|
||||
|
||||
|
||||
static QByteArray formatForDebug(const QAbstractSocket *dev);
|
||||
|
||||
|
||||
|
||||
CommandMap getCommands() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
void newDataInternal();
|
||||
|
||||
|
||||
int initCommands(unsigned short port);
|
||||
|
||||
|
||||
|
||||
void cleanupCommands();
|
||||
|
||||
|
||||
|
||||
qintptr m_socketDescriptor;
|
||||
|
||||
|
||||
QPointer<QAbstractSocket> m_connection;
|
||||
|
||||
|
||||
unsigned short m_port;
|
||||
|
||||
|
||||
QByteArray m_connString;
|
||||
|
||||
|
||||
bool m_bRedirectIncomingData;
|
||||
|
||||
|
||||
CommandInterface *m_bRedirectDataHandler;
|
||||
|
||||
|
||||
|
||||
CommandMap m_registeredCommands;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WorkerInstance final : public QObject, public WorkerBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WorkerInstance(qintptr sd, unsigned short port, QObject *parent = nullptr);
|
||||
virtual ~WorkerInstance();
|
||||
|
||||
|
||||
|
||||
bool isRunning() const;
|
||||
|
||||
|
||||
bool isFinished() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
|
||||
void quit();
|
||||
|
||||
|
||||
|
||||
void doWork();
|
||||
|
||||
protected Q_SLOTS:
|
||||
|
||||
|
||||
void newData();
|
||||
|
||||
|
||||
void connectionDisconnected();
|
||||
|
||||
Q_SIGNALS:
|
||||
void finished();
|
||||
|
||||
private:
|
||||
bool m_bFinished;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user