Adds q2 repos to migrate

This commit is contained in:
torsten committed 2026-07-14 12:07:36 +02:00
1 parent ad1f62c4ee
commit 17f1c61c9e
991 files changed
+178451

No files matched your search

+56
View File
@@ -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()
+29
View File
@@ -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");
}
+19
View File
@@ -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;
};
+23
View File
@@ -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");
}
+19
View File
@@ -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;
};
+19
View File
@@ -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");
}
+19
View File
@@ -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;
};
+86
View File
@@ -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>");
}
+23
View File
@@ -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;
};
+45
View File
@@ -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>");
}
+17
View File
@@ -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;
};
+25
View File
@@ -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");
}
+25
View File
@@ -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:
};
+329
View File
@@ -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;
}
+158
View File
@@ -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;
};
+209
View File
@@ -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;
}
+96
View File
@@ -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);
};
+27
View File
@@ -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
+27
View File
@@ -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; }
+43
View File
@@ -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;
}
+304
View File
@@ -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();
}
+127
View File
@@ -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;
};