2018-08-08 Fred Gleason <fredg@paravelsystems.com>

* Refactored rdcatchd(8) to remove arbitrary limits on number of
	control connections.
	* Removed Qt3 support classes from rdcatchd(8).
This commit is contained in:
Fred Gleason 2018-08-08 16:03:36 -04:00
parent 3a7306de13
commit e3bb963c3f
7 changed files with 293 additions and 324 deletions

View File

@ -17327,3 +17327,7 @@
* Upgraded Qt3 to Qt4. * Upgraded Qt3 to Qt4.
2018-08-07 Fred Gleason <fredg@paravelsystems.com> 2018-08-07 Fred Gleason <fredg@paravelsystems.com>
* Removed Qt3 support classes from ripcd(8). * Removed Qt3 support classes from ripcd(8).
2018-08-08 Fred Gleason <fredg@paravelsystems.com>
* Refactored rdcatchd(8) to remove arbitrary limits on number of
control connections.
* Removed Qt3 support classes from rdcatchd(8).

View File

@ -20,7 +20,7 @@
## ##
## Use automake to process this into a Makefile.in ## Use automake to process this into a Makefile.in
AM_CPPFLAGS = -Wall -I$(top_srcdir)/lib @QT4_CFLAGS@ -DQT3_SUPPORT -I/usr/include/Qt3Support AM_CPPFLAGS = -Wall -I$(top_srcdir)/lib @QT4_CFLAGS@ -I/usr/include/Qt3Support
LIBS = -L$(top_srcdir)/lib LIBS = -L$(top_srcdir)/lib
MOC = @QT_MOC@ MOC = @QT_MOC@
@ -35,12 +35,10 @@ dist_rdcatchd_SOURCES = batch.cpp\
event_player.cpp event_player.h\ event_player.cpp event_player.h\
local_macros.cpp\ local_macros.cpp\
rdcatchd.cpp rdcatchd.h\ rdcatchd.cpp rdcatchd.h\
rdcatchd_socket.cpp rdcatchd_socket.h\
startdropboxes.cpp startdropboxes.cpp
nodist_rdcatchd_SOURCES = moc_event_player.cpp\ nodist_rdcatchd_SOURCES = moc_event_player.cpp\
moc_rdcatchd.cpp\ moc_rdcatchd.cpp
moc_rdcatchd_socket.cpp
rdcatchd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support rdcatchd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support

View File

@ -38,13 +38,11 @@
#include <qtimer.h> #include <qtimer.h>
#include <qsignalmapper.h> #include <qsignalmapper.h>
#include <qsessionmanager.h> #include <qsessionmanager.h>
#include <qurl.h>
#include <rdapplication.h> #include <rdapplication.h>
#include <rdaudioconvert.h> #include <rdaudioconvert.h>
#include <rdcatchd_socket.h>
#include <rdcatchd.h>
#include <rdcheck_daemons.h> #include <rdcheck_daemons.h>
#include <rdcmd_switch.h>
#include <rdconf.h> #include <rdconf.h>
#include <rdcut.h> #include <rdcut.h>
#include <rddb.h> #include <rddb.h>
@ -52,18 +50,15 @@
#include <rddebug.h> #include <rddebug.h>
#include <rddownload.h> #include <rddownload.h>
#include <rdescape_string.h> #include <rdescape_string.h>
#include <rdlibrary_conf.h>
#include <rdmixer.h>
#include <rdpodcast.h>
#include <rdrecording.h>
#include <rdsettings.h> #include <rdsettings.h>
#include <rdtempdirectory.h> #include <rdtempdirectory.h>
#include <rdttyout.h>
#include <rdupload.h> #include <rdupload.h>
#include <rdurl.h> #include <rdurl.h>
#include <rdwavefile.h> #include <rdwavefile.h>
#include <rdweb.h> #include <rdweb.h>
#include "rdcatchd.h"
void MainObject::catchConnectedData(int serial,bool state) void MainObject::catchConnectedData(int serial,bool state)
{ {
if(!state) { if(!state) {
@ -195,7 +190,7 @@ void MainObject::RunDownload(CatchEvent *evt)
QString url_username=evt->urlUsername(); QString url_username=evt->urlUsername();
QString url_password=evt->urlPassword(); QString url_password=evt->urlPassword();
if(url_username.isEmpty()&& if(url_username.isEmpty()&&
(Q3Url(evt->resolvedUrl()).protocol().lower()=="ftp")) { (QUrl(evt->resolvedUrl()).scheme().lower()=="ftp")) {
url_username=RD_ANON_FTP_USERNAME; url_username=RD_ANON_FTP_USERNAME;
url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION; url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION;
} }
@ -316,7 +311,7 @@ void MainObject::RunUpload(CatchEvent *evt)
QString url_username=evt->urlUsername(); QString url_username=evt->urlUsername();
QString url_password=evt->urlPassword(); QString url_password=evt->urlPassword();
if(url_username.isEmpty()&& if(url_username.isEmpty()&&
(Q3Url(evt->resolvedUrl()).protocol().lower()=="ftp")) { (QUrl(evt->resolvedUrl()).scheme().lower()=="ftp")) {
url_username=RD_ANON_FTP_USERNAME; url_username=RD_ANON_FTP_USERNAME;
url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION; url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION;
} }

View File

@ -41,15 +41,12 @@
#include <qsignalmapper.h> #include <qsignalmapper.h>
#include <qsessionmanager.h> #include <qsessionmanager.h>
#include <dbversion.h>
#include <rdapplication.h> #include <rdapplication.h>
#include <rdcatchd_socket.h>
#include <rdcheck_daemons.h> #include <rdcheck_daemons.h>
#include <rdconf.h> #include <rdconf.h>
#include <rdcut.h> #include <rdcut.h>
#include <rddatedecode.h> #include <rddatedecode.h>
#include <rddb.h> #include <rddb.h>
#include <rddebug.h>
#include <rdescape_string.h> #include <rdescape_string.h>
#include <rdhash.h> #include <rdhash.h>
#include <rdlibrary_conf.h> #include <rdlibrary_conf.h>
@ -59,7 +56,6 @@
#include <rdrecording.h> #include <rdrecording.h>
#include <rdsettings.h> #include <rdsettings.h>
#include <rdtempdirectory.h> #include <rdtempdirectory.h>
#include <rdttyout.h>
#include <rdurl.h> #include <rdurl.h>
#include <rdwavefile.h> #include <rdwavefile.h>
@ -119,12 +115,80 @@ void SigHandler(int signum)
} }
ServerConnection::ServerConnection(int id,QTcpSocket *sock)
{
conn_id=id;
conn_socket=sock;
conn_authenticated=false;
conn_meter_enabled=false;
conn_is_closing=false;
accum="";
}
ServerConnection::~ServerConnection()
{
delete conn_socket;
}
int ServerConnection::id() const
{
return conn_id;
}
bool ServerConnection::isAuthenticated() const
{
return conn_authenticated;
}
void ServerConnection::setAuthenticated(bool state)
{
conn_authenticated=state;
}
bool ServerConnection::meterEnabled() const
{
return conn_meter_enabled;
}
void ServerConnection::setMeterEnabled(bool state)
{
conn_meter_enabled=state;
}
QTcpSocket *ServerConnection::socket()
{
return conn_socket;
}
bool ServerConnection::isClosing() const
{
return conn_is_closing;
}
void ServerConnection::close()
{
conn_is_closing=true;
}
MainObject::MainObject(QObject *parent) MainObject::MainObject(QObject *parent)
:QObject(parent) :QObject(parent)
{ {
QString sql; QString sql;
RDSqlQuery *q; RDSqlQuery *q;
QString err_msg; QString err_msg;
debug=false;
// //
// Open the Database // Open the Database
@ -143,6 +207,10 @@ MainObject::MainObject(QObject *parent)
RunBatch(rda->cmdSwitch()); RunBatch(rda->cmdSwitch());
return; return;
} }
if(rda->cmdSwitch()->key(i)=="-d") {
debug=true;
rda->cmdSwitch()->setProcessed(i,true);
}
if(!rda->cmdSwitch()->processed(i)) { if(!rda->cmdSwitch()->processed(i)) {
fprintf(stderr,"rdcatchdd: unknown command option \"%s\"\n", fprintf(stderr,"rdcatchdd: unknown command option \"%s\"\n",
(const char *)rda->cmdSwitch()->key(i)); (const char *)rda->cmdSwitch()->key(i));
@ -161,15 +229,6 @@ MainObject::MainObject(QObject *parent)
// //
// Initialize Data Structures // Initialize Data Structures
// //
debug=false;
for(unsigned i=0;i<RDCATCHD_MAX_CONNECTIONS;i++) {
socket[i]=NULL;
istate[i]=0;
argnum[i]=0;
argptr[i]=0;
auth[i]=false;
catch_meter_enabled[i]=false;
}
for(int i=0;i<MAX_DECKS;i++) { for(int i=0;i<MAX_DECKS;i++) {
catch_record_deck_status[i]=RDDeck::Offline; catch_record_deck_status[i]=RDDeck::Offline;
catch_playout_deck_status[i]=RDDeck::Offline; catch_playout_deck_status[i]=RDDeck::Offline;
@ -207,12 +266,22 @@ MainObject::MainObject(QObject *parent)
connect(timer,SIGNAL(timeout()),this,SLOT(freeEventsData())); connect(timer,SIGNAL(timeout()),this,SLOT(freeEventsData()));
timer->start(RDCATCHD_FREE_EVENTS_INTERVAL); timer->start(RDCATCHD_FREE_EVENTS_INTERVAL);
server=new RDCatchdSocket(RDCATCHD_TCP_PORT,0,this); //
if(!server->ok()) { // Command Server
printf("rdcatchd: aborting - couldn't bind socket"); //
server=new QTcpServer(this);
if(!server->listen(QHostAddress::Any,RDCATCHD_TCP_PORT)) {
fprintf(stderr,"rdcatchd: aborting - couldn't bind socket");
exit(1); exit(1);
} }
connect(server,SIGNAL(connection(int)),this,SLOT(newConnection(int))); connect(server,SIGNAL(newConnection()),this,SLOT(newConnectionData()));
catch_ready_mapper=new QSignalMapper(this);
connect(catch_ready_mapper,SIGNAL(mapped(int)),this,SLOT(socketReadyReadData(int)));
catch_kill_mapper=new QSignalMapper(this);
connect(catch_kill_mapper,SIGNAL(mapped(int)),this,SLOT(socketKillData(int)));
catch_garbage_timer=new QTimer(this);
catch_garbage_timer->setSingleShot(true);
connect(catch_garbage_timer,SIGNAL(timeout()),this,SLOT(garbageData()));
// connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), // connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)),
// this,SLOT(log(RDConfig::LogPriority,const QString &))); // this,SLOT(log(RDConfig::LogPriority,const QString &)));
@ -427,26 +496,24 @@ void MainObject::log(RDConfig::LogPriority prio,const QString &msg)
} }
void MainObject::newConnection(int fd) void MainObject::newConnectionData()
{ {
unsigned i=0; int i=0;
QTcpSocket *sock=server->nextPendingConnection();
while((i<RDCATCHD_MAX_CONNECTIONS)&&(socket[i]!=NULL)) { while((i<catch_connections.size())&&(catch_connections[i]!=NULL)) {
i++; i++;
} }
if(i==RDCATCHD_MAX_CONNECTIONS) { // Table full, drop it on the floor if(i==catch_connections.size()) { // Table full, create a new slot
LogLine(RDConfig::LogWarning,QString().sprintf( catch_connections.push_back(new ServerConnection(i,sock));
"rdcatchd connection table full, dropping connection (%d/%d)",
i, RDCATCHD_MAX_CONNECTIONS));
close(fd);
return;
} }
socket[i]=new RDSocket(i,this); else {
socket[i]->setSocket(fd); catch_connections[i]=new ServerConnection(i,sock);
connect(socket[i],SIGNAL(readyReadID(int)),this,SLOT(socketData(int))); }
connect(socket[i],SIGNAL(connectionClosedID(int)), connect(sock,SIGNAL(readyRead()),catch_ready_mapper,SLOT(map()));
this,SLOT(socketKill(int))); catch_ready_mapper->setMapping(sock,i);
LogLine(RDConfig::LogDebug,"rdcatchd new connection open"); connect(sock,SIGNAL(connectionClosed()),catch_kill_mapper,SLOT(map()));
catch_kill_mapper->setMapping(sock,i);
rda->log(RDConfig::LogDebug,QString().sprintf("created connection %d",i));
} }
@ -528,7 +595,6 @@ void MainObject::startTimerData(int id)
{ {
int event=GetEvent(id); int event=GetEvent(id);
unsigned deck=catch_events[event].channel()-1; unsigned deck=catch_events[event].channel()-1;
// bool waiting=false;
catch_events[event].setStatus(RDDeck::Idle); catch_events[event].setStatus(RDDeck::Idle);
for(unsigned i=0;i<catch_events.size();i++) { for(unsigned i=0;i<catch_events.size();i++) {
@ -836,15 +902,33 @@ void MainObject::engineData(int id)
} }
void MainObject::socketData(int ch) void MainObject::socketReadyReadData(int ch)
{ {
ParseCommand(ch); ParseCommand(ch);
} }
void MainObject::socketKill(int ch) void MainObject::socketKillData(int conn_id)
{ {
KillSocket(ch); if(catch_connections[conn_id]!=NULL) {
catch_connections[conn_id]->close();
catch_garbage_timer->start(1);
}
}
void MainObject::garbageData()
{
for(int i=0;i<catch_connections.size();i++) {
if(catch_connections.at(i)!=NULL) {
if(catch_connections.at(i)->isClosing()) {
delete catch_connections.at(i);
catch_connections[i]=NULL;
rda->log(RDConfig::LogDebug,
QString().sprintf("closed connection %d",i));
}
}
}
} }
@ -1551,13 +1635,15 @@ void MainObject::SendFullStatus(int ch)
void MainObject::SendMeterLevel(int deck,short levels[2]) void MainObject::SendMeterLevel(int deck,short levels[2])
{ {
for(unsigned i=0;i<RDCATCHD_MAX_CONNECTIONS;i++) { for(int i=0;i<catch_connections.size();i++) {
if(catch_meter_enabled[i]) { if(catch_connections.at(i)!=NULL) {
if(catch_connections.at(i)->meterEnabled()) {
EchoCommand(i,QString().sprintf("RM %d 0 %d!",deck,(int)levels[0])); EchoCommand(i,QString().sprintf("RM %d 0 %d!",deck,(int)levels[0]));
EchoCommand(i,QString().sprintf("RM %d 1 %d!",deck,(int)levels[1])); EchoCommand(i,QString().sprintf("RM %d 1 %d!",deck,(int)levels[1]));
} }
} }
} }
}
void MainObject::SendDeckEvent(int deck,int number) void MainObject::SendDeckEvent(int deck,int number)
@ -1568,42 +1654,29 @@ void MainObject::SendDeckEvent(int deck,int number)
void MainObject::ParseCommand(int ch) void MainObject::ParseCommand(int ch)
{ {
char buf[256]; char data[1501];
static int c; int n;
while((c=socket[ch]->readBlock(buf,256))>0) { ServerConnection *conn=catch_connections.at(ch);
buf[c]=0; if(conn!=NULL) {
for(int i=0;i<c;i++) { while((n=conn->socket()->read(data,1500))>0) {
if(buf[i]==' ') { data[n]=0;
if(argnum[ch]<RDCATCHD_MAX_ARGS) { QString line=QString::fromUtf8(data);
args[ch][argnum[ch]][argptr[ch]]=0; for(int i=0;i<line.length();i++) {
argnum[ch]++; QChar c=line.at(i);
argptr[ch]=0; switch(c.toAscii()) {
} case '!':
else { DispatchCommand(conn);
if(debug) { conn->accum="";
printf("Argument list truncated!\n"); break;
}
} case '\r':
} case '\n':
if(buf[i]=='!') { break;
args[ch][argnum[ch]++][argptr[ch]]=0;
DispatchCommand(ch); default:
argnum[ch]=0; conn->accum+=c;
argptr[ch]=0; break;
if(socket[ch]==NULL) {
return;
}
}
if((isgraph(buf[i]))&&(buf[i]!='!')) {
if(argptr[ch]<RDCATCHD_MAX_LENGTH) {
args[ch][argnum[ch]][argptr[ch]]=buf[i];
argptr[ch]++;
}
else {
if(debug) {
LogLine(RDConfig::LogWarning,"parser arguments truncated");
}
} }
} }
} }
@ -1611,40 +1684,35 @@ void MainObject::ParseCommand(int ch)
} }
void MainObject::DispatchCommand(int ch) void MainObject::DispatchCommand(ServerConnection *conn)
{ {
int chan; int chan;
int id; int id;
int event; int event;
int code; int code;
QString str; QString str;
bool ok=false;
/* QStringList cmds=conn->accum.split(" ");
printf("RDCATCHD Received:");
for(int i=0;i<argnum[ch];i++) {
printf(" %s",args[ch][i]);
}
printf("\n");
*/
// //
// Common Commands // Common Commands
// Authentication not required to execute these! // Authentication not required to execute these!
// //
if(!strcmp(args[ch][0],"DC")) { // Drop Connection if(cmds.at(0)=="DC") { // Drop Connection
socket[ch]->close(); socketKillData(conn->id());
KillSocket(ch);
return; return;
} }
if(!strcmp(args[ch][0],"PW")) { // Password Authenticate
if(!strcmp(args[ch][1],rda->config()->password())) { if((cmds.at(0)=="PW")&&(cmds.size()==2)) { // Password Authenticate
auth[ch]=true; if(cmds.at(1)==rda->config()->password()) {
EchoCommand(ch,"PW +!"); conn->setAuthenticated(true);
EchoCommand(conn->id(),"PW +!");
return; return;
} }
else { else {
auth[ch]=false; conn->setAuthenticated(false);
EchoCommand(ch,"PW -!"); EchoCommand(conn->id(),"PW -!");
return; return;
} }
} }
@ -1653,99 +1721,97 @@ void MainObject::DispatchCommand(int ch)
// Priviledged Commands // Priviledged Commands
// Authentication required to execute these! // Authentication required to execute these!
// //
if(!auth[ch]) { if(!conn->isAuthenticated()) {
EchoArgs(ch,'-'); EchoArgs(conn->id(),'-');
return; return;
} }
if(!strcmp(args[ch][0],"RS")) { // Reset if(cmds.at(0)=="RS") { // Reset
EchoArgs(ch,'+'); EchoArgs(conn->id(),'+');
LoadEngine(); LoadEngine();
} }
if(!strcmp(args[ch][0],"RA")) { // Add Event if((cmds.at(0)=="RA")&&(cmds.size()==2)) { // Add Event
if(AddEvent(QString(args[ch][1]).toInt())) { if(AddEvent(cmds.at(1).toInt())) {
EchoArgs(ch,'+'); EchoArgs(conn->id(),'+');
BroadcastCommand(QString().sprintf("RU %s!",args[ch][1]),ch); BroadcastCommand("RU "+cmds.at(1)+"!",conn->id());
} }
else { else {
EchoArgs(ch,'-'); EchoArgs(conn->id(),'-');
} }
} }
if(!strcmp(args[ch][0],"RR")) { // Remove Event if((cmds.at(0)=="RR")&&(cmds.size()==2)) { // Remove Event
RemoveEvent(QString(args[ch][1]).toInt()); RemoveEvent(cmds.at(1).toInt());
EchoArgs(ch,'+'); EchoArgs(conn->id(),'+');
BroadcastCommand(QString().sprintf("RU %s!",args[ch][1]),ch); BroadcastCommand("RU "+cmds.at(1)+"!",conn->id());
} }
if(!strcmp(args[ch][0],"RU")) { // Update Event if((cmds.at(0)=="RU")&&(cmds.size()==2)) { // Update Event
if(UpdateEvent(QString(args[ch][1]).toInt())) { if(UpdateEvent(cmds.at(1).toInt())) {
EchoArgs(ch,'+'); EchoArgs(conn->id(),'+');
} }
else { else {
EchoArgs(ch,'-'); EchoArgs(conn->id(),'-');
} }
} }
if(!strcmp(args[ch][0],"RD")) { // Load Deck List if(cmds.at(0)=="RD") { // Load Deck List
EchoArgs(ch,'+'); EchoArgs(conn->id(),'+');
LoadDeckList(); LoadDeckList();
} }
if(!strcmp(args[ch][0],"RO")) { // Reload Time Offset if(cmds.at(0)=="RO") { // Reload Time Offset
EchoArgs(ch,'+'); EchoArgs(conn->id(),'+');
catch_engine->setTimeOffset(rda->station()->timeOffset()); catch_engine->setTimeOffset(rda->station()->timeOffset());
} }
if(!strcmp(args[ch][0],"RE")) { // Request Status if((cmds.at(0)=="RE")&&(cmds.size()==2)) { // Request Status
if(sscanf(args[ch][1],"%u",&chan)!=1) { chan=cmds.at(1).toInt(&ok);
EchoArgs(ch,'-'); if(!ok) {
EchoArgs(conn->id(),'-');
return; return;
} }
if(chan==0) { if(chan==0) {
SendFullStatus(ch); SendFullStatus(conn->id());
return; return;
} }
chan--; chan--;
if(chan<MAX_DECKS) { if(chan<MAX_DECKS) {
if(catch_record_deck_status[chan]==RDDeck::Offline) { if(catch_record_deck_status[chan]==RDDeck::Offline) {
EchoArgs(ch,'-'); EchoArgs(conn->id(),'-');
return; return;
} }
EchoCommand(ch,QString().sprintf("RE %u %d %d!", EchoCommand(conn->id(),QString().sprintf("RE %u %d %d!",
chan+1,catch_record_deck_status[chan], chan+1,
catch_record_deck_status[chan],
catch_record_id[chan])); catch_record_id[chan]));
EchoCommand(ch,QString().sprintf("MN %u %d!",chan+1, EchoCommand(conn->id(),QString().sprintf("MN %u %d!",chan+1,
catch_monitor_state[chan])); catch_monitor_state[chan]));
return; return;
} }
if((chan>=128)&&(chan<(MAX_DECKS+128))) { if((chan>=128)&&(chan<(MAX_DECKS+128))) {
if(catch_playout_deck_status[chan-128]==RDDeck::Offline) { if(catch_playout_deck_status[chan-128]==RDDeck::Offline) {
EchoArgs(ch,'-'); EchoArgs(conn->id(),'-');
return; return;
} }
EchoCommand(ch, EchoCommand(conn->id(),
QString().sprintf("RE %u %d %d!", QString().sprintf("RE %u %d %d!",
chan+1,catch_playout_deck_status[chan-128], chan+1,catch_playout_deck_status[chan-128],
catch_playout_id[chan-128])); catch_playout_id[chan-128]));
return; return;
} }
EchoArgs(ch,'-'); EchoArgs(conn->id(),'-');
return; return;
} }
if(!strcmp(args[ch][0],"RM")) { // Enable/Disable Metering if((cmds.at(0)=="RM")&&(cmds.size()==2)) { // Enable/Disable Metering
if(!strcmp(args[ch][1],"0")) { // Disable Metering conn->setMeterEnabled(cmds.at(1).trimmed()!="0");
catch_meter_enabled[ch]=false;
}
if(!strcmp(args[ch][1],"1")) { // Enable Metering
catch_meter_enabled[ch]=true;
}
} }
if(!strcmp(args[ch][0],"SR")) { // Stop Recording if((cmds.at(0)=="SR")&&(cmds.size()==2)) { // Stop Recording
if(sscanf(args[ch][1],"%d",&chan)!=1) { chan=cmds.at(1).toInt(&ok);
if(!ok) {
return; return;
} }
if((chan>0)&&(chan<(MAX_DECKS+1))) { if((chan>0)&&(chan<(MAX_DECKS+1))) {
@ -1776,21 +1842,22 @@ void MainObject::DispatchCommand(int ch)
} }
} }
if(!strcmp(args[ch][0],"RH")) { // Reload Heartbeat Configuration if(cmds.at(0)=="RH") { // Reload Heartbeat Configuration
LoadHeartbeat(); LoadHeartbeat();
} }
if(!strcmp(args[ch][0],"RX")) { // Restart Dropbox Instances if(cmds.at(0)=="RX") { // Restart Dropbox Instances
StartDropboxes(); StartDropboxes();
} }
if(!strcmp(args[ch][0],"MN")) { // Monitor State if((cmds.at(0)=="MN")&&(cmds.size()==3)) { // Monitor State
if(sscanf(args[ch][1],"%d",&chan)!=1) { chan=cmds.at(1).toInt(&ok);
if(!ok) {
return; return;
} }
if((chan>0)&&(chan<(MAX_DECKS+1))) { if((chan>0)&&(chan<(MAX_DECKS+1))) {
if(catch_monitor_port[chan-1]>=0) { if(catch_monitor_port[chan-1]>=0) {
if(args[ch][2][0]=='1') { if(cmds.at(2).toInt()!=0) {
rda->cae()->setPassthroughVolume(catch_record_card[chan-1], rda->cae()->setPassthroughVolume(catch_record_card[chan-1],
catch_record_stream[chan-1], catch_record_stream[chan-1],
catch_monitor_port[chan-1],0); catch_monitor_port[chan-1],0);
@ -1809,17 +1876,19 @@ void MainObject::DispatchCommand(int ch)
} }
} }
if(!strcmp(args[ch][0],"SC")) { // Set Exit Code if((cmds.at(0)=="SC")&&(cmds.size()>=4)) { // Set Exit Code
if(sscanf(args[ch][1],"%d",&id)!=1) { id=cmds.at(1).toInt(&ok);
if(!ok) {
return; return;
} }
if(sscanf(args[ch][2],"%d",&code)!=1) { code=cmds.at(2).toInt(&ok);
if(!ok) {
return; return;
} }
str=""; str="";
for(int i=3;i<argnum[ch];i++) { for(int i=3;i<cmds.size();i++) {
str+=QString(args[ch][i])+" "; str+=cmds.at(i)+" ";
str.stripWhiteSpace(); str=str.left(str.length()-1);
} }
if((event=GetEvent(id))<0) { if((event=GetEvent(id))<0) {
return; return;
@ -1836,25 +1905,12 @@ void MainObject::DispatchCommand(int ch)
} }
void MainObject::KillSocket(int ch)
{
istate[ch]=0;
argnum[ch]=0;
argptr[ch]=0;
auth[ch]=false;
catch_meter_enabled[ch]=false;
delete socket[ch];
socket[ch]=NULL;
LogLine(RDConfig::LogDebug,"rdcatchd dropped connection");
}
void MainObject::EchoCommand(int ch,const char *command) void MainObject::EchoCommand(int ch,const char *command)
{ {
// LogLine(RDConfig::LogDebug,QString().sprintf("rdcatchd: EchoCommand(%d,%s)",ch,command)); // LogLine(RDConfig::LogDebug,QString().sprintf("rdcatchd: EchoCommand(%d,%s)",ch,command));
if(socket[ch]->state()==Q3Socket::Connection) { ServerConnection *conn=catch_connections.at(ch);
socket[ch]->writeBlock(command,strlen(command)); if(conn->socket()->state()==QAbstractSocket::ConnectedState) {
conn->socket()->write(command,strlen(command));
} }
} }
@ -1862,9 +1918,9 @@ void MainObject::EchoCommand(int ch,const char *command)
void MainObject::BroadcastCommand(const char *command,int except_ch) void MainObject::BroadcastCommand(const char *command,int except_ch)
{ {
// LogLine(RDConfig::LogDebug,QString().sprintf("rdcatchd: BroadcastCommand(%s)",command)); // LogLine(RDConfig::LogDebug,QString().sprintf("rdcatchd: BroadcastCommand(%s)",command));
for(unsigned i=0;i<RDCATCHD_MAX_CONNECTIONS;i++) { for(int i=0;i<catch_connections.size();i++) {
if(socket[i]!=NULL) { if(catch_connections.at(i)!=NULL) {
if((int)i!=except_ch) { if(i!=except_ch) {
EchoCommand(i,command); EchoCommand(i,command);
} }
} }
@ -1874,19 +1930,11 @@ void MainObject::BroadcastCommand(const char *command,int except_ch)
void MainObject::EchoArgs(int ch,const char append) void MainObject::EchoArgs(int ch,const char append)
{ {
char command[RDCATCHD_MAX_LENGTH+2]; ServerConnection *conn=catch_connections.at(ch);
int l; if(conn!=NULL) {
QString cmd=conn->accum+append+"!";
command[0]=0; EchoCommand(ch,cmd);
for(int i=0;i<argnum[ch];i++) {
strcat(command,args[ch][i]);
strcat(command," ");
} }
l=strlen(command);
command[l]=append;
command[l+1]='!';
command[l+2]=0;
EchoCommand(ch,command);
} }
@ -1935,7 +1983,6 @@ QString MainObject::LoadEventSql()
"FORMAT," // 19 "FORMAT," // 19
"CHANNELS,"+ // 20 "CHANNELS,"+ // 20
"SAMPRATE,"+ // 21 "SAMPRATE,"+ // 21
"BITRATE,"+ // 22 "BITRATE,"+ // 22
"MACRO_CART,"+ // 23 "MACRO_CART,"+ // 23
"SWITCH_INPUT,"+ // 24 "SWITCH_INPUT,"+ // 24

View File

@ -2,7 +2,7 @@
// //
// The Rivendell Netcatcher. // The Rivendell Netcatcher.
// //
// (C) Copyright 2002-2004,2016 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2002-2018 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License version 2 as
@ -27,10 +27,11 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <qlist.h>
#include <qobject.h> #include <qobject.h>
#include <qstring.h> #include <qstring.h>
#include <q3serversocket.h> #include <qtcpserver.h>
#include <qsqldatabase.h> #include <qsignalmapper.h>
#include <qtimer.h> #include <qtimer.h>
#include <qhostaddress.h> #include <qhostaddress.h>
#include <qsignalmapper.h> #include <qsignalmapper.h>
@ -53,9 +54,6 @@
// //
// Global RDCATCHD Definitions // Global RDCATCHD Definitions
// //
#define RDCATCHD_MAX_CONNECTIONS 32
#define RDCATCHD_MAX_ARGS 10
#define RDCATCHD_MAX_LENGTH 256
#define RDCATCHD_GPO_INTERVAL 333 #define RDCATCHD_GPO_INTERVAL 333
#define RDCATCHD_MAX_MACROS 64 #define RDCATCHD_MAX_MACROS 64
#define RDCATCHD_FREE_EVENTS_INTERVAL 1000 #define RDCATCHD_FREE_EVENTS_INTERVAL 1000
@ -67,26 +65,51 @@
// //
void LogLine(RDConfig::LogPriority prio,const QString &line); void LogLine(RDConfig::LogPriority prio,const QString &line);
class ServerConnection
{
public:
ServerConnection(int id,QTcpSocket *sock);
~ServerConnection();
int id() const;
bool isAuthenticated() const;
void setAuthenticated(bool state);
bool meterEnabled() const;
void setMeterEnabled(bool state);
QTcpSocket *socket();
bool isClosing() const;
void close();
QString accum;
private:
int conn_id;
bool conn_authenticated;
bool conn_meter_enabled;
QTcpSocket *conn_socket;
bool conn_is_closing;
};
class MainObject : public QObject class MainObject : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
MainObject(QObject *parent=0); MainObject(QObject *parent=0);
public slots:
void newConnection(int fd);
private slots: private slots:
// //
// rdcatchd.cpp // rdcatchd.cpp
// //
void newConnectionData();
void rmlReceivedData(RDMacro *rml); void rmlReceivedData(RDMacro *rml);
void gpiStateChangedData(int matrix,int line,bool state); void gpiStateChangedData(int matrix,int line,bool state);
void startTimerData(int id); void startTimerData(int id);
void offsetTimerData(int id); void offsetTimerData(int id);
void engineData(int); void engineData(int);
void socketData(int); void socketReadyReadData(int conn_id);
void socketKill(int); void socketKillData(int conn_id);
void garbageData();
void isConnectedData(bool state); void isConnectedData(bool state);
void recordLoadedData(int card,int stream); void recordLoadedData(int card,int stream);
void recordingData(int card,int stream); void recordingData(int card,int stream);
@ -139,8 +162,7 @@ class MainObject : public QObject
void SendMeterLevel(int deck,short levels[2]); void SendMeterLevel(int deck,short levels[2]);
void SendDeckEvent(int deck,int number); void SendDeckEvent(int deck,int number);
void ParseCommand(int); void ParseCommand(int);
void DispatchCommand(int); void DispatchCommand(ServerConnection *conn);
void KillSocket(int);
void EchoCommand(int,const char *); void EchoCommand(int,const char *);
void BroadcastCommand(const char *,int except_ch=-1); void BroadcastCommand(const char *,int except_ch=-1);
void EchoArgs(int,const char); void EchoArgs(int,const char);
@ -183,16 +205,13 @@ class MainObject : public QObject
bool debug; bool debug;
RDTimeEngine *catch_engine; RDTimeEngine *catch_engine;
Q_INT16 tcp_port; Q_INT16 tcp_port;
Q3ServerSocket *server; QTcpServer *server;
RDCatchConnect *catch_connect; RDCatchConnect *catch_connect;
RDSocket *socket[RDCATCHD_MAX_CONNECTIONS];
char args[RDCATCHD_MAX_CONNECTIONS][RDCATCHD_MAX_ARGS][RDCATCHD_MAX_LENGTH];
int istate[RDCATCHD_MAX_CONNECTIONS];
int argnum[RDCATCHD_MAX_CONNECTIONS];
int argptr[RDCATCHD_MAX_CONNECTIONS];
bool auth[RDCATCHD_MAX_CONNECTIONS];
bool catch_meter_enabled[RDCATCHD_MAX_CONNECTIONS];
QList<ServerConnection *> catch_connections;
QSignalMapper *catch_ready_mapper;
QSignalMapper *catch_kill_mapper;
QTimer *catch_garbage_timer;
bool catch_record_status[MAX_DECKS]; bool catch_record_status[MAX_DECKS];
int catch_record_card[MAX_DECKS]; int catch_record_card[MAX_DECKS];
int catch_record_stream[MAX_DECKS]; int catch_record_stream[MAX_DECKS];

View File

@ -1,48 +0,0 @@
// rdcatchd_socket.cpp
//
// An automated event executer.
//
// (C) Copyright 2002,2016 Fred Gleason <fredg@paravelsystems.com>
//
// 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 <qapplication.h>
#include <qobject.h>
#include <q3serversocket.h>
#include <qhostaddress.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <rdcatchd_socket.h>
RDCatchdSocket::RDCatchdSocket(Q_UINT16 port,int backlog,QObject *parent)
: Q3ServerSocket(port,0,parent)
{
}
RDCatchdSocket::RDCatchdSocket(const QHostAddress &address,Q_UINT16 port,int backlog,
QObject *parent,const char *name)
: Q3ServerSocket(address,port,0,parent,name)
{
}
void RDCatchdSocket::newConnection(int fd)
{
emit connection(fd);
}

View File

@ -1,46 +0,0 @@
// rdcatchd_socket.h
//
// A telephone services server for Mithlond
//
// (C) Copyright 2002,2016 Fred Gleason <fredg@paravelsystems.com>
//
// 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 RDCATCHD_SOCKET_H
#define RDCATCHD_SOCKET_H
#include <qobject.h>
#include <qstring.h>
#include <q3serversocket.h>
#include <qhostaddress.h>
class RDCatchdSocket : public Q3ServerSocket
{
Q_OBJECT
public:
RDCatchdSocket(Q_UINT16 port,int backlog=0,QObject *parent=0);
RDCatchdSocket(const QHostAddress &address,Q_UINT16 port,int backlog=0,
QObject *parent=0,const char *name=0);
void newConnection(int socket);
signals:
void connection(int);
private:
Q3ServerSocket *socket;
};
#endif