From 4236132aa8c61db2051a379219422f0dbc32f52a Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Tue, 23 May 2023 13:15:21 -0400 Subject: [PATCH] 2023-05-23 Fred Gleason * Implemented the 'Heartbeat' ['HB'] protocol command in ripcd(8). * Added support for the 'Heartbeat' ['HB'] RIPC protocol command to 'RDRipc'. Signed-off-by: Fred Gleason --- ChangeLog | 4 +++ docs/apis/ripc.xml | 20 +++++++++++- lib/rdripc.cpp | 80 +++++++++++++++++++++++++++++++++++++++------- lib/rdripc.h | 10 +++++- ripcd/ripcd.cpp | 4 +++ 5 files changed, 104 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index bbf3782b..56a0103d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24162,3 +24162,7 @@ * Updated screenshot for rdlogmanager(1) in the Operations Guide. 2023-05-22 Fred Gleason * Fixed a regression in the BroadcastTools ACS8.2 driver in ripcd(8). +2023-05-23 Fred Gleason + * Implemented the 'Heartbeat' ['HB'] protocol command in ripcd(8). + * Added support for the 'Heartbeat' ['HB'] RIPC protocol command + to 'RDRipc'. diff --git a/docs/apis/ripc.xml b/docs/apis/ripc.xml index 77ee4a23..188e5d6b 100644 --- a/docs/apis/ripc.xml +++ b/docs/apis/ripc.xml @@ -481,7 +481,7 @@ Return current GPI mask states. - GM matrix! + GI matrix! Request the list of current GPI mask states for @@ -523,6 +523,24 @@ + + Heartbeat + + Verify the TCP network connection. + + + HB! + + + Request a heartbeat response from the + ripcd8. + + + ripcd8 will respond with + HB!. + + + Get GPO Mask States diff --git a/lib/rdripc.cpp b/lib/rdripc.cpp index a6a36a4b..81f4cf04 100644 --- a/lib/rdripc.cpp +++ b/lib/rdripc.cpp @@ -29,21 +29,26 @@ RDRipc::RDRipc(RDStation *station,RDConfig *config,QObject *parent) { ripc_station=station; ripc_config=config; + ripc_socket=NULL; ripc_onair_flag=false; ripc_ignore_mask=false; ripc_accum=""; + ripc_watchdog_pending=false; debug=false; ripc_connected=false; // - // TCP Connection + // Watchdog Timers // - ripc_socket=new QTcpSocket(this); - connect(ripc_socket,SIGNAL(connected()),this,SLOT(connectedData())); - connect(ripc_socket,SIGNAL(error(QAbstractSocket::SocketError)), - this,SLOT(errorData(QAbstractSocket::SocketError))); - connect(ripc_socket,SIGNAL(readyRead()),this,SLOT(readyData())); + ripc_watchdog_timer=new QTimer(this); + ripc_watchdog_timer->setSingleShot(true); + connect(ripc_watchdog_timer,SIGNAL(timeout()),this,SLOT(watchdogRetryData())); + + ripc_heartbeat_timer=new QTimer(this); + ripc_heartbeat_timer->setSingleShot(true); + connect(ripc_heartbeat_timer,SIGNAL(timeout()), + this,SLOT(sendHeartbeatData())); } @@ -85,14 +90,63 @@ void RDRipc::setIgnoreMask(bool state) void RDRipc::connectHost(QString hostname,uint16_t hostport,QString password) { + ripc_hostname=hostname; + ripc_hostport=hostport; ripc_password=password; + + // + // TCP Connection + // + ripc_heartbeat_timer->stop(); + if(ripc_socket!=NULL) { + ripc_socket->deleteLater(); + } + ripc_socket=new QTcpSocket(this); + connect(ripc_socket,SIGNAL(connected()),this,SLOT(connectedData())); + connect(ripc_socket,SIGNAL(error(QAbstractSocket::SocketError)), + this,SLOT(errorData(QAbstractSocket::SocketError))); + connect(ripc_socket,SIGNAL(readyRead()),this,SLOT(readyData())); + ripc_socket->connectToHost(hostname,hostport); + ripc_heartbeat_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL); } void RDRipc::connectedData() { SendCommand(QString("PW ")+ripc_password+"!"); + if(ripc_watchdog_pending) { + rda->syslog(LOG_WARNING,"connection to ripcd(8) restored"); + ripc_watchdog_pending=false; + } +} + + +void RDRipc::disconnectedData() +{ + ripc_heartbeat_timer->stop(); + ripc_watchdog_timer->stop(); + ripc_watchdog_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL); +} + + +void RDRipc::sendHeartbeatData() +{ + ripc_watchdog_timer->stop(); + SendCommand("HB!"); + ripc_watchdog_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL); +} + + +void RDRipc::watchdogRetryData() +{ + if(!ripc_watchdog_pending) { + rda->syslog(LOG_WARNING, + "connection to ripcd(8) timed out, attempting reconnect"); + } + ripc_watchdog_pending=true; + connectHost(ripc_hostname,ripc_hostport,ripc_password); + ripc_watchdog_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL); } @@ -201,12 +255,6 @@ void RDRipc::sendRml(RDMacro *macro) } -void RDRipc::reloadHeartbeat() -{ - SendCommand("RH!"); -} - - void RDRipc::errorData(QAbstractSocket::SocketError err) { rda->syslog(LOG_DEBUG,"received socket error %d",err); @@ -271,6 +319,14 @@ void RDRipc::DispatchCommand() } } + if(cmds[0]=="HB") { // Heartbeat + if(cmds.size()!=1) { + return; + } + ripc_watchdog_timer->stop(); + ripc_heartbeat_timer->start(RIPC_HEARTBEAT_POLL_INTERVAL); + } + if(cmds[0]=="MS") { // Macro Sent if(cmds.size()<4) { return; diff --git a/lib/rdripc.h b/lib/rdripc.h index 6b40ff4c..dd929da0 100644 --- a/lib/rdripc.h +++ b/lib/rdripc.h @@ -34,6 +34,7 @@ #define RIPC_MAX_ARGS 100 #define RIPC_MAX_LENGTH 256 #define RIPC_START_DELAY 2000 +#define RIPC_HEARTBEAT_POLL_INTERVAL 10000 class RDRipc : public QObject { @@ -59,7 +60,6 @@ class RDRipc : public QObject void sendCatchEvent(RDCatchEvent *evt); void sendOnairFlag(); void sendRml(RDMacro *macro); - void reloadHeartbeat(); signals: void connected(bool state); @@ -77,6 +77,9 @@ class RDRipc : public QObject private slots: void connectedData(); + void disconnectedData(); + void sendHeartbeatData(); + void watchdogRetryData(); void errorData(QAbstractSocket::SocketError err); void readyData(); @@ -85,6 +88,8 @@ class RDRipc : public QObject void DispatchCommand(); QTcpSocket *ripc_socket; QString ripc_user; + QString ripc_hostname; + uint16_t ripc_hostport; QString ripc_password; RDStation *ripc_station; RDConfig *ripc_config; @@ -93,6 +98,9 @@ class RDRipc : public QObject bool debug; QString ripc_accum; bool ripc_connected; + QTimer *ripc_heartbeat_timer; + QTimer *ripc_watchdog_timer; + bool ripc_watchdog_pending; }; diff --git a/ripcd/ripcd.cpp b/ripcd/ripcd.cpp index 7f9c0d15..1a720dfb 100644 --- a/ripcd/ripcd.cpp +++ b/ripcd/ripcd.cpp @@ -522,6 +522,10 @@ bool MainObject::DispatchCommand(RipcdConnection *conn) EchoCommand(conn->id(),cmds.join(" ")+"-!"); return true; } + if(cmds[0]=="HB") { // Heartbeat + EchoCommand(conn->id(),"HB!"); + } + if(cmds[0]=="RU") { // Request User EchoCommand(conn->id(),(QString("RU ")+rda->station()->userName()+"!"). toUtf8());