// cae_server.cpp // // Network server for caed(8). // // (C) Copyright 2019 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 #include "cae_server.h" // // Uncomment this to send all protocol messages to syslog (DEBUG priority) // // #define __CAE_SERVER_LOG_PROTOCOL_MESSAGES CaeServerConnection::CaeServerConnection(QTcpSocket *sock) { socket=sock; authenticated=false; accum=""; meter_port=0; for(int i=0;ideleteLater(); } CaeServer::CaeServer(RDConfig *config,QObject *parent) : QObject(parent) { cae_config=config; cae_server=new QTcpServer(this); connect(cae_server,SIGNAL(newConnection()),this,SLOT(newConnectionData())); cae_ready_read_mapper=new QSignalMapper(this); connect(cae_ready_read_mapper,SIGNAL(mapped(int)), this,SLOT(readyReadData(int))); cae_connection_closed_mapper=new QSignalMapper(this); connect(cae_connection_closed_mapper,SIGNAL(mapped(int)), this,SLOT(connectionClosedData(int))); } QList CaeServer::connectionIds() const { QList ret; for(QMap::const_iterator it= cae_connections.begin();it!=cae_connections.end();it++) { ret.push_back(it.key()); } return ret; } QHostAddress CaeServer::peerAddress(int id) const { return cae_connections[id]->socket->peerAddress(); } uint16_t CaeServer::peerPort(int id) const { return cae_connections[id]->socket->peerPort(); } uint16_t CaeServer::meterPort(int id) const { return cae_connections[id]->meter_port; } void CaeServer::setMeterPort(int id,uint16_t port) { cae_connections[id]->meter_port=port; } bool CaeServer::metersEnabled(int id,unsigned card) const { return cae_connections[id]->meters_enabled[card]; } void CaeServer::setMetersEnabled(int id,unsigned card,bool state) { cae_connections[id]->meters_enabled[card]=state; } bool CaeServer::listen(const QHostAddress &addr,uint16_t port) { return cae_server->listen(addr,port); } void CaeServer::sendCommand(const QString &cmd) { for(QMap::const_iterator it= cae_connections.begin();it!=cae_connections.end();it++) { if(it.value()->authenticated) { sendCommand(it.key(),cmd); } } } void CaeServer::sendCommand(int id,const QString &cmd) { #ifdef __CAE_SERVER_LOG_PROTOCOL_MESSAGES RDApplication::syslog(cae_config,LOG_DEBUG, "send[%d]: %s",id,(const char *)cmd.toUtf8()); #endif // __CAE_SERVER_LOG_PROTOCOL_MESSAGES cae_connections.value(id)->socket->write(cmd.toAscii()); } void CaeServer::newConnectionData() { QTcpSocket *sock=cae_server->nextPendingConnection(); cae_connection_closed_mapper->setMapping(sock,sock->socketDescriptor()); connect(sock,SIGNAL(disconnected()),cae_connection_closed_mapper,SLOT(map())); cae_ready_read_mapper->setMapping(sock,sock->socketDescriptor()); connect(sock,SIGNAL(readyRead()),cae_ready_read_mapper,SLOT(map())); cae_connections[sock->socketDescriptor()]=new CaeServerConnection(sock); RDApplication::syslog(cae_config,LOG_DEBUG, "added connection %d",sock->socketDescriptor()); } void CaeServer::readyReadData(int id) { QByteArray data=cae_connections.value(id)->socket->readAll(); for(int i=0;iaccum)) { return; } break; case 10: case 13: break; default: cae_connections.value(id)->accum+=c; break; } } } void CaeServer::connectionClosedData(int id) { emit connectionDropped(id); cae_connections.value(id)->socket->disconnect(); delete cae_connections.value(id); cae_connections.remove(id); RDApplication::syslog(cae_config,LOG_DEBUG,"removed connection %d",id); } bool CaeServer::ProcessCommand(int id,const QString &cmd) { CaeServerConnection *conn=cae_connections.value(id); bool ok=false; QStringList f0=cmd.split(" ",QString::SkipEmptyParts); if(f0.size()==0) { return false; } #ifdef __CAE_SERVER_LOG_PROTOCOL_MESSAGES RDApplication::syslog(cae_config,LOG_DEBUG, "recv[%d]: %s",id,(const char *)cmd.toUtf8()); #endif // __CAE_SERVER_LOG_PROTOCOL_MESSAGES cae_connections.value(id)->accum=""; // // Unpriviledged Commands // if(f0.at(0)=="DC") { connectionClosedData(id); return true; } if(f0.at(0)=="PW") { if((f0.size()==2)&&(f0.at(1)==cae_config->password())) { conn->authenticated=true; sendCommand(id,"PW +!"); } else { conn->authenticated=false; sendCommand(id,"PW -!"); } return false; } // // Priviledged Commands // Authentication required to execute these! // if(!conn->authenticated) { return false; } bool was_processed=false; if((f0.at(0)=="LP")&&(f0.size()==3)) { // Load Playback unsigned card=f0.at(1).toUInt(&ok); if(ok&&(card=3)) { // Meter Enable uint16_t udp_port=0xFFFF&f0.at(1).toUInt(&ok); if(ok) { QList cards; for(int i=2;i