#include "PrtCnvSocketThread.hpp" #include "PrtCnvDbThread.hpp" #include "PrtCnvTelegramLogThread.hpp" #include "PrtCnvThreadStarter.hpp" #include "PrtCnvInjectionThread.hpp" #include #include namespace PrtCnv { PrtCnvSocketThread::PrtCnvSocketThread(PrtCnv::PrtCnvThreadStarter* a_parent, const char *loggerName) : PrtCnvThread(a_parent, loggerName) , m_ConnectionTimer(nullptr) , m_Socket(nullptr) , m_TickTimer(nullptr) , m_ReceiveCounter(0) , m_ReceiveAckCounter(0) , m_State(PrtCnvSocketThread::e_INITIAL) , m_DbThread(nullptr) , m_ConnectTimeout(2000) , m_DisconnectTimeout(10000) , m_AliveTimeout(3000) , m_TickTimeout(900) , m_DoCleanup(false) , m_LogThread(nullptr) , m_InjectionThread(nullptr) , m_currentHostAdressIndex(0) {} PrtCnvSocketThread::~PrtCnvSocketThread() { cleanup(); } int32_t PrtCnvSocketThread::create(NGL::Settings *settings) { PrtCnvThread::create(settings); createNewSocket(); m_ConnectionTimer = new QTimer(this); connect(m_ConnectionTimer, &QTimer::timeout, this, &PrtCnvSocketThread::timeoutAliveAndConnection); m_TickTimer = new QTimer(this); connect(m_TickTimer, &QTimer::timeout, this, &PrtCnvSocketThread::timeoutTick); m_DbThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Db)); m_LogThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Log)); m_InjectionThread = qobject_cast(m_Parent->getOtherThread(PrtCnvApplication::e_Injection)); return 0; } void PrtCnvSocketThread::createNewSocket() { INFO_LOG(m_logger) << "createNewSocket m_oldSocket=" << m_Socket; Q_ASSERT(QThread::currentThreadId() == m_currentThreadId); if (m_Socket) { m_Socket->disconnectFromHost(); m_Socket->disconnect(); if (m_Socket->state() != QAbstractSocket::UnconnectedState) m_Socket->waitForDisconnected(); m_Socket->deleteLater(); } m_Socket = new QTcpSocket(this); qRegisterMetaType("QAbstractSocket::SocketError"); qRegisterMetaType("QAbstractSocket::SocketState"); connect(m_Socket, &QTcpSocket::connected, this, &PrtCnvSocketThread::connected, Qt::QueuedConnection); connect(m_Socket, &QTcpSocket::disconnected, this, &PrtCnvSocketThread::disconnected, Qt::QueuedConnection); connect(m_Socket, QOverload::of(&QTcpSocket::error), this, &PrtCnvSocketThread::error, Qt::QueuedConnection); connect(m_Socket, &QTcpSocket::hostFound, this, &PrtCnvSocketThread::hostFound, Qt::QueuedConnection); connect(m_Socket, &QTcpSocket::stateChanged, this, &PrtCnvSocketThread::stateChanged); connect(m_Socket, &QTcpSocket::readyRead, this, &PrtCnvSocketThread::readyRead, Qt::QueuedConnection); } int32_t PrtCnvSocketThread::destroy() { PrtCnvThread::destroy(); cleanup(); return 0; } void PrtCnvSocketThread::cleanup() { delete m_Socket; m_Socket = nullptr; delete m_ConnectionTimer; m_ConnectionTimer = nullptr; delete m_TickTimer; m_TickTimer = nullptr; } int32_t PrtCnvSocketThread::init() { INFO_LOG(m_logger) << "PrtCnvSocketThread::init()"; PrtCnvThread::init(); m_State = e_INITIAL; m_ConnectTimeout = m_Config->getInteger(getName(), QStringLiteral("ConnectTimeout"), 2000); m_DisconnectTimeout = m_Config->getInteger(getName(), QStringLiteral("DisconnectTimeout"), 10000); m_AliveTimeout = m_Config->getInteger(getName(), QStringLiteral("AliveTimeout"), 3000); return 0; } void PrtCnvSocketThread::connectSocket() { int sockState = m_Socket ? m_Socket->state() : -1; INFO_LOG(m_logger) << "connectSocket m_Socket=" << m_Socket << " state=" << m_State << " socketState=" << sockState; if (e_WORKING != m_State && e_REGISTERING != m_State) { if (m_Socket) { m_Socket->disconnectFromHost(); if (m_Socket->state() != QAbstractSocket::UnconnectedState) m_Socket->waitForDisconnected(); } createNewSocket(); if(m_hostAdresses.isEmpty()) readHostAdresses(); const QString hostname = m_hostAdresses.at(m_currentHostAdressIndex).first; const uint16_t port = m_hostAdresses.at(m_currentHostAdressIndex).second; m_currentHostAdressIndex = ((m_currentHostAdressIndex + 1) % m_hostAdresses.size()); INFO_LOG(m_logger) << "Connecting to " << hostname << ":" << port << " m_Socket=" << m_Socket; m_Socket->connectToHost(hostname, port); m_State = e_CONNECTING; startConnectionTimer(); } else { WARNING_LOG(m_logger) << getName() << ": connectSocket called, but m_State is " << m_State; } } void PrtCnvSocketThread::disconnectSocket() { m_Socket->disconnectFromHost(); startDisconnectionTimer(); m_State = e_DISCONNECTING; } void PrtCnvSocketThread::connected() { INFO_LOG(m_logger) << "connected (implement connected() in inherited class, if you want use this signal...)"; } void PrtCnvSocketThread::disconnected() { INFO_LOG(m_logger) << "got signal 'disconnected' (implement disconnected() in inherited class, if you want use this signal...)"; } void PrtCnvSocketThread::readyRead() { INFO_LOG(m_logger) << "got signal 'newData' (implement newData() in inherited class, if you want use this signal...)"; } void PrtCnvSocketThread::timeoutAliveAndConnection() { INFO_LOG(m_logger) << "got signal 'reconnectTimeout' (implement reconnectTimeout() in inherited class, if you want use this signal...)"; } void PrtCnvSocketThread::error(QAbstractSocket::SocketError a_socketError) { switch (a_socketError) { case QAbstractSocket::ConnectionRefusedError: ERROR_LOG(m_logger) << getName() << ": ConnectionRefusedError m_State=" << m_State; break; case QAbstractSocket::RemoteHostClosedError: ERROR_LOG(m_logger) << getName() << ": RemoteHostClosedError"; break; case QAbstractSocket::HostNotFoundError: break; default: ERROR_LOG(m_logger) << getName() << ": got signal 'error(QAbstractSocket::SocketError=" << a_socketError << ")'"; } } void PrtCnvSocketThread::hostFound() { } void PrtCnvSocketThread::stateChanged(QAbstractSocket::SocketState a_socketState) { Q_UNUSED(a_socketState); } void PrtCnvSocketThread::storeRadioTelegram(const std::shared_ptr &a_telegram, const uint32_t a_readCounter) { m_DbThread->storeRadioTelegram(a_telegram, a_readCounter); } void PrtCnvSocketThread::startAliveTimer() { m_ConnectionTimer->setInterval(m_AliveTimeout); m_ConnectionTimer->start(); } void PrtCnvSocketThread::startConnectionTimer() { m_ConnectionTimer->setInterval(m_ConnectTimeout); m_ConnectionTimer->start(); } void PrtCnvSocketThread::startDisconnectionTimer() { m_ConnectionTimer->setInterval(m_DisconnectTimeout); m_ConnectionTimer->start(); } void PrtCnvSocketThread::startTickTimer() { m_TickTimer->setInterval(m_TickTimeout); m_TickTimer->start(); } bool PrtCnvSocketThread::checkAndUpdateReceiveCounter(const uint32_t a_counter, const uint32_t a_maxCounter, const uint32_t a_startCounter) { TRACE_LOG(m_logger) << "checkAndUpdateReceiveCounter: " << a_counter << ", " << m_ReceiveCounter; if (a_maxCounter == ++m_ReceiveCounter) { m_ReceiveCounter = a_startCounter; } if (m_ReceiveCounter != a_counter) { { if (m_ReceiveCounter > a_counter) { ERROR_LOG(m_logger) << "It seems, the telegram with counter " << a_counter << " was resent from " << getName() << "! Expected: " << m_ReceiveCounter; } else { ERROR_LOG(m_logger) << "It seems, we lost one or several telegrams from " << getName() << ": receive-counter of received telegram: " << a_counter << "; Expected: " << m_ReceiveCounter; } } #if 0 m_ReceiveCounter--; return false; #else m_ReceiveCounter = a_counter; return true; #endif } return true; } void PrtCnvSocketThread::readHostAdresses() { QString host = m_Config->getString(getName(), QStringLiteral("HostName"), QStringLiteral("127.0.0.1")); uint16_t port = m_Config->getInteger(getName(), QStringLiteral("Port"), 4934); m_hostAdresses.push_back(qMakePair(host, port)); for (int i = 1; i < 10; ++i) { const QString hostName = QLatin1String("HostName") + QString::number(i); const QString portName = QLatin1String("Port") + QString::number(i); host = m_Config->getString(getName(), hostName, QString()); port = m_Config->getInteger(getName(), portName, 0); if (host.isEmpty() || port == 0) continue; m_hostAdresses.push_back(qMakePair(host, port)); } for (const auto &p : qAsConst(m_hostAdresses)) { INFO_LOG(m_logger) << "Read Host Adress " << p.first << ":" << p.second << " from settings"; } } }