From 16e35df01dffd6933df45171ade05772f4f5f0e6 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Sat, 13 Jan 2024 14:03:00 -0500 Subject: [PATCH] 2024-01-13 Fred Gleason * Added an extended event PAD output at TCP port 34290. Signed-off-by: Fred Gleason --- ChangeLog | 2 + lib/rd.h | 2 +- lib/rdlogplay.cpp | 171 +++++++++++++++++++++---------------- lib/rdlogplay.h | 4 +- rdpadd/Makefile.am | 8 +- rdpadd/rdpadd.cpp | 177 ++------------------------------------ rdpadd/rdpadd.h | 48 ++--------- rdpadd/repeater.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++ rdpadd/repeater.h | 81 ++++++++++++++++++ 9 files changed, 406 insertions(+), 289 deletions(-) create mode 100644 rdpadd/repeater.cpp create mode 100644 rdpadd/repeater.h diff --git a/ChangeLog b/ChangeLog index 47784b4d..8ec6140b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24596,3 +24596,5 @@ 2023-12-27 Fred Gleason * Fixed a regression in rdcatchd(8) that caused recordings to MPEG Layer II to fail. +2024-01-13 Fred Gleason + * Added an extended event PAD output at TCP port 34290. diff --git a/lib/rd.h b/lib/rd.h index 6381627e..657ce0c2 100644 --- a/lib/rd.h +++ b/lib/rd.h @@ -626,7 +626,7 @@ * PAD Update Connection Points */ #define RD_PAD_CLIENT_TCP_PORT 34289 -#define RD_PAD_SOURCE_UNIX_ADDRESS "m4w8n8fsfddf-473fdueusurt-8954" +#define RD_PAD_SOURCE_UNIX_BASE_ADDRESS "m4w8n8fsfddf-473fdueusurt-8954" /* * Default 'ServiceTimeout=' value in rd.conf(5) diff --git a/lib/rdlogplay.cpp b/lib/rdlogplay.cpp index ec76f7a6..2de42c6f 100644 --- a/lib/rdlogplay.cpp +++ b/lib/rdlogplay.cpp @@ -2,7 +2,7 @@ // // Rivendell Log Playout Machine // -// (C) Copyright 2002-2023 Fred Gleason +// (C) Copyright 2002-2024 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -74,16 +74,18 @@ RDLogPlay::RDLogPlay(int id,RDEventPlayer *player,bool enable_cue,QObject *paren // // PAD Server Connection // - play_pad_socket=new RDUnixSocket(this); - if(!play_pad_socket->connectToAbstract(RD_PAD_SOURCE_UNIX_ADDRESS)) { - fprintf(stderr,"RDLogPlay: unable to connect to rdpadd\n"); + for(int i=0;i<2;i++) { + play_pad_socket[i]=new RDUnixSocket(this); + if(!play_pad_socket[i]-> + connectToAbstract(QString::asprintf("%s-%d", + RD_PAD_SOURCE_UNIX_BASE_ADDRESS,i))) { + fprintf(stderr,"RDLogPlay: unable to connect to rdpadd\n"); + } } // // CAE Connection // - // play_cae=new RDCae(rda->station(),rda->config(),parent); - // play_cae->connectHost(); play_cae=rda->cae(); for(int i=0;i<2;i++) { @@ -3109,11 +3111,13 @@ void RDLogPlay::SendNowNext() // Get NEXT Event // logline[1]=NULL; - for(int i=nextLine();istatus()==RDLogLine::Scheduled)&&(!logLine(i)->asyncronous())) { - logline[1]=logLine(i); - i=lineCount(); + if(nextLine()>=0) { + for(int i=nextLine();istatus()==RDLogLine::Scheduled)&&(!logLine(i)->asyncronous())) { + logline[1]=logLine(i); + i=lineCount(); + } } } } @@ -3158,71 +3162,96 @@ void RDLogPlay::SendNowNext() // // Send to PAD Server // - play_pad_socket->write(QString("{\r\n").toUtf8()); - play_pad_socket->write(QString(" \"padUpdate\": {\r\n").toUtf8()); - play_pad_socket-> - write(RDJsonField("dateTime",QDateTime::currentDateTime(),8).toUtf8()); - play_pad_socket-> - write(RDJsonField("hostName",rda->station()->name(),8).toUtf8()); - play_pad_socket-> - write(RDJsonField("shortHostName",rda->station()->shortName(),8).toUtf8()); - play_pad_socket->write(RDJsonField("machine",play_id+1,8).toUtf8()); - play_pad_socket->write(RDJsonField("onairFlag",play_onair_flag,8).toUtf8()); - play_pad_socket-> - write(RDJsonField("mode",RDAirPlayConf::logModeText(play_op_mode),8).toUtf8()); - - // - // Service - // - if(svcname.isEmpty()) { - play_pad_socket->write(RDJsonNullField("service",8).toUtf8()); - } - else { - RDSvc *svc=new RDSvc(svcname,rda->station(),rda->config(),this); - play_pad_socket->write(QString(" \"service\": {\r\n").toUtf8()); - play_pad_socket->write(RDJsonField("name",svcname,12).toUtf8()); - play_pad_socket-> - write(RDJsonField("description",svc->description(),12).toUtf8()); - play_pad_socket-> - write(RDJsonField("programCode",svc->programCode(),12,true).toUtf8()); - play_pad_socket->write(QString(" },\r\n").toUtf8()); - delete svc; - } - - // - // Log - // - play_pad_socket->write(QString(" \"log\": {\r\n").toUtf8()); - play_pad_socket->write(RDJsonField("name",logName(),12,true).toUtf8()); - play_pad_socket->write(QString(" },\r\n").toUtf8()); - - // - // Now - // - QDateTime start_datetime; + QDateTime next_datetime; if(logline[0]!=NULL) { - start_datetime= + next_datetime= QDateTime(QDate::currentDate(),logline[0]->startTime(RDLogLine::Actual)); } - play_pad_socket-> - write(GetPadJson("now",logline[0],start_datetime,now_line,8,false). - toUtf8()); + int next_num=1; - // - // Next - // - QDateTime next_datetime; - if((mode()==RDAirPlayConf::Auto)&&(logline[0]!=NULL)) { - next_datetime=start_datetime.addSecs(logline[0]->forcedLength()/1000); + for(int i=0;i<2;i++) { + play_pad_socket[i]->write(QString("{\r\n").toUtf8()); + play_pad_socket[i]->write(QString(" \"padUpdate\": {\r\n").toUtf8()); + play_pad_socket[i]-> + write(RDJsonField("dateTime",QDateTime::currentDateTime(),8).toUtf8()); + play_pad_socket[i]-> + write(RDJsonField("hostName",rda->station()->name(),8).toUtf8()); + play_pad_socket[i]-> + write(RDJsonField("shortHostName",rda->station()->shortName(),8).toUtf8()); + play_pad_socket[i]->write(RDJsonField("machine",play_id+1,8).toUtf8()); + play_pad_socket[i]->write(RDJsonField("onairFlag",play_onair_flag,8).toUtf8()); + play_pad_socket[i]-> + write(RDJsonField("mode",RDAirPlayConf::logModeText(play_op_mode),8).toUtf8()); + + // + // Service + // + if(svcname.isEmpty()) { + play_pad_socket[i]->write(RDJsonNullField("service",8).toUtf8()); + } + else { + RDSvc *svc=new RDSvc(svcname,rda->station(),rda->config(),this); + play_pad_socket[i]->write(QString(" \"service\": {\r\n").toUtf8()); + play_pad_socket[i]->write(RDJsonField("name",svcname,12).toUtf8()); + play_pad_socket[i]-> + write(RDJsonField("description",svc->description(),12).toUtf8()); + play_pad_socket[i]-> + write(RDJsonField("programCode",svc->programCode(),12,true).toUtf8()); + play_pad_socket[i]->write(QString(" },\r\n").toUtf8()); + delete svc; + } + + // + // Log + // + play_pad_socket[i]->write(QString(" \"log\": {\r\n").toUtf8()); + play_pad_socket[i]->write(RDJsonField("name",logName(),12,true).toUtf8()); + play_pad_socket[i]->write(QString(" },\r\n").toUtf8()); + + // + // Now + // + play_pad_socket[i]-> + write(GetPadJson("now",logline[0],next_datetime,now_line,8,false). + toUtf8()); + + // + // Next + // + if((mode()==RDAirPlayConf::Auto)&&(logline[0]!=NULL)) { + next_datetime=next_datetime.addSecs(logline[0]->forcedLength()/1000); + } + play_pad_socket[i]-> + write(GetPadJson("next",logline[1], + next_datetime,nextLine(),8,(i==0)|| + ((1+nextLine())==lineCount())||(nextLine()<0)).toUtf8()); + + if(nextLine()>=0) { + // + // Extended Events + // + if((i>0)&&(nextLine()>=0)) { + for(int j=nextLine()+1;jstatus()==RDLogLine::Scheduled)&& + (!logLine(i)->asyncronous())) { + next_datetime=next_datetime.addSecs(ll->forcedLength()/1000); + play_pad_socket[i]-> + write(GetPadJson(QString::asprintf("next%d",next_num++), + ll,next_datetime,j,8,(1+j)==lineCount()). + toUtf8()); + } + } + } + } + } + + // + // Commit the update + // + play_pad_socket[i]->write(QString(" }\r\n").toUtf8()); + play_pad_socket[i]->write(QString("}\r\n\r\n").toUtf8()); } - play_pad_socket->write(GetPadJson("next",logline[1], - next_datetime,nextLine(),8,true).toUtf8()); - - // - // Commit the update - // - play_pad_socket->write(QString(" }\r\n").toUtf8()); - play_pad_socket->write(QString("}\r\n\r\n").toUtf8()); // // Clean up diff --git a/lib/rdlogplay.h b/lib/rdlogplay.h index e96e8bbc..73ec04ae 100644 --- a/lib/rdlogplay.h +++ b/lib/rdlogplay.h @@ -2,7 +2,7 @@ // // Rivendell Log Playout Machine // -// (C) Copyright 2002-2023 Fred Gleason +// (C) Copyright 2002-2024 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -256,7 +256,7 @@ class RDLogPlay : public RDLogModel bool play_audition_head_played; int play_audition_preroll; RDEventPlayer *play_event_player; - RDUnixSocket *play_pad_socket; + RDUnixSocket *play_pad_socket[2]; bool play_hours[24]; int play_slot_quantity; }; diff --git a/rdpadd/Makefile.am b/rdpadd/Makefile.am index f0d89e87..a88c71fa 100644 --- a/rdpadd/Makefile.am +++ b/rdpadd/Makefile.am @@ -2,7 +2,7 @@ ## ## Rivendell PAD Consolidation Server ## -## (C) Copyright 2018-2022 Fred Gleason +## (C) Copyright 2018-2024 Fred Gleason ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License version 2 as @@ -31,9 +31,11 @@ moc_%.cpp: %.h sbin_PROGRAMS = rdpadd -dist_rdpadd_SOURCES = rdpadd.cpp rdpadd.h +dist_rdpadd_SOURCES = rdpadd.cpp rdpadd.h\ + repeater.cpp repeater.h -nodist_rdpadd_SOURCES = moc_rdpadd.cpp +nodist_rdpadd_SOURCES = moc_rdpadd.cpp\ + moc_repeater.cpp rdpadd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT5_LIBS@ @MUSICBRAINZ_LIBS@ @IMAGEMAGICK_LIBS@ diff --git a/rdpadd/rdpadd.cpp b/rdpadd/rdpadd.cpp index 81af9e6c..dcb513a7 100644 --- a/rdpadd/rdpadd.cpp +++ b/rdpadd/rdpadd.cpp @@ -2,7 +2,7 @@ // // Rivendell PAD Consolidation Server // -// (C) Copyright 2018-2021 Fred Gleason +// (C) Copyright 2018-2024 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -18,182 +18,19 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // -#include -#include - #include -#include #include -#include #include "rdpadd.h" -MetadataSource::MetadataSource(QTcpSocket *sock) +MainObject::MainObject() + : QObject() { - meta_socket=sock; - meta_committed=true; -} - - -QByteArray MetadataSource::buffer() const -{ - return meta_buffer; -} - - -bool MetadataSource::appendBuffer(const QByteArray &data) -{ - // printf("data: %s\n",(const char *)data); - - if(meta_committed) { - meta_buffer.clear(); - } - meta_buffer+=data; - meta_committed=meta_buffer.endsWith("\r\n\r\n"); - - return meta_committed; -} - - -bool MetadataSource::isCommitted() const -{ - return meta_committed; -} - - -QTcpSocket *MetadataSource::socket() const -{ - return meta_socket; -} - - - - -MainObject::MainObject(QObject *parent) - : QObject(parent) -{ - new RDCmdSwitch("rdpadd",RDPADD_USAGE); - - // - // Client Server - // - pad_client_disconnect_mapper=new QSignalMapper(this); - connect(pad_client_disconnect_mapper,SIGNAL(mapped(int)), - this,SLOT(clientDisconnected(int))); - - pad_client_server=new QTcpServer(this); - connect(pad_client_server,SIGNAL(newConnection()), - this,SLOT(newClientConnectionData())); - if(!pad_client_server->listen(QHostAddress::Any,RD_PAD_CLIENT_TCP_PORT)) { - fprintf(stderr,"rdpadd: unable to bind client port %d\n", - RD_PAD_CLIENT_TCP_PORT); - exit(1); - } - - // - // Source Server - // - pad_source_ready_mapper=new QSignalMapper(this); - connect(pad_source_ready_mapper,SIGNAL(mapped(int)), - this,SLOT(sourceReadyReadData(int))); - - pad_source_disconnect_mapper=new QSignalMapper(this); - connect(pad_source_disconnect_mapper,SIGNAL(mapped(int)), - this,SLOT(sourceDisconnected(int))); - - pad_source_server=new RDUnixServer(this); - connect(pad_source_server,SIGNAL(newConnection()), - this,SLOT(newSourceConnectionData())); - if(!pad_source_server->listenToAbstract(RD_PAD_SOURCE_UNIX_ADDRESS)) { - fprintf(stderr,"rdpadd: unable to bind source socket [%s]\n", - (const char *)pad_source_server->errorString().toUtf8()); - exit(1); - } -} - - -void MainObject::newClientConnectionData() -{ - QTcpSocket *sock=pad_client_server->nextPendingConnection(); - connect(sock,SIGNAL(disconnected()),pad_client_disconnect_mapper,SLOT(map())); - pad_client_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); - pad_client_sockets[sock->socketDescriptor()]=sock; - - SendState(sock->socketDescriptor()); - // printf("client connection %d opened\n",sock->socketDescriptor()); -} - - -void MainObject::clientDisconnected(int id) -{ - QTcpSocket *sock=NULL; - - if((sock=pad_client_sockets.value(id))!=NULL) { - sock->deleteLater(); - pad_client_sockets.remove(id); - // printf("client connection %d closed\n",id); - } - else { - fprintf(stderr,"unknown client connection %d attempted to close\n",id); - } -} - - -void MainObject::newSourceConnectionData() -{ - QTcpSocket *sock=pad_source_server->nextPendingConnection(); - if(sock==NULL) { - fprintf(stderr,"rdpadd: UNIX socket error [%s]\n", - (const char *)pad_source_server->errorString().toUtf8()); - exit(1); - } - connect(sock,SIGNAL(readyRead()),pad_source_ready_mapper,SLOT(map())); - pad_source_ready_mapper->setMapping(sock,sock->socketDescriptor()); - - connect(sock,SIGNAL(disconnected()),pad_source_disconnect_mapper,SLOT(map())); - pad_source_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); - - pad_sources[sock->socketDescriptor()]=new MetadataSource(sock); - - // printf("source connection %d opened\n",sock->socketDescriptor()); -} - - -void MainObject::sourceReadyReadData(int id) -{ - if(pad_sources[id]!=NULL) { - if(pad_sources[id]->appendBuffer(pad_sources[id]->socket()->readAll())) { - for(QMap::const_iterator it=pad_client_sockets.begin(); - it!=pad_client_sockets.end();it++) { - it.value()->write(pad_sources[id]->buffer()); - } - } - } -} - - -void MainObject::sourceDisconnected(int id) -{ - if(pad_sources.value(id)!=NULL) { - pad_sources.value(id)->socket()->deleteLater(); - delete pad_sources.value(id); - pad_sources.remove(id); - // printf("source connection %d closed\n",id); - } - else { - fprintf(stderr,"unknown source connection %d attempted to close\n",id); - } -} - - -void MainObject::SendState(int id) -{ - for(QMap::const_iterator it=pad_sources.begin(); - it!=pad_sources.end();it++) { - if(it.value()->isCommitted()) { - pad_client_sockets.value(id)->write(it.value()->buffer()); - } + for(int i=0;i<2;i++) { + d_repeaters.push_back(new Repeater(QString::asprintf("%s-%d", + RD_PAD_SOURCE_UNIX_BASE_ADDRESS,i), + RD_PAD_CLIENT_TCP_PORT+i,this)); } } diff --git a/rdpadd/rdpadd.h b/rdpadd/rdpadd.h index cf4d03df..75badd67 100644 --- a/rdpadd/rdpadd.h +++ b/rdpadd/rdpadd.h @@ -2,7 +2,7 @@ // // Rivendell PAD Consolidation Server // -// (C) Copyright 2018 Fred Gleason +// (C) Copyright 2018-2024 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -21,57 +21,21 @@ #ifndef RDPADD_H #define RDPADD_H -#include -#include -#include -#include -#include +#include +#include -#include +#include "repeater.h" #define RDPADD_USAGE "\n\n" -class MetadataSource -{ - public: - MetadataSource(QTcpSocket *sock); - QByteArray buffer() const; - bool appendBuffer(const QByteArray &data); - bool isCommitted() const; - QTcpSocket *socket() const; - - private: - QByteArray meta_buffer; - bool meta_committed; - QTcpSocket *meta_socket; -}; - - - - class MainObject : public QObject { Q_OBJECT public: - MainObject(QObject *parent=0); - - private slots: - void newClientConnectionData(); - void clientDisconnected(int id); - void newSourceConnectionData(); - void sourceReadyReadData(int id); - void sourceDisconnected(int id); + MainObject(); private: - void SendState(int id); - QSignalMapper *pad_client_disconnect_mapper; - QTcpServer *pad_client_server; - QMap pad_client_sockets; - - QSignalMapper *pad_source_ready_mapper; - QSignalMapper *pad_source_disconnect_mapper; - RDUnixServer *pad_source_server; - QMap pad_sources; + QList d_repeaters; }; diff --git a/rdpadd/repeater.cpp b/rdpadd/repeater.cpp new file mode 100644 index 00000000..b9450aff --- /dev/null +++ b/rdpadd/repeater.cpp @@ -0,0 +1,202 @@ +// rdpadd.cpp +// +// Rivendell PAD Data Repeater +// +// (C) Copyright 2018-2024 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +#include + +#include "repeater.h" + +MetadataSource::MetadataSource(QTcpSocket *sock) +{ + meta_socket=sock; + meta_committed=true; +} + + +QByteArray MetadataSource::buffer() const +{ + return meta_buffer; +} + + +bool MetadataSource::appendBuffer(const QByteArray &data) +{ + if(meta_committed) { + meta_buffer.clear(); + } + meta_buffer+=data; + meta_committed=meta_buffer.endsWith("\r\n\r\n"); + + return meta_committed; +} + + +bool MetadataSource::isCommitted() const +{ + return meta_committed; +} + + +QTcpSocket *MetadataSource::socket() const +{ + return meta_socket; +} + + + + +Repeater::Repeater(const QString &src_unix_addr,uint16_t serv_port, + QObject *parent) + : QObject(parent) +{ + pad_source_unix_address=src_unix_addr; + pad_server_port=serv_port; + + // + // Client Server + // + pad_client_disconnect_mapper=new QSignalMapper(this); + connect(pad_client_disconnect_mapper,SIGNAL(mapped(int)), + this,SLOT(clientDisconnected(int))); + + pad_client_server=new QTcpServer(this); + connect(pad_client_server,SIGNAL(newConnection()), + this,SLOT(newClientConnectionData())); + if(!pad_client_server->listen(QHostAddress::Any,pad_server_port)) { + fprintf(stderr,"rdpadd: unable to bind client port %d\n",pad_server_port); + exit(1); + } + + // + // Source Server + // + pad_source_ready_mapper=new QSignalMapper(this); + connect(pad_source_ready_mapper,SIGNAL(mapped(int)), + this,SLOT(sourceReadyReadData(int))); + + pad_source_disconnect_mapper=new QSignalMapper(this); + connect(pad_source_disconnect_mapper,SIGNAL(mapped(int)), + this,SLOT(sourceDisconnected(int))); + + pad_source_server=new RDUnixServer(this); + connect(pad_source_server,SIGNAL(newConnection()), + this,SLOT(newSourceConnectionData())); + if(!pad_source_server->listenToAbstract(pad_source_unix_address)) { + fprintf(stderr,"rdpadd: unable to bind source socket [%s]\n", + pad_source_server->errorString().toUtf8().constData()); + exit(1); + } +} + + +QString Repeater::sourceUnixAddress() const +{ + return pad_source_unix_address; +} + + +uint16_t Repeater::serverPort() const +{ + return pad_server_port; +} + + +void Repeater::newClientConnectionData() +{ + QTcpSocket *sock=pad_client_server->nextPendingConnection(); + connect(sock,SIGNAL(disconnected()),pad_client_disconnect_mapper,SLOT(map())); + pad_client_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); + pad_client_sockets[sock->socketDescriptor()]=sock; + + SendState(sock->socketDescriptor()); +} + + +void Repeater::clientDisconnected(int id) +{ + QTcpSocket *sock=NULL; + + if((sock=pad_client_sockets.value(id))!=NULL) { + sock->deleteLater(); + pad_client_sockets.remove(id); + } + else { + fprintf(stderr,"unknown client connection %d attempted to close\n",id); + } +} + + +void Repeater::newSourceConnectionData() +{ + QTcpSocket *sock=pad_source_server->nextPendingConnection(); + if(sock==NULL) { + fprintf(stderr,"rdpadd: UNIX socket error [%s]\n", + (const char *)pad_source_server->errorString().toUtf8()); + exit(1); + } + connect(sock,SIGNAL(readyRead()),pad_source_ready_mapper,SLOT(map())); + pad_source_ready_mapper->setMapping(sock,sock->socketDescriptor()); + + connect(sock,SIGNAL(disconnected()),pad_source_disconnect_mapper,SLOT(map())); + pad_source_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); + + pad_sources[sock->socketDescriptor()]=new MetadataSource(sock); +} + + +void Repeater::sourceReadyReadData(int id) +{ + if(pad_sources[id]!=NULL) { + if(pad_sources[id]->appendBuffer(pad_sources[id]->socket()->readAll())) { + for(QMap::const_iterator it=pad_client_sockets.begin(); + it!=pad_client_sockets.end();it++) { + it.value()->write(pad_sources[id]->buffer()); + } + } + } +} + + +void Repeater::sourceDisconnected(int id) +{ + if(pad_sources.value(id)!=NULL) { + pad_sources.value(id)->socket()->deleteLater(); + delete pad_sources.value(id); + pad_sources.remove(id); + } + else { + fprintf(stderr,"unknown source connection %d attempted to close\n",id); + } +} + + +void Repeater::SendState(int id) +{ + for(QMap::const_iterator it=pad_sources.begin(); + it!=pad_sources.end();it++) { + if(it.value()->isCommitted()) { + pad_client_sockets.value(id)->write(it.value()->buffer()); + } + } +} diff --git a/rdpadd/repeater.h b/rdpadd/repeater.h new file mode 100644 index 00000000..71040cc3 --- /dev/null +++ b/rdpadd/repeater.h @@ -0,0 +1,81 @@ +// repeater.h +// +// Rivendell PAD Data Repeater +// +// (C) Copyright 2018 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef REPEATER_H +#define REPEATER_H + +#include +#include +#include +#include +#include + +#include + +#include "repeater.h" + +class MetadataSource +{ + public: + MetadataSource(QTcpSocket *sock); + QByteArray buffer() const; + bool appendBuffer(const QByteArray &data); + bool isCommitted() const; + QTcpSocket *socket() const; + + private: + QByteArray meta_buffer; + bool meta_committed; + QTcpSocket *meta_socket; +}; + + + + +class Repeater : public QObject +{ + Q_OBJECT + public: + Repeater(const QString &src_unix_addr,uint16_t serv_port,QObject *parent=0); + QString sourceUnixAddress() const; + uint16_t serverPort() const; + + private slots: + void newClientConnectionData(); + void clientDisconnected(int id); + void newSourceConnectionData(); + void sourceReadyReadData(int id); + void sourceDisconnected(int id); + + private: + void SendState(int id); + uint16_t pad_server_port; + QString pad_source_unix_address; + QSignalMapper *pad_client_disconnect_mapper; + QTcpServer *pad_client_server; + QMap pad_client_sockets; + QSignalMapper *pad_source_ready_mapper; + QSignalMapper *pad_source_disconnect_mapper; + RDUnixServer *pad_source_server; + QMap pad_sources; +}; + + +#endif // REPEATER_H