From 95028374b43fd106355c8009a641e39a805adbdd Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 16 Feb 2021 16:16:46 +0000 Subject: [PATCH 1/5] First commit of server code Doesn't actually do anything at the moment other than allow clients to connect and login. --- udpserver.cpp | 446 +++++++++++++++++++++++++++++++++++++++++++++ udpserver.h | 105 +++++++++++ udpserversetup.cpp | 56 +++++- udpserversetup.h | 24 +++ wfmain.cpp | 76 ++++++++ wfmain.h | 15 +- wfview.pro | 6 +- 7 files changed, 723 insertions(+), 5 deletions(-) create mode 100644 udpserver.cpp create mode 100644 udpserver.h diff --git a/udpserver.cpp b/udpserver.cpp new file mode 100644 index 0000000..bf93fdf --- /dev/null +++ b/udpserver.cpp @@ -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 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(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(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(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(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(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(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(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(r.mid(0x17, 2)); + current->tokenRx = qFromLittleEndian(r.mid(0x1a, 2)); + current->authSeq = qFromLittleEndian(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(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), + static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(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(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), + static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >>16 & 0xff), static_cast(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(sendSeq & 0xff),static_cast(sendSeq >>8 & 0xff), + static_cast(c->myId & 0xff), static_cast(c->myId >>8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), + static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), + static_cast(reply), static_cast(pingSeq & 0xff), static_cast(pingSeq >> 8 & 0xff), static_cast(pingSeq >> 16 & 0xff), static_cast(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(seq & 0xff),static_cast(seq >>8 & 0xff), + static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), + static_cast(c->remoteId >> 24 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(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(c->txSeq & 0xff), static_cast(c->txSeq >> 8 & 0xff), + static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >> 24 & 0xff), + static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 24 & 0xff), + /*0x10*/ 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, + static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(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(c->txSeq & 0xff), static_cast(c->txSeq >>8 & 0xff), + static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >>24 & 0xff), + static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), + /*0x10*/ 0x00, 0x00, 0x00, 0x98, 0x02, 0x02, 0x00, + static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >>8 & 0xff), 0x00, static_cast(c->tokenRx & 0xff), static_cast(c->tokenRx >>8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(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(c->txSeq & 0xff), static_cast(c->txSeq >>8 & 0xff), + static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >> 24 & 0xff), + static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), + /*0x10*/ 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >>8 & 0xff), 0x00, static_cast(c->tokenRx & 0xff), static_cast(c->tokenRx >>8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(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(c->txSeq & 0xff), static_cast(c->txSeq >> 8 & 0xff), + static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >> 24 & 0xff), + static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 24 & 0xff), + /*0x10*/ 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00, + static_cast(seq & 0xff), static_cast(seq >> 8 & 0xff), 0x00, static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(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; +} + + + diff --git a/udpserver.h b/udpserver.h new file mode 100644 index 0000000..3bc0125 --- /dev/null +++ b/udpserver.h @@ -0,0 +1,105 @@ +#ifndef UDPSERVER_H +#define UDPSERVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Allow easy endian-ness conversions +#include + +#include + +#include + +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 controlClients = QList(); + QList civClients = QList(); + QList audioClients = QList(); + +}; + + +#endif // UDPSERVER_H \ No newline at end of file diff --git a/udpserversetup.cpp b/udpserversetup.cpp index 13ed5b6..785d55c 100644 --- a/udpserversetup.cpp +++ b/udpserversetup.cpp @@ -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(); +} diff --git a/udpserversetup.h b/udpserversetup.h index 4a72329..0c10361 100644 --- a/udpserversetup.h +++ b/udpserversetup.h @@ -3,6 +3,23 @@ #include +#include + + +struct SERVERUSER { + QString username; + QString password; + quint8 userType; +}; + +struct SERVERCONFIG { + bool enabled; + quint16 controlPort; + quint16 civPort; + quint16 audioPort; + QList 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 diff --git a/wfmain.cpp b/wfmain.cpp index c014cfb..61767c6 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -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; + } + +} \ No newline at end of file diff --git a/wfmain.h b/wfmain.h index d49db7e..cb3bd4c 100644 --- a/wfmain.h +++ b/wfmain.h @@ -19,6 +19,7 @@ #include "calibrationwindow.h" #include "satellitesetup.h" #include "udpserversetup.h" +#include "udpserver.h" #include #include @@ -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) ; diff --git a/wfview.pro b/wfview.pro index c588fe1..42cab9d 100644 --- a/wfview.pro +++ b/wfview.pro @@ -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 \ From b52629f72b7c9ea6df8ac00e8bc69b6d3795e3c5 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 16 Feb 2021 16:42:56 +0000 Subject: [PATCH 2/5] Fix server user saving error. --- wfmain.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wfmain.cpp b/wfmain.cpp index 61767c6..3d97306 100644 --- a/wfmain.cpp +++ b/wfmain.cpp @@ -772,13 +772,13 @@ void wfmain::loadSettings() 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(); + int numUsers = settings.value("ServerNumUsers", 2).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(); + user.username = settings.value("ServerUsername_" + QString::number(f), "").toString(); + user.password = settings.value("ServerPassword_" + QString::number(f), "").toString(); serverConfig.users.append(user); } @@ -947,8 +947,8 @@ void wfmain::saveSettings() 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.setValue("ServerUsername_" + QString::number(f), serverConfig.users[f].username); + settings.setValue("ServerPassword_" + QString::number(f), serverConfig.users[f].password); } settings.endGroup(); From e3a3844f3edc8f9df6a8032bce4ea4cf6b8505da Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 16 Feb 2021 20:55:30 +0000 Subject: [PATCH 3/5] Few fixes to server setup ui. --- udpserver.cpp | 61 +++++++++++++++++++++++++---------------- udpserver.h | 4 +-- udpserversetup.cpp | 28 +++++++++++++++---- udpserversetup.h | 3 +++ udpserversetup.ui | 67 ++-------------------------------------------- 5 files changed, 68 insertions(+), 95 deletions(-) diff --git a/udpserver.cpp b/udpserver.cpp index bf93fdf..119de2c 100644 --- a/udpserver.cpp +++ b/udpserver.cpp @@ -66,7 +66,7 @@ udpServer::~udpServer() { client->idleTimer->stop(); delete client->idleTimer; - delete& client; // Not sure how safe this is? + //delete& client; // Not sure how safe this is? } foreach(CLIENT* client, civClients) { @@ -74,7 +74,7 @@ udpServer::~udpServer() delete client->idleTimer; client->pingTimer->stop(); delete client->pingTimer; - delete& client; // Not sure how safe this is? + //delete& client; // Not sure how safe this is? } foreach(CLIENT* client, audioClients) { @@ -82,7 +82,7 @@ udpServer::~udpServer() delete client->idleTimer; client->pingTimer->stop(); delete client->pingTimer; - delete& client; // Not sure how safe this is? + //delete& client; // Not sure how safe this is? } } @@ -112,8 +112,8 @@ void udpServer::controlReceived() current->myId = controlId; current->remoteId = qFromLittleEndian(r.mid(8, 4)); current->socket = udpControl; - current->innerPingSeq = (quint32)rand(); - current->pingSeq = 1; + current->innerPingSeq = (quint16)rand(); + current->pingSeq = (quint8)rand() << 8 | (quint8)rand(); current->pingTimer = new QTimer(); current->idleTimer = new QTimer(); connect(current->pingTimer, &QTimer::timeout, this, std::bind(&udpServer::sendPing, this, current, (quint16)0x00, false)); @@ -225,9 +225,9 @@ void udpServer::controlReceived() // Generate login response current->clientName = parseNullTerminatedString(r, 0x60); current->authInnerSeq = qFromLittleEndian(r.mid(0x17, 2)); - current->tokenRx = qFromLittleEndian(r.mid(0x1a, 2)); current->authSeq = qFromLittleEndian(r.mid(0x06, 2)); - current->tokenTx = (quint16)rand(); + current->tokenRx = qFromLittleEndian(r.mid(0x1a, 2)); + current->tokenTx = (quint32)(quint8)rand() | (quint8)rand() << 8 | (quint8) rand << 16 | (quint16)rand() << 24; if (userOk) { sendLoginResponse(current, true); @@ -251,6 +251,8 @@ void udpServer::civReceived() while (udpCiv->hasPendingDatagrams()) { QNetworkDatagram datagram = udpCiv->receiveDatagram(); QByteArray r = datagram.data(); + qDebug() << "CIV Data from :" << datagram.senderAddress().toString() << ":" << QString::number(datagram.senderPort()); + } } @@ -259,6 +261,7 @@ void udpServer::audioReceived() while (udpAudio->hasPendingDatagrams()) { QNetworkDatagram datagram = udpAudio->receiveDatagram(); QByteArray r = datagram.data(); + qDebug() << "Audio Data from :" << datagram.senderAddress().toString() << ":" << QString::number(datagram.senderPort()); } } @@ -290,22 +293,22 @@ 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; + pingSeq = (quint32)((quint8)(rand() & 0xff)) | (quint16)c->innerPingSeq << 8 | (quint8)0x06 << 24; + seq = c->pingSeq; } // First byte of pings "from" server is 0x00 NOT packet length! // - const quint8 p[] = { 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,static_cast(sendSeq & 0xff),static_cast(sendSeq >>8 & 0xff), + const quint8 p[] = { 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,static_cast(seq & 0xff),static_cast(seq >>8 & 0xff), static_cast(c->myId & 0xff), static_cast(c->myId >>8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), static_cast(reply), static_cast(pingSeq & 0xff), static_cast(pingSeq >> 8 & 0xff), static_cast(pingSeq >> 16 & 0xff), static_cast(pingSeq >>24 & 0xff) }; + c->innerPingSeq++; c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); return; @@ -313,11 +316,13 @@ void udpServer::sendPing(CLIENT* c, quint16 seq, bool reply) 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(seq & 0xff),static_cast(seq >>8 & 0xff), static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), @@ -335,7 +340,10 @@ void udpServer::sendLoginResponse(CLIENT* c,bool allowed) static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >> 24 & 0xff), static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 24 & 0xff), /*0x10*/ 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, - static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, + static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), + static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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, @@ -365,7 +373,10 @@ void udpServer::sendCapabilities(CLIENT* c) static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >>24 & 0xff), static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), /*0x10*/ 0x00, 0x00, 0x00, 0x98, 0x02, 0x02, 0x00, - static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >>8 & 0xff), 0x00, static_cast(c->tokenRx & 0xff), static_cast(c->tokenRx >>8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, + static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), + static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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, @@ -380,10 +391,11 @@ void udpServer::sendCapabilities(CLIENT* c) // 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 + //p[0x94] = (char)0x8e; // IC-7851 C-IV address + memcpy(p + 0x4d, QByteArrayLiteral("\x0b\xe7\x64").constData(), 3); // IC9700 - p[0x94] = (char)0xa2; // IC-9700 - + p[0x94] = (char)0xa2; // IC-9700 C-IV address + memcpy(p + 0x52, QByteArrayLiteral("IC-9700").constData(), 7); memcpy(p + 0x72, QByteArrayLiteral("ICOM_VAUDIO").constData(), 11); @@ -401,7 +413,10 @@ void udpServer::sendConnectionInfo(CLIENT* c) static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >> 24 & 0xff), static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), /*0x10*/ 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, - static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >>8 & 0xff), 0x00, static_cast(c->tokenRx & 0xff), static_cast(c->tokenRx >>8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, + static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), + static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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, @@ -412,7 +427,8 @@ void udpServer::sendConnectionInfo(CLIENT* c) }; // 0x1a-0x1f is authid (random number? - memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7); + //memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7); + memcpy(p + 0x40, QByteArrayLiteral("IC-9700").constData(), 7); c->authInnerSeq++; c->txSeq++; @@ -423,16 +439,15 @@ void udpServer::sendConnectionInfo(CLIENT* c) 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(c->txSeq & 0xff), static_cast(c->txSeq >> 8 & 0xff), static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >> 24 & 0xff), static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 24 & 0xff), /*0x10*/ 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00, - static_cast(seq & 0xff), static_cast(seq >> 8 & 0xff), 0x00, static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), 0x00, 0x00, static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, + static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), + static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), + static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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 }; diff --git a/udpserver.h b/udpserver.h index 3bc0125..5b22e1f 100644 --- a/udpserver.h +++ b/udpserver.h @@ -49,10 +49,10 @@ private: quint32 rxPingSeq; // 32bit as has other info quint16 authInnerSeq; quint16 authSeq; - quint32 innerPingSeq; + quint16 innerPingSeq; quint16 innerSeq; quint16 tokenRx; - quint16 tokenTx; + quint32 tokenTx; QUdpSocket* socket; QTimer* pingTimer; diff --git a/udpserversetup.cpp b/udpserversetup.cpp index 785d55c..5ae61f5 100644 --- a/udpserversetup.cpp +++ b/udpserversetup.cpp @@ -31,7 +31,6 @@ void udpServerSetup::receiveServerConfig(SERVERCONFIG conf) { 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)); @@ -42,6 +41,8 @@ void udpServerSetup::receiveServerConfig(SERVERCONFIG conf) { ui->usersTable->removeRow(count); } + ui->usersTable->insertRow(ui->usersTable->rowCount()); + //ui->usersTable->setHorizontalHeaderItem(ui->usersTable->rowCount() - 1, new QTableWidgetItem("User " + QString::number(row + 1))); } @@ -58,12 +59,29 @@ void udpServerSetup::accept() 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); + if (ui->usersTable->item(row, 0) != NULL && ui->usersTable->item(row, 1) != NULL) + { + SERVERUSER user; + user.username = ui->usersTable->item(row, 0)->text(); + user.password = ui->usersTable->item(row, 1)->text(); + config.users.append(user); + + } + else { + ui->usersTable->removeRow(row); + } } emit serverConfig(config,true); this->hide(); } + + +void udpServerSetup::on_usersTable_cellClicked(int row, int col) +{ + qDebug() << "Clicked on " << row << "," << col; + if (row == ui->usersTable->model()->rowCount() - 1 && ui->usersTable->item(row, 0) != NULL && ui->usersTable->item(row, 1) != NULL) { + ui->usersTable->insertRow(ui->usersTable->rowCount()); + } + +} \ No newline at end of file diff --git a/udpserversetup.h b/udpserversetup.h index 0c10361..b144761 100644 --- a/udpserversetup.h +++ b/udpserversetup.h @@ -32,6 +32,9 @@ public: explicit udpServerSetup(QWidget* parent = 0); ~udpServerSetup(); +private slots: + void on_usersTable_cellClicked(int row, int col); + public slots: void receiveServerConfig(SERVERCONFIG conf); diff --git a/udpserversetup.ui b/udpserversetup.ui index 5fcf2e4..a293138 100644 --- a/udpserversetup.ui +++ b/udpserversetup.ui @@ -7,7 +7,7 @@ 0 0 368 - 262 + 341 @@ -143,7 +143,7 @@ - + 0 0 @@ -193,56 +193,6 @@ false - - - User 1 - - - - - User 2 - - - - - User 3 - - - - - User 4 - - - - - User 5 - - - - - User 6 - - - - - User 7 - - - - - User 8 - - - - - User 9 - - - - - User 10 - - Username @@ -260,19 +210,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - From 6b99d122a29733518cc90f7e028b8fe019cc526d Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 16 Feb 2021 20:57:48 +0000 Subject: [PATCH 4/5] Fix udpserver compile warnings --- udpserver.cpp | 6 +++--- udpserver.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/udpserver.cpp b/udpserver.cpp index 119de2c..875c876 100644 --- a/udpserver.cpp +++ b/udpserver.cpp @@ -200,7 +200,7 @@ void udpServer::controlReceived() } else if (r.mid(0x13,3) == QByteArrayLiteral("\x30\01\x05")) { qDebug() << current->ipAddress.toString() << ": Received 'token renewal' request"; - sendTokenRenewal(current, qFromLittleEndian(r.mid(0x17, 2))); + sendTokenRenewal(current); } break; case (0x80): @@ -227,7 +227,7 @@ void udpServer::controlReceived() current->authInnerSeq = qFromLittleEndian(r.mid(0x17, 2)); current->authSeq = qFromLittleEndian(r.mid(0x06, 2)); current->tokenRx = qFromLittleEndian(r.mid(0x1a, 2)); - current->tokenTx = (quint32)(quint8)rand() | (quint8)rand() << 8 | (quint8) rand << 16 | (quint16)rand() << 24; + current->tokenTx = (quint32)((quint16)rand() | (quint16)rand() << 16) ; if (userOk) { sendLoginResponse(current, true); @@ -437,7 +437,7 @@ void udpServer::sendConnectionInfo(CLIENT* c) return; } -void udpServer::sendTokenRenewal(CLIENT* c, quint16 seq) +void udpServer::sendTokenRenewal(CLIENT* c) { qDebug() << c->ipAddress.toString() << ": Sending Token renwal"; quint8 p[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast(c->txSeq & 0xff), static_cast(c->txSeq >> 8 & 0xff), diff --git a/udpserver.h b/udpserver.h index 5b22e1f..716444e 100644 --- a/udpserver.h +++ b/udpserver.h @@ -75,7 +75,7 @@ private: void sendLoginResponse(CLIENT* c, bool allowed); void sendCapabilities(CLIENT* c); void sendConnectionInfo(CLIENT* c); - void sendTokenRenewal(CLIENT* c, quint16 seq); + void sendTokenRenewal(CLIENT* c); SERVERCONFIG config; From e3b3d2a3f4981adba7f46cc1a365b187bd0025c3 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Wed, 17 Feb 2021 23:10:26 +0000 Subject: [PATCH 5/5] server now accepting civ/audio connection. --- udphandler.cpp | 8 + udpserver.cpp | 735 ++++++++++++++++++++++++++++++++++--------------- udpserver.h | 26 +- 3 files changed, 545 insertions(+), 224 deletions(-) diff --git a/udphandler.cpp b/udphandler.cpp index f424a14..d1240fa 100644 --- a/udphandler.cpp +++ b/udphandler.cpp @@ -298,18 +298,25 @@ void udpHandler::sendRequestSerialAndAudio() 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast(myId & 0xff), static_cast(myId >> 8 & 0xff), static_cast(myId >> 16 & 0xff), static_cast(myId >> 24 & 0xff), static_cast(remoteId & 0xff), static_cast(remoteId >> 8 & 0xff), static_cast(remoteId >> 16 & 0xff), static_cast(remoteId >> 24 & 0xff), + 0x00, 0x00, 0x00, 0x80, 0x01, 0x03, 0x00, static_cast(authInnerSendSeq & 0xff), static_cast(authInnerSendSeq >> 8 & 0xff), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, rxCodec, txCodec, 0x00, 0x00, static_cast(rxSampleRate >> 8 & 0xff), static_cast(rxSampleRate & 0xff), 0x00, 0x00, static_cast(txSampleRate >> 8 & 0xff), static_cast(txSampleRate & 0xff), 0x00, 0x00, static_cast(civPort >> 8 & 0xff), static_cast(civPort & 0xff), @@ -346,6 +353,7 @@ void udpHandler::sendLogin() // Only used on control stream. qDebug() << this->metaObject()->className() << ": Sending login packet"; uint16_t authStartID = rand() | rand() << 8; + //uint16_t authStartID = 0x7866; QByteArray usernameEncoded; QByteArray passwordEncoded; passcode(username, usernameEncoded); diff --git a/udpserver.cpp b/udpserver.cpp index 875c876..2f90d4e 100644 --- a/udpserver.cpp +++ b/udpserver.cpp @@ -33,14 +33,16 @@ void udpServer::init() udpControl = new QUdpSocket(this); udpControl->bind(config.controlPort); + udpCiv = new QUdpSocket(this); - udpCiv->bind(config.civPort); udpAudio = new QUdpSocket(this); - udpAudio->bind(config.audioPort); + + udpAudio->bind(config.audioPort); + udpCiv->bind(config.civPort); QUdpSocket::connect(udpControl, &QUdpSocket::readyRead, this, &udpServer::controlReceived); - QUdpSocket::connect(udpCiv, &QUdpSocket::readyRead, this, &udpServer::civReceived); QUdpSocket::connect(udpAudio, &QUdpSocket::readyRead, this, &udpServer::audioReceived); + QUdpSocket::connect(udpCiv, &QUdpSocket::readyRead, this, &udpServer::civReceived); } @@ -48,6 +50,33 @@ udpServer::~udpServer() { qDebug() << "Closing udpServer"; + + foreach(CLIENT * client, controlClients) + { + client->idleTimer->stop(); + delete client->idleTimer; + client->pingTimer->stop(); + delete client->pingTimer; + client->wdTimer->stop(); + delete client->wdTimer; + //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->pingTimer->stop(); + delete client->pingTimer; + //delete& client; // Not sure how safe this is? + } + + if (udpControl != Q_NULLPTR) { udpControl->close(); delete udpControl; @@ -62,29 +91,6 @@ udpServer::~udpServer() } - 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? - } - } @@ -106,25 +112,206 @@ void udpServer::controlReceived() { current = new CLIENT(); current->connected = true; - current->timeConnected = time(NULL); + current->isStreaming = false; + current->timeConnected = QDateTime::currentDateTime(); current->ipAddress = datagram.senderAddress(); current->port = datagram.senderPort(); + current->civPort = config.civPort; + current->audioPort = config.audioPort; current->myId = controlId; current->remoteId = qFromLittleEndian(r.mid(8, 4)); current->socket = udpControl; current->innerPingSeq = (quint16)rand(); - current->pingSeq = (quint8)rand() << 8 | (quint8)rand(); + current->pingSeq = (quint8)rand() << 8 | (quint8)rand(); current->pingTimer = new QTimer(); current->idleTimer = new QTimer(); + current->wdTimer = 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)); + connect(current->wdTimer, &QTimer::timeout, this, std::bind(&udpServer::sendWatchdog, this, current)); + current->pingTimer->start(100); + current->idleTimer->start(100); + current->wdTimer->start(10000); + qDebug() << "New connection created from :" << current->ipAddress.toString() << ":" << QString::number(current->port); + controlClients.append(current); + } + + current->lastHeard = QDateTime::currentDateTime(); + quint16 gotSeq = qFromLittleEndian(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(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(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(); + current->wdTimer->stop(); + delete current; + controlClients.removeOne(current); + + } + break; + case (0x14): + // Watchdog packet. + break; + 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(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->authInnerSeq = qFromLittleEndian(r.mid(0x16, 4)); + if (r[0x15] == (char)0x02) { + // Request for new token + //current->tokenTx = (quint16)rand(); + qDebug() << current->ipAddress.toString() << ": Received create token request"; + sendCapabilities(current); + current->authInnerSeq = 0x00; + sendConnectionInfo(current); + } + else { + qDebug() << current->ipAddress.toString() << ": Received token request"; + sendTokenResponse(current, r[0x15]); + } + 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(r.mid(0x16, 4)); + current->tokenRx = qFromLittleEndian(r.mid(0x1a, 2)); + current->tokenTx = (quint32)((quint16)rand() | (quint16)rand() << 16); + + if (userOk) { + sendLoginResponse(current, gotSeq, true); + } + else { + qDebug() << "Username no match!"; + sendLoginResponse(current, gotSeq, false); + } + + } + break; + case 0x90: + qDebug() << current->ipAddress.toString() << ": Received request for radio connection"; + // Request to start audio and civ! + current->isStreaming = true; + current->rxCodec = r[0x72]; + current->txCodec = r[0x73]; + current->rxSampleRate = qFromBigEndian(r.mid(0x76, 2)); + current->txSampleRate = qFromBigEndian(r.mid(0x7a, 2)); + //current->civPort = qFromBigEndian(r.mid(0x7e, 2)); // Ignore port sent from client and tell it which to use + //current->audioPort = qFromBigEndian(r.mid(0x82, 2)); + current->txBufferLen = qFromBigEndian(r.mid(0x86, 2)); + current->authInnerSeq = qFromLittleEndian(r.mid(0x16, 4)); + current->connSeq = qFromLittleEndian(r.mid(0x2c, 4)); + sendStatus(current); + sendConnectionInfo(current); + + break; + + default: + qDebug() << "Unknown length packet received: " << r.length(); + break; + } + } +} + + +void udpServer::civReceived() +{ + while (udpCiv->hasPendingDatagrams()) { + QNetworkDatagram datagram = udpCiv->receiveDatagram(); + QByteArray r = datagram.data(); + + CLIENT* current = Q_NULLPTR; + + foreach(CLIENT * client, civClients) + { + if (client->ipAddress == datagram.senderAddress() && client->port == datagram.senderPort()) + { + current = client; + } + } + if (current == Q_NULLPTR) + { + current = new CLIENT(); + current->connected = true; + current->timeConnected = QDateTime::currentDateTime(); + current->ipAddress = datagram.senderAddress(); + current->port = datagram.senderPort(); + current->myId = civId; + current->remoteId = qFromLittleEndian(r.mid(8, 4)); + current->socket = udpCiv; + current->innerPingSeq = (quint16)rand(); + current->pingSeq = (quint8)rand() << 8 | (quint8)rand(); + current->pingTimer = new QTimer(); + current->idleTimer = new QTimer(); + current->wdTimer = 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); + civClients.append(current); } - current->lastHeard = time(NULL); + current->lastHeard = QDateTime::currentDateTime(); quint16 gotSeq = qFromLittleEndian(r.mid(0x06, 2)); switch (r.length()) @@ -159,7 +346,9 @@ void udpServer::controlReceived() } break; - qDebug() << "Got 0x14 command: " << gotSeq; + case (0x14): + // Watchdog packet. + break; case (0x15): if (r.mid(1, 5) == QByteArrayLiteral("\x00\x00\x00\x07\x00")) { @@ -176,286 +365,396 @@ void udpServer::controlReceived() current->pingSeq++; } else { - qDebug() << current->ipAddress.toString() << ": Server got out of sequence ping reply. Got: " << gotSeq << " expecting: " << current->pingSeq; + qDebug() << current->ipAddress.toString() << ": Civ got out of sequence ping reply. Got: " << gotSeq << " expecting: " << current->pingSeq; } } } break; - case (0x40): - // Token request - //current->authSeq = qFromLittleEndian(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); - } - 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(r.mid(0x17, 2)); - current->authSeq = qFromLittleEndian(r.mid(0x06, 2)); - current->tokenRx = qFromLittleEndian(r.mid(0x1a, 2)); - current->tokenTx = (quint32)((quint16)rand() | (quint16)rand() << 16) ; - - 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(); - qDebug() << "CIV Data from :" << datagram.senderAddress().toString() << ":" << QString::number(datagram.senderPort()); - - } -} - void udpServer::audioReceived() { while (udpAudio->hasPendingDatagrams()) { QNetworkDatagram datagram = udpAudio->receiveDatagram(); QByteArray r = datagram.data(); - qDebug() << "Audio Data from :" << datagram.senderAddress().toString() << ":" << QString::number(datagram.senderPort()); + CLIENT* current = Q_NULLPTR; + + foreach(CLIENT * client, audioClients) + { + if (client != Q_NULLPTR && client->ipAddress == datagram.senderAddress() && client->port == datagram.senderPort()) + { + current = client; + } + } + if (current == Q_NULLPTR) + { + current = new CLIENT(); + current->connected = true; + current->timeConnected = QDateTime::currentDateTime(); + current->ipAddress = datagram.senderAddress(); + current->port = datagram.senderPort(); + current->myId = audioId; + current->remoteId = qFromLittleEndian(r.mid(8, 4)); + current->socket = udpAudio; + current->innerPingSeq = (quint16)rand(); + current->pingSeq = (quint8)rand() << 8 | (quint8)rand(); + current->pingTimer = new QTimer(); + connect(current->pingTimer, &QTimer::timeout, this, std::bind(&udpServer::sendPing, this, current, (quint16)0x00, false)); + current->pingTimer->start(100); + qDebug() << "New connection created from :" << current->ipAddress.toString() << ":" << QString::number(current->port); + audioClients.append(current); + } + + current->lastHeard = QDateTime::currentDateTime(); + quint16 gotSeq = qFromLittleEndian(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(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(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->pingTimer->stop(); + delete current; + controlClients.removeOne(current); + + } + break; + case (0x14): + // Watchdog packet. + break; + 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(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() << ": Civ got out of sequence ping reply. Got: " << gotSeq << " expecting: " << current->pingSeq; + } + } + } + break; + default: + break; + } + } } + + + +#define IDLE_SIZE 0x10 + 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(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), - static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff) - }; + + quint8 p[IDLE_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + p[0x04] = (char)0x04; + qToLittleEndian(c->txSeq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); + c->txSeq++; 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(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), - static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >>16 & 0xff), static_cast(c->remoteId >>24 & 0xff) - }; + + quint8 p[IDLE_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + p[0x04] = (char)0x06; + qToLittleEndian(c->txSeq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + + c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); + c->txSeq++; + return; +} + +void udpServer::sendIdle(CLIENT* c, quint16 seq) +{ + if (seq == 0x00) + { + seq = c->txSeq; + c->txSeq++; + } + + quint8 p[IDLE_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + qToLittleEndian(seq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); return; } + + + +#define PING_SIZE 0x15 void udpServer::sendPing(CLIENT* c, quint16 seq, bool reply) { //qDebug() << c->ipAddress.toString() << ": Sending Ping"; quint32 pingSeq = 0; + quint8 pingReply = 0; if (reply) { pingSeq = c->rxPingSeq; + pingReply = 1; } else { pingSeq = (quint32)((quint8)(rand() & 0xff)) | (quint16)c->innerPingSeq << 8 | (quint8)0x06 << 24; seq = c->pingSeq; } - // First byte of pings "from" server is 0x00 NOT packet length! - // - const quint8 p[] = { 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,static_cast(seq & 0xff),static_cast(seq >>8 & 0xff), - static_cast(c->myId & 0xff), static_cast(c->myId >>8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), - static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), - static_cast(reply), static_cast(pingSeq & 0xff), static_cast(pingSeq >> 8 & 0xff), static_cast(pingSeq >> 16 & 0xff), static_cast(pingSeq >>24 & 0xff) - }; + // First byte of pings "from" server can be either 0x00 or packet length! + + quint8 p[PING_SIZE]; + memset(p, 0x0, sizeof(p)); + if (!reply) { + qToLittleEndian(sizeof(p), p + 0x00); + } + p[0x04] = (char)0x07; + qToLittleEndian(seq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + qToLittleEndian(pingSeq, p + 0x11); + p[0x10] = pingReply; + c->innerPingSeq++; 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(seq & 0xff),static_cast(seq >>8 & 0xff), - static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >>24 & 0xff), - static_cast(c->remoteId >> 24 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(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) +#define LOGINRESP_SIZE 0x60 +void udpServer::sendLoginResponse(CLIENT* c,quint16 seq, bool allowed) { qDebug() << c->ipAddress.toString() << ": Sending Login response: " << c->txSeq; - quint8 p[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast(c->txSeq & 0xff), static_cast(c->txSeq >> 8 & 0xff), - static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >> 24 & 0xff), - static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 24 & 0xff), - /*0x10*/ 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, - static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, - static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), - static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), - static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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 - }; + + quint8 p[LOGINRESP_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + qToLittleEndian(seq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + memcpy(p + 0x13, QByteArrayLiteral("\x50\x02\00").constData(), 3); + qToLittleEndian(c->authInnerSeq, p + 0x16); + qToLittleEndian(c->tokenRx, p + 0x1a); + qToLittleEndian(c->tokenTx, p + 0x1c); if (!allowed) { memcpy(p + 0x30, QByteArrayLiteral("\xFF\xFF\xFF\xFE").constData(), 4); c->idleTimer->stop(); c->pingTimer->stop(); + c->wdTimer->stop(); } else { - memcpy(p + 0x40, QByteArrayLiteral("FTTH").constData(), 4); - //memcpy(p + 0x40, QByteArrayLiteral("WFVIEW").constData(), 6); + //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; } +#define CAP_SIZE 0xa8 void udpServer::sendCapabilities(CLIENT* c) { qDebug() << c->ipAddress.toString() << ": Sending Capabilities :" << c->txSeq; - quint8 p[] = { 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast(c->txSeq & 0xff), static_cast(c->txSeq >>8 & 0xff), - static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >>24 & 0xff), - static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), - /*0x10*/ 0x00, 0x00, 0x00, 0x98, 0x02, 0x02, 0x00, - static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, - static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), - static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), - static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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 C-IV address + quint8 p[CAP_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + qToLittleEndian(c->txSeq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + memcpy(p + 0x13, QByteArrayLiteral("\x98\x02\02").constData(), 3); + qToLittleEndian(c->authInnerSeq, p + 0x16); + qToLittleEndian(c->tokenRx, p + 0x1a); + qToLittleEndian(c->tokenTx, p + 0x1c); + p[0x41] = (char)0x01; + p[0x49] = (char)0x10; + p[0x4a] = (char)0x80; + memcpy(p + 0x49, QByteArrayLiteral("\x10\x80").constData(), 2); + memcpy(p + 0x4d, QByteArrayLiteral("\x90\xc7\x0b\xe7").constData(), 4); // IC9700 + memcpy(p + 0x92, QByteArrayLiteral("\x3f\x07\x00\x01\x8b\x01\x8b\x01\x01\x01\x00\x00\x4b").constData(), 13); + memcpy(p + 0xa0, QByteArrayLiteral("\x01\x50\x00\x90\x01").constData(), 5); - memcpy(p + 0x4d, QByteArrayLiteral("\x0b\xe7\x64").constData(), 3); // IC9700 - p[0x94] = (char)0xa2; // IC-9700 C-IV address - - memcpy(p + 0x52, QByteArrayLiteral("IC-9700").constData(), 7); + p[0x94] = rigciv; + p[0x51] = (char)0x64; + memcpy(p + 0x52, rigname.toLocal8Bit(), rigname.length()); 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); + c->txSeq++; return; } +// When client has requested civ/audio connection, this will contain their details +// Also used to display currently connected used information. +#define CONNINFO_SIZE 0x90 void udpServer::sendConnectionInfo(CLIENT* c) { qDebug() << c->ipAddress.toString() << ": Sending ConnectionInfo :" << c->txSeq; - quint8 p[] = { 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast(c->txSeq & 0xff), static_cast(c->txSeq >>8 & 0xff), - static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >>16 & 0xff), static_cast(c->myId >> 24 & 0xff), - static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >>24 & 0xff), - /*0x10*/ 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, - static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, - static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), - static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), - static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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 - }; + quint8 p[CONNINFO_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + qToLittleEndian(c->txSeq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + p[0x13] = (char)0x80; + p[0x14] = (char)0x03; + qToLittleEndian(c->authInnerSeq, p + 0x16); + qToLittleEndian(c->tokenRx, p + 0x1a); + qToLittleEndian(c->tokenTx, p + 0x1c); + p[0x27] = (char)0x10; + p[0x28] = (char)0x80; + memcpy(p + 0x2b, QByteArrayLiteral("\x90\xc7\x0b\xe7\x64").constData(), 5); // THIS SHOULD BE DYNAMIC? // 0x1a-0x1f is authid (random number? - //memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7); - memcpy(p + 0x40, QByteArrayLiteral("IC-9700").constData(), 7); + // memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7); - c->authInnerSeq++; - c->txSeq++; + memcpy(p + 0x40, rigname.toLocal8Bit(), rigname.length()); + + // This is the current streaming client (should we support multiple clients?) + if (c->isStreaming) { + p[0x60] = (char)0x01; + memcpy(p + 0x64, c->clientName.constData(), c->clientName.length()); + qToBigEndian(c->ipAddress.toIPv4Address(), p + 0x84); + qToLittleEndian(c->connSeq, p + 0x2c); + + } c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); c->idleTimer->start(100); + c->txSeq++; return; } -void udpServer::sendTokenRenewal(CLIENT* c) +#define TOKEN_SIZE 0x40 +void udpServer::sendTokenResponse(CLIENT* c, quint8 type) { - qDebug() << c->ipAddress.toString() << ": Sending Token renwal"; - quint8 p[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, static_cast(c->txSeq & 0xff), static_cast(c->txSeq >> 8 & 0xff), - static_cast(c->myId & 0xff), static_cast(c->myId >> 8 & 0xff), static_cast(c->myId >> 16 & 0xff), static_cast(c->myId >> 24 & 0xff), - static_cast(c->remoteId & 0xff), static_cast(c->remoteId >> 8 & 0xff), static_cast(c->remoteId >> 16 & 0xff), static_cast(c->remoteId >> 24 & 0xff), - /*0x10*/ 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00, - static_cast(c->authInnerSeq & 0xff), static_cast(c->authInnerSeq >> 8 & 0xff), 0x00, - static_cast(c->tokenRx >> 0 & 0xff), static_cast(c->tokenRx >> 8 & 0xff), - static_cast(c->tokenTx & 0xff), static_cast(c->tokenTx >> 8 & 0xff), - static_cast(c->tokenTx >> 16 & 0xff), static_cast(c->tokenTx >> 24 & 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++; + qDebug() << c->ipAddress.toString() << ": Sending Token response for type: " << type; + + quint8 p[TOKEN_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + qToLittleEndian(c->txSeq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + p[0x13] = (char)0x30; + p[0x14] = (char)0x02; + p[0x15] = (char)type; + qToLittleEndian(c->authInnerSeq, p + 0x16); + qToLittleEndian(c->tokenRx, p + 0x1a); + qToLittleEndian(c->tokenTx, p + 0x1c); + + c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); + c->idleTimer->start(100); c->txSeq++; + return; +} + +#define WATCHDOG_SIZE 0x14 +void udpServer::sendWatchdog(CLIENT* c) +{ + QDateTime now = QDateTime::currentDateTime(); + qint32 deciSeconds = (qint32)c->timeConnected.msecsTo(now)/100; + + quint8 p[WATCHDOG_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + p[0x04] = (char)0x01; + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + qToLittleEndian(deciSeconds, p + 0x10); + qToLittleEndian(deciSeconds+1, p + 0x12); + + c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); return; + + +} +#define STATUS_SIZE 0x50 + +void udpServer::sendStatus(CLIENT* c) +{ + qDebug() << c->ipAddress.toString() << ": Sending Status"; + + quint8 p[STATUS_SIZE]; + memset(p, 0x0, sizeof(p)); + qToLittleEndian(sizeof(p), p + 0x00); + qToLittleEndian(c->txSeq, p + 0x06); + qToLittleEndian(c->myId, p + 0x08); + qToLittleEndian(c->remoteId, p + 0x0c); + p[0x13] = (char)0x40; + p[0x14] = (char)0x02; + p[0x15] = (char)0x03; + qToLittleEndian(c->authInnerSeq, p + 0x16); + qToLittleEndian(c->tokenRx, p + 0x1a); + qToLittleEndian(c->tokenTx, p + 0x1c); + p[0x27] = (char)0x10; + p[0x28] = (char)0x80; + p[0x2b] = (char)0x90; + qToLittleEndian(c->connSeq, p + 0x2c); + + qToBigEndian(c->civPort, p + 0x42); + qToBigEndian(c->audioPort, p + 0x46); + + // Send this to reject the request to tx/rx audio/civ + //memcpy(p + 0x30, QByteArrayLiteral("\xff\xff\xff\xfe").constData(), 4); + + + c->txSeq++; + c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port); + + } - - diff --git a/udpserver.h b/udpserver.h index 716444e..8cb66d9 100644 --- a/udpserver.h +++ b/udpserver.h @@ -39,24 +39,32 @@ private: QHostAddress ipAddress; quint16 port; QByteArray clientName; - time_t timeConnected; - time_t lastHeard; + QDateTime timeConnected; + QDateTime lastHeard; + bool isStreaming; + quint16 civPort; + quint16 audioPort; + quint16 txBufferLen; quint32 myId; quint32 remoteId; - quint32 txSeq=1; + quint32 txSeq=0; quint32 rxSeq; + quint32 connSeq; quint16 pingSeq; quint32 rxPingSeq; // 32bit as has other info - quint16 authInnerSeq; + quint32 authInnerSeq; quint16 authSeq; quint16 innerPingSeq; quint16 innerSeq; quint16 tokenRx; quint32 tokenTx; + quint8 wdseq; QUdpSocket* socket; + QTimer* pingTimer; QTimer* idleTimer; + QTimer* wdTimer; // Only used for audio. quint8 rxCodec; @@ -72,10 +80,13 @@ private: 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 sendLoginResponse(CLIENT* c, quint16 seq, bool allowed); void sendCapabilities(CLIENT* c); void sendConnectionInfo(CLIENT* c); - void sendTokenRenewal(CLIENT* c); + void sendTokenResponse(CLIENT* c,quint8 type); + void sendWatchdog(CLIENT* c); + void sendStatus(CLIENT* c); + SERVERCONFIG config; @@ -89,6 +100,9 @@ private: quint32 civId = 0; quint32 audioId = 0; + QString rigname = "IC-9700"; + quint8 rigciv = 0xa2; + struct SEQBUFENTRY { time_t timeSent; uint16_t seqNum;