First commit of server code

Doesn't actually do anything at the moment other than allow clients to connect and login.
merge-requests/2/head
Phil Taylor 2021-02-16 16:16:46 +00:00
rodzic 87f41cc20a
commit 95028374b4
7 zmienionych plików z 723 dodań i 5 usunięć

446
udpserver.cpp 100644
Wyświetl plik

@ -0,0 +1,446 @@
#include "udpserver.h"
udpServer::udpServer(SERVERCONFIG config) :
config(config)
{
qDebug() << "Starting udp server";
}
void udpServer::init()
{
srand(time(NULL)); // Generate random key
// Convoluted way to find the external IP address, there must be a better way????
QString localhostname = QHostInfo::localHostName();
QList<QHostAddress> hostList = QHostInfo::fromName(localhostname).addresses();
foreach(const QHostAddress & address, hostList)
{
if (address.protocol() == QAbstractSocket::IPv4Protocol && address.isLoopback() == false)
{
localIP = QHostAddress(address.toString());
}
}
uint32_t addr = localIP.toIPv4Address();
qDebug() << " Got: " << QHostAddress(addr).toString();
controlId = (addr >> 8 & 0xff) << 24 | (addr & 0xff) << 16 | (config.controlPort & 0xffff);
civId = (addr >> 8 & 0xff) << 24 | (addr & 0xff) << 16 | (config.civPort & 0xffff);
audioId = (addr >> 8 & 0xff) << 24 | (addr & 0xff) << 16 | (config.audioPort & 0xffff);
udpControl = new QUdpSocket(this);
udpControl->bind(config.controlPort);
udpCiv = new QUdpSocket(this);
udpCiv->bind(config.civPort);
udpAudio = new QUdpSocket(this);
udpAudio->bind(config.audioPort);
QUdpSocket::connect(udpControl, &QUdpSocket::readyRead, this, &udpServer::controlReceived);
QUdpSocket::connect(udpCiv, &QUdpSocket::readyRead, this, &udpServer::civReceived);
QUdpSocket::connect(udpAudio, &QUdpSocket::readyRead, this, &udpServer::audioReceived);
}
udpServer::~udpServer()
{
qDebug() << "Closing udpServer";
if (udpControl != Q_NULLPTR) {
udpControl->close();
delete udpControl;
}
if (udpCiv != Q_NULLPTR) {
udpCiv->close();
delete udpCiv;
}
if (udpAudio != Q_NULLPTR) {
udpAudio->close();
delete udpAudio;
}
foreach(CLIENT* client, controlClients)
{
client->idleTimer->stop();
delete client->idleTimer;
delete& client; // Not sure how safe this is?
}
foreach(CLIENT* client, civClients)
{
client->idleTimer->stop();
delete client->idleTimer;
client->pingTimer->stop();
delete client->pingTimer;
delete& client; // Not sure how safe this is?
}
foreach(CLIENT* client, audioClients)
{
client->idleTimer->stop();
delete client->idleTimer;
client->pingTimer->stop();
delete client->pingTimer;
delete& client; // Not sure how safe this is?
}
}
void udpServer::controlReceived()
{
// Received data on control port.
while (udpControl->hasPendingDatagrams()) {
QNetworkDatagram datagram = udpControl->receiveDatagram();
QByteArray r = datagram.data();
CLIENT* current = Q_NULLPTR;
foreach(CLIENT * client, controlClients)
{
if (client->ipAddress == datagram.senderAddress() && client->port == datagram.senderPort())
{
current = client;
}
}
if (current == Q_NULLPTR)
{
current = new CLIENT();
current->connected = true;
current->timeConnected = time(NULL);
current->ipAddress = datagram.senderAddress();
current->port = datagram.senderPort();
current->myId = controlId;
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
current->socket = udpControl;
current->innerPingSeq = (quint32)rand();
current->pingSeq = 1;
current->pingTimer = new QTimer();
current->idleTimer = new QTimer();
connect(current->pingTimer, &QTimer::timeout, this, std::bind(&udpServer::sendPing, this, current, (quint16)0x00, false));
connect(current->idleTimer, &QTimer::timeout, this, std::bind(&udpServer::sendIdle, this, current, (quint16)0x00));
current->pingTimer->start(100);
current->idleTimer->start(100);
qDebug() << "New connection created from :" << current->ipAddress.toString() << ":" << QString::number(current->port);
controlClients.append(current);
}
current->lastHeard = time(NULL);
quint16 gotSeq = qFromLittleEndian<quint16>(r.mid(0x06, 2));
switch (r.length())
{
case (0x10):
if (r.mid(0, 8) == QByteArrayLiteral("\x10\x00\x00\x00\x03\x00\x00\x00")) {
qDebug() << current->ipAddress.toString() << ": Received 'are you there'";
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
sendIAmHere(current);
} // This is This is "Are you ready" in response to "I am here".
else if (r.mid(0, 8) == QByteArrayLiteral("\x10\x00\x00\x00\x06\x00\x01\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'Are you ready'";
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
sendIAmReady(current);
} // This is a retransmit request
else if (r.mid(0, 6) == QByteArrayLiteral("\x10\x00\x00\x00\x01\x00"))
{
// Just send an idle for now!
qDebug() << current->ipAddress.toString() << ": Received 'retransmit' request for " << gotSeq;
sendIdle(current, gotSeq);
} // This is a disconnect request
else if (r.mid(0, 6) == QByteArrayLiteral("\x10\x00\x00\x00\x05\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'disconnect' request";
sendIdle(current, gotSeq);
current->idleTimer->stop();
current->pingTimer->stop();
delete current;
controlClients.removeOne(current);
}
break;
qDebug() << "Got 0x14 command: " << gotSeq;
case (0x15):
if (r.mid(1, 5) == QByteArrayLiteral("\x00\x00\x00\x07\x00"))
{
// It is a ping request/response
if (r[16] == (char)0x00)
{
current->rxPingSeq = qFromLittleEndian<quint32>(r.mid(0x11, 4));
sendPing(current, gotSeq, true);
}
else if (r[16] == (char)0x01) {
// A Reply to our ping!
if (gotSeq == current->pingSeq) {
current->pingSeq++;
}
else {
qDebug() << current->ipAddress.toString() << ": Server got out of sequence ping reply. Got: " << gotSeq << " expecting: " << current->pingSeq;
}
}
}
break;
case (0x40):
// Token request
//current->authSeq = qFromLittleEndian<quint16>(r.mid(0x06, 2));
if (r[0x15] == (char)0x02) {
// Request for new token
//current->tokenTx = (quint16)rand();
sendIdle(current, gotSeq);
current->authSeq++;
sendCapabilities(current);
current->authSeq++;
sendConnectionInfo(current);
}
else if(r[0x15] == (char)0x01) {
// De-auth request
sendIdle(current, gotSeq);
current->authSeq++;
}
else if (r.mid(0x13,3) == QByteArrayLiteral("\x30\01\x05")) {
qDebug() << current->ipAddress.toString() << ": Received 'token renewal' request";
sendTokenRenewal(current, qFromLittleEndian<quint16>(r.mid(0x17, 2)));
}
break;
case (0x80):
if (r.mid(0, 8) == QByteArrayLiteral("\x80\x00\x00\x00\x00\x00\x01\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'login'";
bool userOk = false;
foreach(SERVERUSER user, config.users)
{
QByteArray usercomp;
passcode(user.username, usercomp);
QByteArray passcomp;
passcode(user.password, passcomp);
if (r.mid(0x40, usercomp.length()) == usercomp && r.mid(0x50, passcomp.length()) == passcomp)
{
userOk = true;
break;
}
}
// Generate login response
current->clientName = parseNullTerminatedString(r, 0x60);
current->authInnerSeq = qFromLittleEndian<quint16>(r.mid(0x17, 2));
current->tokenRx = qFromLittleEndian<quint16>(r.mid(0x1a, 2));
current->authSeq = qFromLittleEndian<quint16>(r.mid(0x06, 2));
current->tokenTx = (quint16)rand();
if (userOk) {
sendLoginResponse(current, true);
}
else {
qDebug() << "Username no match!";
sendLoginResponse(current, false);
}
}
break;
default:
break;
}
}
}
void udpServer::civReceived()
{
while (udpCiv->hasPendingDatagrams()) {
QNetworkDatagram datagram = udpCiv->receiveDatagram();
QByteArray r = datagram.data();
}
}
void udpServer::audioReceived()
{
while (udpAudio->hasPendingDatagrams()) {
QNetworkDatagram datagram = udpAudio->receiveDatagram();
QByteArray r = datagram.data();
}
}
void udpServer::sendIAmHere(CLIENT* c)
{
qDebug() << c->ipAddress.toString() << ": Sending I am here...";
const quint8 p[] = { 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff)
};
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
return;
}
void udpServer::sendIAmReady(CLIENT* c)
{
qDebug() << c->ipAddress.toString() << ": Sending I am ready...";
const quint8 p[] = { 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >>16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff)
};
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
return;
}
void udpServer::sendPing(CLIENT* c, quint16 seq, bool reply)
{
//qDebug() << c->ipAddress.toString() << ": Sending Ping";
quint32 pingSeq = 0;
quint16 sendSeq = seq;
if (reply) {
pingSeq = c->rxPingSeq;
}
else {
pingSeq = (quint32)((quint16)rand() << 16) | c->innerPingSeq;
sendSeq = c->pingSeq;
}
// First byte of pings "from" server is 0x00 NOT packet length!
//
const quint8 p[] = { 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,static_cast<quint8>(sendSeq & 0xff),static_cast<quint8>(sendSeq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >>8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
static_cast<quint8>(reply), static_cast<quint8>(pingSeq & 0xff), static_cast<quint8>(pingSeq >> 8 & 0xff), static_cast<quint8>(pingSeq >> 16 & 0xff), static_cast<quint8>(pingSeq >>24 & 0xff)
};
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
return;
}
void udpServer::sendIdle(CLIENT* c, quint16 seq)
{
if (seq == 0x00)
{
seq = c->txSeq;
c->txSeq++;
}
const quint8 p[] = { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,static_cast<quint8>(seq & 0xff),static_cast<quint8>(seq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId >> 24 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
};
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
return;
}
void udpServer::sendLoginResponse(CLIENT* c,bool allowed)
{
qDebug() << c->ipAddress.toString() << ": Sending Login response: " << c->txSeq;
quint8 p[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >> 8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >> 16 & 0xff), static_cast<quint8>(c->myId >> 24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >> 24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00,
static_cast<quint8>(c->authInnerSeq & 0xff), static_cast<quint8>(c->authInnerSeq >> 8 & 0xff), 0x00, static_cast<quint8>(c->tokenRx >> 0 & 0xff), static_cast<quint8>(c->tokenRx >> 8 & 0xff), 0x00, 0x00, static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
/*0x20*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x30*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x40*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x50*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
if (!allowed) {
memcpy(p + 0x30, QByteArrayLiteral("\xFF\xFF\xFF\xFE").constData(), 4);
c->idleTimer->stop();
c->pingTimer->stop();
}
else {
memcpy(p + 0x40, QByteArrayLiteral("FTTH").constData(), 4);
//memcpy(p + 0x40, QByteArrayLiteral("WFVIEW").constData(), 6);
}
c->authInnerSeq++;
c->txSeq++;
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
c->idleTimer->start(100);
return;
}
void udpServer::sendCapabilities(CLIENT* c)
{
qDebug() << c->ipAddress.toString() << ": Sending Capabilities :" << c->txSeq;
quint8 p[] = { 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >> 16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x98, 0x02, 0x02, 0x00,
static_cast<quint8>(c->authInnerSeq & 0xff), static_cast<quint8>(c->authInnerSeq >>8 & 0xff), 0x00, static_cast<quint8>(c->tokenRx & 0xff), static_cast<quint8>(c->tokenRx >>8 & 0xff), 0x00, 0x00, static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
/*0x20*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x30*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x40*/ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x90, 0xc7, 0x00,
/*0x50*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x60*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x70*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x80*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x90*/ 0x00, 0x00, 0x3f, 0x07, 0x00, 0x01, 0x8b, 0x01, 0x8b, 0x01, 0x01, 0x01, 0x00, 0x00, 0x4b, 0x00,
/*0xA0*/ 0x01, 0x50, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00,
};
// 0x42-0x51 is "replyID" need to research what this is?
// 0x90-0xa8 contains lots of seemingly random data, radio info?
//memcpy(p + 0x4d, QByteArrayLiteral("\x08\x7a\x55").constData(), 3); // IC7851
//p[0x94] = (char)0x8e; // IC-7851
memcpy(p + 0x4d, QByteArrayLiteral("\x0b\xe7\x64").constData(), 3); // IC9700
p[0x94] = (char)0xa2; // IC-9700
memcpy(p + 0x52, QByteArrayLiteral("IC-9700").constData(), 7);
memcpy(p + 0x72, QByteArrayLiteral("ICOM_VAUDIO").constData(), 11);
c->authInnerSeq++;
c->txSeq++;
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
c->idleTimer->start(100);
return;
}
void udpServer::sendConnectionInfo(CLIENT* c)
{
qDebug() << c->ipAddress.toString() << ": Sending ConnectionInfo :" << c->txSeq;
quint8 p[] = { 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >> 24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
static_cast<quint8>(c->authInnerSeq & 0xff), static_cast<quint8>(c->authInnerSeq >>8 & 0xff), 0x00, static_cast<quint8>(c->tokenRx & 0xff), static_cast<quint8>(c->tokenRx >>8 & 0xff), 0x00, 0x00, static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
/*0x20*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x90, 0xc7, 0x08, 0x7a, 0x55,
/*0x30*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x40*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x50*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x60*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x70*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x80*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 0x1a-0x1f is authid (random number?
memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7);
c->authInnerSeq++;
c->txSeq++;
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
c->idleTimer->start(100);
return;
}
void udpServer::sendTokenRenewal(CLIENT* c, quint16 seq)
{
if (seq == 0x00)
{
seq = c->authInnerSeq;
}
qDebug() << c->ipAddress.toString() << ": Sending Token renwal";
quint8 p[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >> 8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >> 16 & 0xff), static_cast<quint8>(c->myId >> 24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >> 24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00,
static_cast<quint8>(seq & 0xff), static_cast<quint8>(seq >> 8 & 0xff), 0x00, static_cast<quint8>(c->tokenRx >> 0 & 0xff), static_cast<quint8>(c->tokenRx >> 8 & 0xff), 0x00, 0x00, static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
/*0x20*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*0x30*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
c->authInnerSeq++;
c->txSeq++;
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
return;
}

105
udpserver.h 100644
Wyświetl plik

@ -0,0 +1,105 @@
#ifndef UDPSERVER_H
#define UDPSERVER_H
#include <QObject>
#include <QUdpSocket>
#include <QNetworkDatagram>
#include <QHostInfo>
#include <QTimer>
#include <QMutex>
#include <QDateTime>
#include <QByteArray>
#include <QList>
// Allow easy endian-ness conversions
#include <QtEndian>
#include <QDebug>
#include <udpserversetup.h>
extern void passcode(QString in,QByteArray& out);
extern QByteArray parseNullTerminatedString(QByteArray c, int s);
class udpServer : public QObject
{
Q_OBJECT
public:
udpServer(SERVERCONFIG config);
~udpServer();
public slots:
void init();
private:
struct CLIENT {
bool connected = false;
QHostAddress ipAddress;
quint16 port;
QByteArray clientName;
time_t timeConnected;
time_t lastHeard;
quint32 myId;
quint32 remoteId;
quint32 txSeq=1;
quint32 rxSeq;
quint16 pingSeq;
quint32 rxPingSeq; // 32bit as has other info
quint16 authInnerSeq;
quint16 authSeq;
quint32 innerPingSeq;
quint16 innerSeq;
quint16 tokenRx;
quint16 tokenTx;
QUdpSocket* socket;
QTimer* pingTimer;
QTimer* idleTimer;
// Only used for audio.
quint8 rxCodec;
quint8 txCodec;
quint16 rxSampleRate;
quint16 txSampleRate;
};
void controlReceived();
void civReceived();
void audioReceived();
void sendIAmHere(CLIENT* c);
void sendIAmReady(CLIENT* c);
void sendPing(CLIENT* c, quint16 seq, bool reply);
void sendIdle(CLIENT* c, quint16 seq);
void sendLoginResponse(CLIENT* c, bool allowed);
void sendCapabilities(CLIENT* c);
void sendConnectionInfo(CLIENT* c);
void sendTokenRenewal(CLIENT* c, quint16 seq);
SERVERCONFIG config;
QUdpSocket* udpControl = Q_NULLPTR;
QUdpSocket* udpCiv = Q_NULLPTR;
QUdpSocket* udpAudio = Q_NULLPTR;
QHostAddress localIP;
quint32 controlId = 0;
quint32 civId = 0;
quint32 audioId = 0;
struct SEQBUFENTRY {
time_t timeSent;
uint16_t seqNum;
QByteArray data;
};
QList <CLIENT*> controlClients = QList<CLIENT*>();
QList <CLIENT*> civClients = QList<CLIENT*>();
QList <CLIENT*> audioClients = QList<CLIENT*>();
};
#endif // UDPSERVER_H

Wyświetl plik

@ -6,10 +6,64 @@ udpServerSetup::udpServerSetup(QWidget* parent) :
ui(new Ui::udpServerSetup)
{
ui->setupUi(this);
ui->enableCheckbox->setChecked(true);
// Get any stored config information from the main form.
SERVERCONFIG config;
emit serverConfig(config,false); // Just send blank server config.
}
udpServerSetup::~udpServerSetup()
{
delete ui;
}
// Slot to receive config.
void udpServerSetup::receiveServerConfig(SERVERCONFIG conf)
{
qDebug() << "Getting server config";
ui->enableCheckbox->setChecked(conf.enabled);
ui->controlPortText->setText(QString::number(conf.controlPort));
ui->civPortText->setText(QString::number(conf.civPort));
ui->audioPortText->setText(QString::number(conf.audioPort));
int row = 0;
foreach (SERVERUSER user, conf.users)
{
if (ui->usersTable->rowCount() <= row) {
ui->usersTable->insertRow(ui->usersTable->rowCount());
ui->usersTable->setHorizontalHeaderItem(ui->usersTable->rowCount() - 1, new QTableWidgetItem("User " + QString::number(row + 1)));
}
ui->usersTable->setItem(row, 0, new QTableWidgetItem(user.username));
ui->usersTable->setItem(row, 1, new QTableWidgetItem(user.password));
row++;
}
// Delete any rows no longer needed
for (int count = row; count < ui->usersTable->rowCount(); count++)
{
ui->usersTable->removeRow(count);
}
}
void udpServerSetup::accept()
{
qDebug() << "Server config stored";
SERVERCONFIG config;
config.enabled = ui->enableCheckbox->isChecked();
config.controlPort = ui->controlPortText->text().toInt();
config.civPort = ui->civPortText->text().toInt();
config.audioPort = ui->audioPortText->text().toInt();
config.users.clear();
for (int row = 0; row < ui->usersTable->model()->rowCount(); row++)
{
SERVERUSER user;
user.username = ui->usersTable->item(row, 0)->text();
user.password = ui->usersTable->item(row, 1)->text();
config.users.append(user);
}
emit serverConfig(config,true);
this->hide();
}

Wyświetl plik

@ -3,6 +3,23 @@
#include <QDialog>
#include <QDebug>
struct SERVERUSER {
QString username;
QString password;
quint8 userType;
};
struct SERVERCONFIG {
bool enabled;
quint16 controlPort;
quint16 civPort;
quint16 audioPort;
QList <SERVERUSER> users;
};
namespace Ui {
class udpServerSetup;
}
@ -15,8 +32,15 @@ public:
explicit udpServerSetup(QWidget* parent = 0);
~udpServerSetup();
public slots:
void receiveServerConfig(SERVERCONFIG conf);
signals:
void serverConfig(SERVERCONFIG conf, bool store);
private:
Ui::udpServerSetup* ui;
void accept();
};
#endif // UDPSERVER_H

Wyświetl plik

@ -27,6 +27,10 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, QWidget *parent
sat = new satelliteSetup();
srv = new udpServerSetup();
connect(this, SIGNAL(sendServerConfig(SERVERCONFIG)), srv, SLOT(receiveServerConfig(SERVERCONFIG)));
connect(srv, SIGNAL(serverConfig(SERVERCONFIG, bool)), this, SLOT(serverConfigRequested(SERVERCONFIG, bool)));
haveRigCaps = false;
@ -187,6 +191,20 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, QWidget *parent
// serialPortRig = prefs.serialPortRadio;
// }
// Start server if enabled in config
if (serverConfig.enabled) {
udp = new udpServer(serverConfig);
serverThread = new QThread(this);
udp->moveToThread(serverThread);
connect(this, SIGNAL(initServer()), udp, SLOT(init()));
connect(serverThread, SIGNAL(finished()), udp, SLOT(deleteLater()));
serverThread->start();
emit initServer();
}
plot = ui->plot; // rename it waterfall.
wf = ui->waterfall;
@ -393,6 +411,10 @@ wfmain::~wfmain()
{
rigThread->quit();
rigThread->wait();
if (serverThread != Q_NULLPTR) {
serverThread->quit();
serverThread->wait();
}
delete ui;
}
@ -743,6 +765,25 @@ void wfmain::loadSettings()
ui->audioOutputCombo->setCurrentIndex(audioInputIndex);
settings.endGroup();
settings.beginGroup("Server");
serverConfig.enabled = settings.value("ServerEnabled", false).toBool();
serverConfig.controlPort = settings.value("ServerControlPort", 50001).toInt();
serverConfig.civPort = settings.value("ServerCivPort", 50002).toInt();
serverConfig.audioPort = settings.value("ServerAudioPort", 50003).toInt();
int numUsers = settings.value("ServerNumUsers", 0).toInt();
serverConfig.users.clear();
for (int f = 0; f < numUsers; f++)
{
SERVERUSER user;
user.username = settings.value("ServerUsername" + f, "").toString();
user.password = settings.value("ServerPassword" + f, "").toString();
serverConfig.users.append(user);
}
settings.endGroup();
// Memory channels
settings.beginGroup("Memory");
@ -776,6 +817,9 @@ void wfmain::loadSettings()
settings.endArray();
settings.endGroup();
emit sendServerConfig(serverConfig);
}
@ -894,6 +938,22 @@ void wfmain::saveSettings()
settings.endGroup();
settings.beginGroup("Server");
settings.setValue("ServerEnabled", serverConfig.enabled);
settings.setValue("ServerControlPort", serverConfig.controlPort);
settings.setValue("ServerCivPort", serverConfig.civPort);
settings.setValue("ServerAudioPort", serverConfig.audioPort);
settings.setValue("ServerNumUsers", serverConfig.users.count());
for (int f = 0; f < serverConfig.users.count(); f++)
{
settings.setValue("ServerUsername" + f, serverConfig.users[f].username);
settings.setValue("ServerPassword" + f, serverConfig.users[f].password);
}
settings.endGroup();
settings.sync(); // Automatic, not needed (supposedly)
}
@ -2463,3 +2523,19 @@ void wfmain::on_debugBtn_clicked()
//emit getMode();
sat->show();
}
// Slot to send/receive server config.
// If store is true then write to config otherwise send current config by signal
void wfmain::serverConfigRequested(SERVERCONFIG conf, bool store)
{
if (!store) {
emit sendServerConfig(serverConfig);
}
else {
// Store config in file!
qDebug() << "Storing server config";
serverConfig = conf;
}
}

Wyświetl plik

@ -19,6 +19,7 @@
#include "calibrationwindow.h"
#include "satellitesetup.h"
#include "udpserversetup.h"
#include "udpserver.h"
#include <qcustomplot.h>
#include <qserialportinfo.h>
@ -78,6 +79,8 @@ signals:
QString username, QString password, quint16 buffer, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec);
void sendCloseComm();
void sendChangeBufferSize(quint16 value);
void initServer();
void sendServerConfig(SERVERCONFIG conf);
private slots:
void shortcutF1();
@ -141,6 +144,7 @@ private slots:
void handlePlotScroll(QWheelEvent *);
void runDelayedCommand();
void showStatusBarText(QString text);
void serverConfigRequested(SERVERCONFIG conf, bool store);
// void on_getFreqBtn_clicked();
@ -346,13 +350,14 @@ private:
rigCommander * rig=Q_NULLPTR;
QThread * rigThread=Q_NULLPTR;
QThread* rigThread = Q_NULLPTR;
QCPColorMap * colorMap;
QCPColorMapData * colorMapData;
QCPColorScale * colorScale;
QTimer * delayedCommand;
QTimer * pttTimer;
QStringList modes;
int currentModeIndex;
QStringList spans;
@ -448,11 +453,17 @@ private:
calibrationWindow *cal;
satelliteSetup *sat;
udpServerSetup* srv;
udpServerSetup *srv;
udpServer *udp;
QThread *serverThread = Q_NULLPTR;
void bandStackBtnClick();
bool waitingForBandStackRtn;
char bandStkBand;
char bandStkRegCode;
SERVERCONFIG serverConfig;
};
Q_DECLARE_METATYPE(struct rigCapabilities) ;

Wyświetl plik

@ -84,7 +84,8 @@ SOURCES += main.cpp\
audiohandler.cpp \
calibrationwindow.cpp \
satellitesetup.cpp \
udpserversetup.cpp
udpserversetup.cpp \
udpserver.cpp
HEADERS += wfmain.h \
commhandler.h \
@ -96,7 +97,8 @@ HEADERS += wfmain.h \
audiohandler.h \
calibrationwindow.h \
satellitesetup.h \
udpserversetup.h
udpserversetup.h \
udpserver.h
FORMS += wfmain.ui \