wfview/udpserver.cpp

1955 wiersze
70 KiB
C++

#include "udpserver.h"
2021-02-23 21:21:22 +00:00
#include "logcategories.h"
#define STALE_CONNECTION 15
#define LOCK_PERIOD 10 // time to attempt to lock Mutex in ms
2022-01-12 20:01:17 +00:00
#define AUDIO_SEND_PERIOD 20 //
udpServer::udpServer(SERVERCONFIG* config, QObject* parent) :
2022-05-08 18:33:22 +00:00
QObject(parent),
config(config)
{
qInfo(logUdpServer()) << "Starting udp server";
}
2022-01-16 18:47:13 +00:00
void udpServer::init()
{
2022-01-04 21:26:03 +00:00
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* rig : config->rigs)
2022-01-26 09:49:52 +00:00
{
2022-01-27 19:11:16 +00:00
qDebug(logUdpServer()) << "CIV:" << rig->civAddr;
qDebug(logUdpServer()) << "Model:" << rig->modelName;
qDebug(logUdpServer()) << "Name:" << rig->rigName;
qDebug(logUdpServer()) << "CIV:" << rig->civAddr;
2022-01-26 09:49:52 +00:00
qDebug(logUdpServer()).noquote() << QString("GUID: {%1%2%3%4-%5%6-%7%8-%9%10-%11%12%13%14%15%16}")
2022-01-27 19:11:16 +00:00
.arg(rig->guid[0], 2, 16, QLatin1Char('0'))
.arg(rig->guid[1], 2, 16, QLatin1Char('0'))
.arg(rig->guid[2], 2, 16, QLatin1Char('0'))
.arg(rig->guid[3], 2, 16, QLatin1Char('0'))
.arg(rig->guid[4], 2, 16, QLatin1Char('0'))
.arg(rig->guid[5], 2, 16, QLatin1Char('0'))
.arg(rig->guid[6], 2, 16, QLatin1Char('0'))
.arg(rig->guid[7], 2, 16, QLatin1Char('0'))
.arg(rig->guid[8], 2, 16, QLatin1Char('0'))
.arg(rig->guid[9], 2, 16, QLatin1Char('0'))
.arg(rig->guid[10], 2, 16, QLatin1Char('0'))
.arg(rig->guid[11], 2, 16, QLatin1Char('0'))
.arg(rig->guid[12], 2, 16, QLatin1Char('0'))
.arg(rig->guid[13], 2, 16, QLatin1Char('0'))
.arg(rig->guid[14], 2, 16, QLatin1Char('0'))
.arg(rig->guid[15], 2, 16, QLatin1Char('0'))
2022-01-26 09:49:52 +00:00
;
}
2022-01-29 22:50:58 +00:00
srand(time(NULL)); // Generate random
//timeStarted.start();
// 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());
}
}
2022-04-20 12:35:23 +00:00
QString macTemp;
2021-02-28 20:10:07 +00:00
foreach(QNetworkInterface netInterface, QNetworkInterface::allInterfaces())
{
// Return only the first non-loopback MAC Address
if (!(netInterface.flags() & QNetworkInterface::IsLoopBack)) {
2022-04-20 12:35:23 +00:00
macTemp = netInterface.hardwareAddress();
2021-02-28 20:10:07 +00:00
}
}
2022-04-20 12:35:23 +00:00
memcpy(&macAddress, macTemp.toLocal8Bit(), 6);
memcpy(&macAddress, QByteArrayLiteral("\x00\x90\xc7").constData(), 3);
uint32_t addr = localIP.toIPv4Address();
2022-04-20 12:35:23 +00:00
qInfo(logUdpServer()) << "My IP Address:" << QHostAddress(addr).toString();
2022-04-20 12:35:23 +00:00
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);
2022-04-20 12:35:23 +00:00
qInfo(logUdpServer()) << "Server Binding Control to: " << config->controlPort;
udpControl = new QUdpSocket(this);
2022-04-20 12:35:23 +00:00
udpControl->bind(config->controlPort);
2021-02-28 20:10:07 +00:00
QUdpSocket::connect(udpControl, &QUdpSocket::readyRead, this, &udpServer::controlReceived);
2022-04-20 12:35:23 +00:00
qInfo(logUdpServer()) << "Server Binding CIV to: " << config->civPort;
udpCiv = new QUdpSocket(this);
2022-04-20 12:35:23 +00:00
udpCiv->bind(config->civPort);
2021-02-28 20:10:07 +00:00
QUdpSocket::connect(udpCiv, &QUdpSocket::readyRead, this, &udpServer::civReceived);
2022-04-20 12:35:23 +00:00
qInfo(logUdpServer()) << "Server Binding Audio to: " << config->audioPort;
2021-02-28 20:10:07 +00:00
udpAudio = new QUdpSocket(this);
2022-04-20 12:35:23 +00:00
udpAudio->bind(config->audioPort);
QUdpSocket::connect(udpAudio, &QUdpSocket::readyRead, this, &udpServer::audioReceived);
2021-06-11 09:20:09 +00:00
wdTimer = new QTimer();
connect(wdTimer, &QTimer::timeout, this, &udpServer::watchdog);
wdTimer->start(500);
}
udpServer::~udpServer()
{
qInfo(logUdpServer()) << "Closing udpServer";
foreach(CLIENT * client, controlClients)
{
2021-10-20 11:47:16 +00:00
deleteConnection(&controlClients, client);
2021-02-28 20:10:07 +00:00
}
foreach(CLIENT * client, civClients)
{
2021-10-20 11:47:16 +00:00
deleteConnection(&civClients, client);
}
2021-10-20 11:47:16 +00:00
foreach(CLIENT * client, audioClients)
{
2021-10-20 11:47:16 +00:00
deleteConnection(&audioClients, client);
2021-03-22 09:10:03 +00:00
}
2022-01-29 22:50:58 +00:00
// Now all connections are deleted, close and delete the sockets
if (udpControl != Q_NULLPTR) {
udpControl->close();
delete udpControl;
}
if (udpCiv != Q_NULLPTR) {
udpCiv->close();
delete udpCiv;
}
if (udpAudio != Q_NULLPTR) {
udpAudio->close();
delete udpAudio;
}
2022-02-02 16:02:40 +00:00
status.message = QString("");
emit haveNetworkStatus(status);
}
2021-02-28 20:10:07 +00:00
void udpServer::receiveRigCaps(rigCapabilities caps)
{
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* rig: config->rigs) {
if (!memcmp(rig->guid, caps.guid, GUIDLEN) || config->rigs.size()==1) {
2022-01-26 09:49:52 +00:00
// Matching rig, fill-in missing details
2022-01-27 19:11:16 +00:00
rig->rigAvailable = true;
rig->modelName = caps.modelName;
rig->civAddr = caps.civ;
2022-01-29 22:50:58 +00:00
if (rig->rigName == "<NONE>") {
2022-01-27 19:11:16 +00:00
rig->rigName = caps.modelName;
2022-01-26 09:49:52 +00:00
}
}
}
2021-02-28 20:10:07 +00:00
}
2022-01-29 22:50:58 +00:00
void udpServer::controlReceived()
{
// Received data on control port.
while (udpControl->hasPendingDatagrams()) {
QNetworkDatagram datagram = udpControl->receiveDatagram();
QByteArray r = datagram.data();
CLIENT* current = Q_NULLPTR;
if (datagram.senderAddress().isNull() || datagram.senderPort() == 65535 || datagram.senderPort() == 0)
2021-02-18 09:14:41 +00:00
return;
foreach(CLIENT * client, controlClients)
{
if (client != Q_NULLPTR)
{
if (client->ipAddress == datagram.senderAddress() && client->port == datagram.senderPort())
{
current = client;
}
}
}
if (current == Q_NULLPTR)
{
current = new CLIENT();
2021-05-14 08:55:02 +00:00
current->type = "Control";
current->connected = true;
current->isAuthenticated = false;
current->isStreaming = false;
current->timeConnected = QDateTime::currentDateTime();
current->ipAddress = datagram.senderAddress();
current->port = datagram.senderPort();
2022-04-20 12:35:23 +00:00
current->civPort = config->civPort;
current->audioPort = config->audioPort;
current->myId = controlId;
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
current->socket = udpControl;
current->pingSeq = (quint8)rand() << 8 | (quint8)rand();
2021-02-28 20:10:07 +00:00
current->pingTimer = new QTimer();
connect(current->pingTimer, &QTimer::timeout, this, std::bind(&udpServer::sendPing, this, &controlClients, current, (quint16)0x00, false));
current->pingTimer->start(100);
2021-02-28 20:10:07 +00:00
current->idleTimer = new QTimer();
connect(current->idleTimer, &QTimer::timeout, this, std::bind(&udpServer::sendControl, this, current, (quint8)0x00, (quint16)0x00));
current->idleTimer->start(100);
2021-02-28 20:10:07 +00:00
current->retransmitTimer = new QTimer();
connect(current->retransmitTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRetransmitRequest, this, current));
current->retransmitTimer->start(RETRANSMIT_PERIOD);
qInfo(logUdpServer()) << current->ipAddress.toString() << ": New Control connection created";
2021-05-14 08:55:02 +00:00
2022-04-20 12:35:23 +00:00
if (connMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-04-20 12:35:23 +00:00
// Quick hack to replace the GUID with a MAC address.
if (config->rigs.size() == 1) {
memset(config->rigs.first()->guid, 0, GUIDLEN);
config->rigs.first()->commoncap = (quint16)0x8010;
memcpy(config->rigs.first()->macaddress, macAddress, 6);
memcpy(current->guid, config->rigs.first()->guid, GUIDLEN);
}
controlClients.append(current);
connMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock connMutex()";
}
}
current->lastHeard = QDateTime::currentDateTime();
switch (r.length())
{
2021-06-01 16:49:48 +00:00
case (CONTROL_SIZE):
{
control_packet_t in = (control_packet_t)r.constData();
if (in->type == 0x05)
{
2021-06-01 16:49:48 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received 'disconnect' request";
sendControl(current, 0x00, in->seq);
2021-06-11 08:56:19 +00:00
if (current->audioClient != Q_NULLPTR) {
deleteConnection(&audioClients, current->audioClient);
}
if (current->civClient != Q_NULLPTR) {
deleteConnection(&civClients, current->civClient);
}
2021-06-01 16:49:48 +00:00
deleteConnection(&controlClients, current);
2021-06-11 09:20:09 +00:00
return;
2021-02-21 21:05:58 +00:00
}
2021-06-01 16:49:48 +00:00
break;
}
case (PING_SIZE):
{
ping_packet_t in = (ping_packet_t)r.constData();
if (in->type == 0x07)
{
2021-06-01 16:49:48 +00:00
// It is a ping request/response
2021-02-21 21:05:58 +00:00
2021-06-01 16:49:48 +00:00
if (in->reply == 0x00)
{
current->rxPingTime = in->time;
sendPing(&controlClients, current, in->seq, true);
}
else if (in->reply == 0x01) {
2022-01-05 14:45:34 +00:00
// A Reply to our ping!
if (in->seq == current->pingSeq) {
current->pingSeq++;
}
}
}
2021-06-01 16:49:48 +00:00
break;
}
case (TOKEN_SIZE):
{
// Token request
token_packet_t in = (token_packet_t)r.constData();
current->rxSeq = in->seq;
current->authInnerSeq = in->innerseq;
2022-04-20 12:35:23 +00:00
memcpy(current->guid, in->guid, GUIDLEN);
if (in->requesttype == 0x02 && in->requestreply == 0x01) {
2021-06-01 16:49:48 +00:00
// Request for new token
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received create token request";
sendCapabilities(current);
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* radio : config->rigs) {
2022-01-27 19:11:16 +00:00
sendConnectionInfo(current, radio->guid);
2022-01-26 09:49:52 +00:00
}
}
2022-04-20 12:35:23 +00:00
else if (in->requesttype == 0x01 && in->requestreply == 0x01) {
2021-06-01 16:49:48 +00:00
// Token disconnect
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received token disconnect request";
2022-04-20 12:35:23 +00:00
sendTokenResponse(current, in->requesttype);
2021-06-01 16:49:48 +00:00
}
2022-04-20 12:35:23 +00:00
else if (in->requesttype == 0x04 && in->requestreply == 0x01) {
2021-06-01 16:49:48 +00:00
// Disconnect audio/civ
2022-04-20 12:35:23 +00:00
sendTokenResponse(current, in->requesttype);
2021-06-01 16:49:48 +00:00
current->isStreaming = false;
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* radio : config->rigs) {
if (!memcmp(radio->guid, current->guid, GUIDLEN) || config->rigs.size() == 1)
2022-01-26 09:49:52 +00:00
{
2022-01-27 19:11:16 +00:00
sendConnectionInfo(current, radio->guid);
2022-01-26 09:49:52 +00:00
}
}
2021-06-01 16:49:48 +00:00
}
else {
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received token request";
2022-04-20 12:35:23 +00:00
sendTokenResponse(current, in->requesttype);
2021-06-01 16:49:48 +00:00
}
break;
}
case (LOGIN_SIZE):
{
login_packet_t in = (login_packet_t)r.constData();
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received 'login'";
2022-04-20 12:35:23 +00:00
foreach(SERVERUSER user, config->users)
{
2021-06-01 16:49:48 +00:00
QByteArray usercomp;
passcode(user.username, usercomp);
QByteArray passcomp;
passcode(user.password, passcomp);
if (!user.username.trimmed().isEmpty() && !user.password.trimmed().isEmpty() && !strcmp(in->username, usercomp.constData()) &&
(!strcmp(in->password, user.password.toUtf8()) || !strcmp(in->password, passcomp.constData())))
{
current->isAuthenticated = true;
2021-06-01 16:49:48 +00:00
current->user = user;
break;
}
2021-02-21 21:05:58 +00:00
}
2021-06-01 16:49:48 +00:00
// Generate login response
current->rxSeq = in->seq;
current->clientName = in->name;
current->authInnerSeq = in->innerseq;
current->tokenRx = in->tokrequest;
current->tokenTx = (quint8)rand() | (quint8)rand() << 8 | (quint8)rand() << 16 | (quint8)rand() << 24;
if (current->isAuthenticated) {
2021-06-01 16:49:48 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << ": User " << current->user.username << " login OK";
}
else {
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Incorrect username/password";
}
2021-10-21 23:24:15 +00:00
sendLoginResponse(current, current->isAuthenticated);
2021-06-01 16:49:48 +00:00
break;
}
case (CONNINFO_SIZE):
{
conninfo_packet_t in = (conninfo_packet_t)r.constData();
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received request for radio connection";
// Request to start audio and civ!
current->isStreaming = true;
current->rxSeq = in->seq;
current->rxCodec = in->rxcodec;
current->txCodec = in->txcodec;
current->rxSampleRate = qFromBigEndian<quint32>(in->rxsample);
current->txSampleRate = qFromBigEndian<quint32>(in->txsample);
current->txBufferLen = qFromBigEndian<quint32>(in->txbuffer);
current->authInnerSeq = in->innerseq;
2022-01-29 22:50:58 +00:00
memcpy(current->guid, in->guid, GUIDLEN);
2021-06-01 16:49:48 +00:00
sendStatus(current);
current->authInnerSeq = 0x00;
2022-01-26 09:49:52 +00:00
sendConnectionInfo(current,in->guid);
2021-06-01 16:49:48 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << ": rxCodec:" << current->rxCodec << " txCodec:" << current->txCodec <<
" rxSampleRate" << current->rxSampleRate <<
2021-08-14 18:02:04 +00:00
" txSampleRate" << current->txSampleRate <<
2021-06-01 16:49:48 +00:00
" txBufferLen" << current->txBufferLen;
2021-06-04 07:24:26 +00:00
2022-01-27 19:11:16 +00:00
audioSetup setup;
2022-04-20 12:35:23 +00:00
setup.resampleQuality = config->resampleQuality;
for (RIGCONFIG* radio : config->rigs) {
if ((!memcmp(radio->guid, current->guid, GUIDLEN) || config->rigs.size()==1) && radio->txaudio == Q_NULLPTR && !config->lan)
2022-01-27 19:11:16 +00:00
{
radio->txAudioSetup.codec = current->txCodec;
radio->txAudioSetup.sampleRate=current->txSampleRate;
2022-01-27 19:11:16 +00:00
radio->txAudioSetup.isinput = false;
radio->txAudioSetup.latency = current->txBufferLen;
2022-04-10 22:13:51 +00:00
2022-01-27 19:11:16 +00:00
outAudio.isinput = false;
2021-06-04 07:24:26 +00:00
2022-05-12 14:53:48 +00:00
if (radio->txAudioSetup.type == qtAudio) {
radio->txaudio = new audioHandler();
}
else if (radio->txAudioSetup.type == portAudio) {
radio->txaudio = new paHandler();
}
else if (radio->txAudioSetup.type == rtAudio) {
radio->txaudio = new rtHandler();
}
else
{
qCritical(logAudio()) << "Unsupported Transmit Audio Handler selected!";
}
2022-05-02 15:11:35 +00:00
if (radio->txaudio != Q_NULLPTR) {
radio->txAudioThread = new QThread(this);
radio->txAudioThread->setObjectName("txAudio()");
2021-03-22 09:10:03 +00:00
2021-09-22 10:07:07 +00:00
radio->txaudio->moveToThread(radio->txAudioThread);
2021-03-22 09:10:03 +00:00
radio->txAudioThread->start(QThread::TimeCriticalPriority);
2021-03-22 09:10:03 +00:00
connect(this, SIGNAL(setupTxAudio(audioSetup)), radio->txaudio, SLOT(init(audioSetup)));
connect(radio->txAudioThread, SIGNAL(finished()), radio->txaudio, SLOT(deleteLater()));
// Not sure how we make this work in QT5.9?
2022-05-14 12:45:56 +00:00
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
QMetaObject::invokeMethod(radio->txaudio, [=]() {
radio->txaudio->init(radio->txAudioSetup);
}, Qt::QueuedConnection);
2022-01-27 22:51:28 +00:00
#else
emit setupTxAudio(radio->txAudioSetup);
#warning "QT 5.9 is not fully supported multiple rigs will NOT work!"
2022-01-27 22:51:28 +00:00
#endif
hasTxAudio = datagram.senderAddress();
2021-03-22 09:10:03 +00:00
connect(this, SIGNAL(haveAudioData(audioPacket)), radio->txaudio, SLOT(incomingAudio(audioPacket)));
}
2022-01-27 19:11:16 +00:00
}
if ((!memcmp(radio->guid, current->guid, GUIDLEN) || config->rigs.size() == 1) && radio->rxaudio == Q_NULLPTR && !config->lan)
2022-01-27 19:11:16 +00:00
{
radio->rxAudioSetup.codec = current->rxCodec;
radio->rxAudioSetup.sampleRate=current->rxSampleRate;
2022-01-27 19:11:16 +00:00
radio->rxAudioSetup.latency = current->txBufferLen;
radio->rxAudioSetup.isinput = true;
2022-04-10 22:13:51 +00:00
memcpy(radio->rxAudioSetup.guid, radio->guid, GUIDLEN);
2022-05-12 14:53:48 +00:00
//radio->rxaudio = new audioHandler();
if (radio->rxAudioSetup.type == qtAudio) {
radio->rxaudio = new audioHandler();
}
else if (radio->rxAudioSetup.type == portAudio) {
radio->rxaudio = new paHandler();
}
else if (radio->rxAudioSetup.type == rtAudio) {
radio->rxaudio = new rtHandler();
}
else
{
qCritical(logAudio()) << "Unsupported Receive Audio Handler selected!";
}
if (radio->rxaudio != Q_NULLPTR)
{
radio->rxAudioThread = new QThread(this);
radio->rxAudioThread->setObjectName("rxAudio()");
radio->rxaudio->moveToThread(radio->rxAudioThread);
2021-03-22 09:10:03 +00:00
radio->rxAudioThread->start(QThread::TimeCriticalPriority);
2021-03-22 09:10:03 +00:00
connect(radio->rxAudioThread, SIGNAL(finished()), radio->rxaudio, SLOT(deleteLater()));
connect(radio->rxaudio, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket)));
2021-03-22 09:10:03 +00:00
2022-05-14 12:45:56 +00:00
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
QMetaObject::invokeMethod(radio->rxaudio, [=]() {
radio->rxaudio->init(radio->rxAudioSetup);
}, Qt::QueuedConnection);
2022-01-27 22:51:28 +00:00
#else
//#warning "QT 5.9 is not fully supported multiple rigs will NOT work!"
connect(this, SIGNAL(setupRxAudio(audioSetup)), radio->rxaudio, SLOT(init(audioSetup)));
setupRxAudio(radio->rxAudioSetup);
2022-01-27 22:51:28 +00:00
#endif
2022-01-27 19:11:16 +00:00
}
2021-03-22 09:10:03 +00:00
}
}
2021-06-01 16:49:48 +00:00
break;
}
default:
{
break;
}
}
2021-06-11 09:16:13 +00:00
// Connection "may" have been deleted so check before calling common function.
if (current != Q_NULLPTR) {
commonReceived(&controlClients, current, r);
}
}
}
void udpServer::civReceived()
{
while (udpCiv->hasPendingDatagrams()) {
QNetworkDatagram datagram = udpCiv->receiveDatagram();
QByteArray r = datagram.data();
2021-02-16 20:55:30 +00:00
CLIENT* current = Q_NULLPTR;
if (datagram.senderAddress().isNull() || datagram.senderPort() == 65535 || datagram.senderPort() == 0)
2021-02-18 09:14:41 +00:00
return;
QDateTime now = QDateTime::currentDateTime();
foreach(CLIENT * client, civClients)
{
if (client != Q_NULLPTR)
{
if (client->ipAddress == datagram.senderAddress() && client->port == datagram.senderPort())
{
current = client;
}
}
}
if (current == Q_NULLPTR)
{
current = new CLIENT();
2021-06-11 08:56:19 +00:00
foreach(CLIENT* client, controlClients)
{
if (client != Q_NULLPTR)
{
if (client->ipAddress == datagram.senderAddress() && client->isAuthenticated && client->civClient == Q_NULLPTR)
{
current->controlClient = client;
client->civClient = current;
2022-01-29 22:50:58 +00:00
memcpy(current->guid, client->guid, GUIDLEN);
2021-06-11 08:56:19 +00:00
}
}
}
2021-08-15 13:41:54 +00:00
if (current->controlClient == Q_NULLPTR || !current->controlClient->isAuthenticated)
{
// There is no current controlClient that matches this civClient
delete current;
return;
}
2021-05-14 08:55:02 +00:00
current->type = "CIV";
current->civId = 0;
current->connected = true;
current->timeConnected = QDateTime::currentDateTime();
current->ipAddress = datagram.senderAddress();
current->port = datagram.senderPort();
current->myId = civId;
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
current->socket = udpCiv;
current->pingSeq = (quint8)rand() << 8 | (quint8)rand();
2021-02-28 20:10:07 +00:00
current->pingTimer = new QTimer();
connect(current->pingTimer, &QTimer::timeout, this, std::bind(&udpServer::sendPing, this, &civClients, current, (quint16)0x00, false));
current->pingTimer->start(100);
2021-02-28 20:10:07 +00:00
current->idleTimer = new QTimer();
connect(current->idleTimer, &QTimer::timeout, this, std::bind(&udpServer::sendControl, this, current, 0x00, (quint16)0x00));
2021-05-14 08:55:02 +00:00
//current->idleTimer->start(100); // Start idleTimer after receiving iamready.
2021-02-28 20:10:07 +00:00
current->retransmitTimer = new QTimer();
connect(current->retransmitTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRetransmitRequest, this, current));
current->retransmitTimer->start(RETRANSMIT_PERIOD);
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): New connection created";
if (connMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
civClients.append(current);
connMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock connMutex()";
}
2021-05-14 08:55:02 +00:00
}
2021-06-11 08:56:19 +00:00
switch (r.length())
{
2021-05-14 08:55:02 +00:00
/* case (CONTROL_SIZE):
{
}
2021-05-14 08:55:02 +00:00
*/
2021-06-01 16:49:48 +00:00
case (PING_SIZE):
{
ping_packet_t in = (ping_packet_t)r.constData();
if (in->type == 0x07)
{
2021-06-01 16:49:48 +00:00
// It is a ping request/response
2021-06-01 16:49:48 +00:00
if (in->reply == 0x00)
{
current->rxPingTime = in->time;
sendPing(&civClients, current, in->seq, true);
}
else if (in->reply == 0x01) {
2022-01-05 14:45:34 +00:00
// A Reply to our ping!
if (in->seq == current->pingSeq) {
current->pingSeq++;
}
}
}
2021-06-01 16:49:48 +00:00
break;
}
default:
{
2021-02-28 20:10:07 +00:00
2021-06-01 16:49:48 +00:00
if (r.length() > 0x18) {
data_packet_t in = (data_packet_t)r.constData();
if (in->type != 0x01)
{
if (quint16(in->datalen + 0x15) == (quint16)in->len)
{
2021-06-01 16:49:48 +00:00
// Strip all '0xFE' command preambles first:
int lastFE = r.lastIndexOf((char)0xfe);
//qInfo(logUdpServer()) << "Got:" << r.mid(lastFE);
if (current->civId == 0 && r.length() > lastFE + 2 && (quint8)r[lastFE+2] != 0xE1 && (quint8)r[lastFE + 2] > (quint8)0xdf && (quint8)r[lastFE + 2] < (quint8)0xef) {
2021-06-01 16:49:48 +00:00
// This is (should be) the remotes CIV id.
current->civId = (quint8)r[lastFE + 2];
2022-04-28 09:46:47 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Detected remote CI-V:" << QString("0x%1").arg(current->civId,0,16);
2021-06-01 16:49:48 +00:00
}
else if (current->civId != 0 && r.length() > lastFE + 2 && (quint8)r[lastFE+2] != 0xE1 && (quint8)r[lastFE + 2] != current->civId)
2021-02-28 20:10:07 +00:00
{
2021-06-01 16:49:48 +00:00
current->civId = (quint8)r[lastFE + 2];
2022-04-28 09:46:47 +00:00
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Detected different remote CI-V:" << QString("0x%1").arg(current->civId,0,16);
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Detected different remote CI-V:" << QString("0x%1").arg(current->civId,0,16);
} else if (r.length() > lastFE+2 && (quint8)r[lastFE+2] != 0xE1) {
2022-04-28 09:46:47 +00:00
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Detected invalid remote CI-V:" << QString("0x%1").arg((quint8)r[lastFE+2],0,16);
2022-01-26 09:49:52 +00:00
}
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* radio : config->rigs) {
if (!memcmp(radio->guid, current->guid, sizeof(radio->guid)) || config->rigs.size()==1)
2022-01-26 09:49:52 +00:00
{
// Only send to the rig that it belongs to!
2022-04-20 12:35:23 +00:00
//qDebug(logUdpServer()) << "Sending data" << r.mid(0x15);
2022-01-27 22:51:28 +00:00
#if (QT_VERSION >= QT_VERSION_CHECK(5,10,0))
2022-01-27 19:11:16 +00:00
QMetaObject::invokeMethod(radio->rig, [=]() {
radio->rig->dataFromServer(r.mid(0x15));;
2022-01-26 09:49:52 +00:00
}, Qt::DirectConnection);
2022-01-27 22:51:28 +00:00
#else
2022-01-30 10:29:23 +00:00
#warning "QT 5.9 is not fully supported, multiple rigs will NOT work!"
emit haveDataFromServer(r.mid(0x15));
2022-01-27 22:51:28 +00:00
#endif
2022-01-26 09:49:52 +00:00
}
}
2021-05-14 08:55:02 +00:00
2021-06-01 16:49:48 +00:00
}
else {
qInfo(logUdpServer()) << current->ipAddress.toString() << ": Datalen mismatch " << quint16(in->datalen + 0x15) << ":" << (quint16)in->len;
}
2021-02-18 09:14:41 +00:00
}
}
2021-06-01 16:49:48 +00:00
//break;
}
}
2021-05-14 08:55:02 +00:00
if (current != Q_NULLPTR) {
udpServer::commonReceived(&civClients, current, r);
}
2021-02-28 20:10:07 +00:00
}
}
void udpServer::audioReceived()
{
while (udpAudio->hasPendingDatagrams()) {
QNetworkDatagram datagram = udpAudio->receiveDatagram();
QByteArray r = datagram.data();
CLIENT* current = Q_NULLPTR;
if (datagram.senderAddress().isNull() || datagram.senderPort() == 65535 || datagram.senderPort() == 0)
2021-02-18 09:14:41 +00:00
return;
QDateTime now = QDateTime::currentDateTime();
foreach(CLIENT * client, audioClients)
{
if (client != Q_NULLPTR)
{
if (client->ipAddress == datagram.senderAddress() && client->port == datagram.senderPort())
{
current = client;
}
}
}
if (current == Q_NULLPTR)
{
current = new CLIENT();
2021-06-11 08:56:19 +00:00
foreach(CLIENT* client, controlClients)
{
if (client != Q_NULLPTR)
{
if (client->ipAddress == datagram.senderAddress() && client->isAuthenticated && client->audioClient == Q_NULLPTR)
{
current->controlClient = client;
client->audioClient = current;
2022-01-29 22:50:58 +00:00
memcpy(current->guid, client->guid, GUIDLEN);
2021-06-11 08:56:19 +00:00
}
}
}
2021-08-15 13:41:54 +00:00
if (current->controlClient == Q_NULLPTR || !current->controlClient->isAuthenticated)
{
// There is no current controlClient that matches this audioClient
delete current;
return;
}
2021-05-14 08:55:02 +00:00
current->type = "Audio";
current->connected = true;
current->timeConnected = QDateTime::currentDateTime();
current->ipAddress = datagram.senderAddress();
current->port = datagram.senderPort();
current->myId = audioId;
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
current->socket = udpAudio;
current->pingSeq = (quint8)rand() << 8 | (quint8)rand();
2021-06-01 16:49:48 +00:00
current->pingTimer = new QTimer();
connect(current->pingTimer, &QTimer::timeout, this, std::bind(&udpServer::sendPing, this, &audioClients, current, (quint16)0x00, false));
current->pingTimer->start(PING_PERIOD);
2021-02-28 20:10:07 +00:00
current->retransmitTimer = new QTimer();
connect(current->retransmitTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRetransmitRequest, this, current));
current->retransmitTimer->start(RETRANSMIT_PERIOD);
2021-03-22 09:10:03 +00:00
current->seqPrefix = 0;
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): New connection created";
if (connMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
audioClients.append(current);
connMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock connMutex()";
}
2021-05-14 08:55:02 +00:00
}
2021-05-14 08:55:02 +00:00
switch (r.length())
{
2021-06-01 16:49:48 +00:00
case (PING_SIZE):
{
ping_packet_t in = (ping_packet_t)r.constData();
if (in->type == 0x07)
{
2021-06-01 16:49:48 +00:00
// It is a ping request/response
2021-06-01 16:49:48 +00:00
if (in->reply == 0x00)
{
current->rxPingTime = in->time;
sendPing(&audioClients, current, in->seq, true);
}
else if (in->reply == 0x01) {
2022-01-05 14:45:34 +00:00
// A Reply to our ping!
if (in->seq == current->pingSeq) {
current->pingSeq++;
}
}
}
2021-06-01 16:49:48 +00:00
break;
}
default:
{
/* Audio packets start as follows:
PCM 16bit and PCM8/uLAW stereo: 0x44,0x02 for first packet and 0x6c,0x05 for second.
uLAW 8bit/PCM 8bit 0xd8,0x03 for all packets
PCM 16bit stereo 0x6c,0x05 first & second 0x70,0x04 third
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
*/
control_packet_t in = (control_packet_t)r.constData();
2021-03-22 09:10:03 +00:00
2021-08-14 19:08:11 +00:00
if (in->type != 0x01) {
// Opus packets can be smaller than this! && in->len >= 0xAC) {
2021-06-01 16:49:48 +00:00
if (in->seq == 0)
{
// Seq number has rolled over.
current->seqPrefix++;
}
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
if (hasTxAudio == current->ipAddress)
{
// 0xac is the smallest possible audio packet.
audioPacket tempAudio;
tempAudio.seq = (quint32)current->seqPrefix << 16 | in->seq;
tempAudio.time = QTime::currentTime();;
tempAudio.sent = 0;
tempAudio.data = r.mid(0x18);
//qInfo(logUdpServer()) << "sending tx audio " << in->seq;
2021-11-15 15:02:00 +00:00
emit haveAudioData(tempAudio);
//txaudio->incomingAudio(tempAudio);
2021-03-22 09:10:03 +00:00
}
}
2021-06-01 16:49:48 +00:00
break;
}
2021-03-22 09:10:03 +00:00
}
2021-03-22 15:16:41 +00:00
if (current != Q_NULLPTR) {
2021-05-14 08:55:02 +00:00
udpServer::commonReceived(&audioClients, current, r);
2021-03-22 15:16:41 +00:00
}
}
}
2021-06-01 16:49:48 +00:00
void udpServer::commonReceived(QList<CLIENT*>* l, CLIENT* current, QByteArray r)
2021-02-28 20:10:07 +00:00
{
Q_UNUSED(l); // We might need it later!
if (current == Q_NULLPTR || r.isNull()) {
return;
}
2021-02-28 20:10:07 +00:00
current->lastHeard = QDateTime::currentDateTime();
if (r.length() < 0x10)
{
// Invalid packet
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Invalid packet received, len: " << r.length();
2021-02-28 20:10:07 +00:00
return;
}
2021-02-28 20:10:07 +00:00
switch (r.length())
{
2021-06-01 16:49:48 +00:00
case (CONTROL_SIZE):
{
control_packet_t in = (control_packet_t)r.constData();
if (in->type == 0x03) {
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Received 'Are you there'";
2021-06-01 16:49:48 +00:00
current->remoteId = in->sentid;
sendControl(current, 0x04, in->seq);
} // This is This is "Are you ready" in response to "I am here".
else if (in->type == 0x06)
2021-02-28 20:10:07 +00:00
{
2021-06-01 16:49:48 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Received 'Are you ready'";
current->remoteId = in->sentid;
sendControl(current, 0x06, in->seq);
if (current->idleTimer != Q_NULLPTR && !current->idleTimer->isActive()) {
current->idleTimer->start(100);
2021-02-28 20:10:07 +00:00
}
} // This is a single packet retransmit request
else if (in->type == 0x01 && in->len == 0x10)
2021-02-28 20:10:07 +00:00
{
2022-05-04 23:06:50 +00:00
auto match = current->txSeqBuf.find(in->seq);
2021-06-01 16:49:48 +00:00
if (match != current->txSeqBuf.end() && match->retransmitCount < 5) {
// Found matching entry?
// Don't constantly retransmit the same packet, give-up eventually
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Sending (single packet) retransmit of " << QString("0x%1").arg(match->seqNum, 0, 16);
2021-06-01 16:49:48 +00:00
match->retransmitCount++;
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
current->socket->writeDatagram(match->data, current->ipAddress, current->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-06-01 16:49:48 +00:00
}
else {
// Just send an idle!
2022-05-05 07:57:50 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type <<
"): Requested (single) packet " << QString("0x%1").arg(in->seq, 0, 16) <<
"not found, have " << QString("0x%1").arg(current->txSeqBuf.firstKey(), 0, 16) <<
"to" << QString("0x%1").arg(current->txSeqBuf.lastKey(), 0, 16);
2021-06-01 16:49:48 +00:00
sendControl(current, 0x00, in->seq);
}
2021-02-28 20:10:07 +00:00
}
2021-06-01 16:49:48 +00:00
break;
}
default:
{
2022-01-26 09:49:52 +00:00
//break
2021-06-01 16:49:48 +00:00
}
2021-02-28 20:10:07 +00:00
}
// The packet is at least 0x10 in length so safe to cast it to control_packet for processing
control_packet_t in = (control_packet_t)r.constData();
if (in->type == 0x01 && in->len != 0x10)
{
for (quint16 i = 0x10; i < r.length(); i = i + 2)
{
quint16 seq = (quint8)r[i] | (quint8)r[i + 1] << 8;
2022-05-04 23:06:50 +00:00
auto match = current->txSeqBuf.find(seq);
2021-02-28 20:10:07 +00:00
if (match == current->txSeqBuf.end()) {
2022-05-05 07:57:50 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type <<
"): Requested (multiple) packet " << QString("0x%1").arg(seq,0,16) <<
"not found, have " << QString("0x%1").arg(current->txSeqBuf.firstKey(), 0, 16) <<
"to" << QString("0x%1").arg(current->txSeqBuf.lastKey(), 0, 16);
2021-02-28 20:10:07 +00:00
// Just send idle packet.
sendControl(current, 0, in->seq);
}
else if (match->seqNum != 0x00)
{
// Found matching entry?
// Send "untracked" as it has already been sent once.
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Sending (multiple packet) retransmit of " << QString("0x%1").arg(match->seqNum,0,16);
2021-02-28 20:10:07 +00:00
match->retransmitCount++;
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
current->socket->writeDatagram(match->data, current->ipAddress, current->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-02-28 20:10:07 +00:00
}
}
}
2021-05-14 08:55:02 +00:00
else if (in->type == 0x00 && in->seq != 0x00)
2021-02-28 20:10:07 +00:00
{
2021-05-14 08:55:02 +00:00
//if (current->type == "CIV") {
// qInfo(logUdpServer()) << "Got:" << in->seq;
2021-05-14 08:55:02 +00:00
//}
if (current->rxSeqBuf.isEmpty())
2021-02-28 20:10:07 +00:00
{
if (current->rxMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
current->rxSeqBuf.insert(in->seq, QTime::currentTime());
current->rxMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock rxMutex()";
}
2021-02-28 20:10:07 +00:00
}
else
{
if (in->seq < current->rxSeqBuf.firstKey() || in->seq - current->rxSeqBuf.lastKey() > MAX_MISSING)
2021-02-28 20:10:07 +00:00
{
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "Large seq number gap detected, previous highest: " <<
QString("0x%1").arg(current->rxSeqBuf.lastKey(), 0, 16) << " current: " << QString("0x%1").arg(in->seq, 0, 16);
2021-02-28 20:10:07 +00:00
// Looks like it has rolled over so clear buffer and start again.
if (current->rxMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
current->rxSeqBuf.clear();
current->rxMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock rxMutex()";
}
if (current->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
current->rxMissing.clear();
current->missMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock missMutex()";
}
2021-02-28 20:10:07 +00:00
return;
}
if (!current->rxSeqBuf.contains(in->seq))
{
if (current->rxMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-01-27 19:11:16 +00:00
// Add incoming packet to the received buffer and if it is in the missing buffer, remove it.
2022-01-29 22:50:58 +00:00
//int missCounter = 0;
2022-01-27 19:11:16 +00:00
if (in->seq > current->rxSeqBuf.lastKey() + 1) {
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "1 or more missing packets detected, previous: " <<
QString("0x%1").arg(current->rxSeqBuf.lastKey(), 0, 16) << " current: " << QString("0x%1").arg(in->seq, 0, 16);
2022-01-27 19:11:16 +00:00
// We are likely missing packets then!
if (current->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-04-08 17:42:37 +00:00
for (quint16 f = current->rxSeqBuf.lastKey() + 1; f <= in->seq; f++)
2022-01-27 19:11:16 +00:00
{
if (current->rxSeqBuf.size() > BUFSIZE)
{
current->rxSeqBuf.remove(current->rxSeqBuf.firstKey());
}
current->rxSeqBuf.insert(f, QTime::currentTime());
if (f != in->seq && !current->rxMissing.contains(f))
{
current->rxMissing.insert(f, 0);
2022-01-27 19:11:16 +00:00
}
}
current->missMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock missMutex()";
}
}
else {
if (current->rxSeqBuf.size() > BUFSIZE)
{
current->rxSeqBuf.remove(current->rxSeqBuf.firstKey());
}
current->rxSeqBuf.insert(in->seq, QTime::currentTime());
}
current->rxMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock rxMutex()";
}
} else{
2021-02-28 20:10:07 +00:00
// Check whether this is one of our missing ones!
if (current->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
2021-02-28 20:10:07 +00:00
{
2022-05-04 23:06:50 +00:00
auto s = current->rxMissing.find(in->seq);
if (s != current->rxMissing.end())
{
2022-04-28 09:46:47 +00:00
qInfo(logUdpServer()) << current->ipAddress.toString() << "(" << current->type << "): Missing SEQ has been received! " << QString("0x%1").arg(in->seq,0,16);
s = current->rxMissing.erase(s);
}
current->missMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock missMutex()";
2021-02-28 20:10:07 +00:00
}
}
}
}
2021-02-28 20:10:07 +00:00
}
void udpServer::sendControl(CLIENT* c, quint8 type, quint16 seq)
{
//qInfo(logUdpServer()) << c->ipAddress.toString() << ": Sending control packet: " << type;
2021-02-28 20:10:07 +00:00
control_packet p;
2021-02-28 20:10:07 +00:00
memset(p.packet, 0x0, CONTROL_SIZE); // We can't be sure it is initialized with 0x00!
p.len = sizeof(p);
p.type = type;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
2021-02-28 20:10:07 +00:00
if (seq == 0x00)
{
p.seq = c->txSeq;
SEQBUFENTRY s;
2022-05-05 10:16:59 +00:00
s.seqNum = c->txSeq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (c->txSeq == 0) {
c->txSeqBuf.clear();
}
else
if (c->txSeqBuf.size() > BUFSIZE)
2022-01-27 19:11:16 +00:00
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
}
2022-05-05 07:57:50 +00:00
c->txSeqBuf.insert(c->txSeq, s);
c->txSeq++;
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-06-02 09:43:52 +00:00
2021-02-28 20:10:07 +00:00
}
else {
p.seq = seq;
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-02-28 20:10:07 +00:00
}
return;
}
2021-06-01 16:49:48 +00:00
void udpServer::sendPing(QList<CLIENT*>* l, CLIENT* c, quint16 seq, bool reply)
{
2021-06-11 09:39:28 +00:00
Q_UNUSED(l);
/*
QDateTime now = QDateTime::currentDateTime();
if (c->lastHeard.secsTo(now) > STALE_CONNECTION)
{
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Deleting stale connection ";
deleteConnection(l, c);
return;
}
*/
//qInfo(logUdpServer()) << c->ipAddress.toString() << ": Sending Ping";
quint32 pingTime = 0;
if (reply) {
pingTime = c->rxPingTime;
}
else {
QTime now=QTime::currentTime();
pingTime = (quint32)now.msecsSinceStartOfDay();
2021-02-16 20:55:30 +00:00
seq = c->pingSeq;
2021-02-28 20:10:07 +00:00
// Don't increment pingseq until we receive a reply.
}
// First byte of pings "from" server can be either 0x00 or packet length!
ping_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
2021-02-28 20:10:07 +00:00
if (reply) {
p.len = sizeof(p);
}
p.type = 0x07;
p.seq = seq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
p.time = pingTime;
2021-02-28 20:10:07 +00:00
p.reply = (char)reply;
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-02-28 20:10:07 +00:00
return;
}
2021-02-28 20:10:07 +00:00
void udpServer::sendLoginResponse(CLIENT* c, bool allowed)
{
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Login response: " << c->txSeq;
login_response_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.len = sizeof(p);
p.type = 0x00;
2021-02-28 20:10:07 +00:00
p.seq = c->txSeq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
p.innerseq = c->authInnerSeq;
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
2022-04-20 12:35:23 +00:00
p.payloadsize = qToBigEndian((quint16)(sizeof(p) - 0x10));
p.requesttype = 0x00;
p.requestreply = 0x01;
if (!allowed) {
p.error = 0xFEFFFFFF;
2021-02-28 20:10:07 +00:00
if (c->idleTimer != Q_NULLPTR)
c->idleTimer->stop();
if (c->pingTimer != Q_NULLPTR)
c->pingTimer->stop();
if (c->retransmitTimer != Q_NULLPTR)
c->retransmitTimer->stop();
}
else {
2022-04-26 07:40:58 +00:00
strcpy(p.connection, "WFVIEW");
//strcpy(p.connection, "FTTH");
}
2021-02-28 20:10:07 +00:00
SEQBUFENTRY s;
s.seqNum = c->txSeq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (c->txSeq == 0) {
c->txSeqBuf.clear();
}
else if (c->txSeqBuf.size() > BUFSIZE)
2022-01-27 19:11:16 +00:00
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
}
c->txSeqBuf.insert(c->txSeq, s);
c->txSeq++;
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
2021-06-02 09:43:52 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-02-28 20:10:07 +00:00
if (c->idleTimer != Q_NULLPTR)
c->idleTimer->start(100);
return;
}
void udpServer::sendCapabilities(CLIENT* c)
{
capabilities_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.type = 0x00;
p.seq = c->txSeq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
2021-03-22 09:10:03 +00:00
p.innerseq = c->authInnerSeq;
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
2022-04-20 12:35:23 +00:00
p.requesttype = 0x02;
p.requestreply = 0x02;
p.numradios = qToBigEndian((quint16)config->rigs.size());
2022-01-26 09:49:52 +00:00
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
2021-02-28 20:10:07 +00:00
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* rig : config->rigs) {
2022-01-27 19:11:16 +00:00
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Capabilities :" << c->txSeq << "for" << rig->modelName;
2022-01-26 09:49:52 +00:00
radio_cap_packet r;
memset(r.packet, 0x0, sizeof(r)); // We can't be sure it is initialized with 0x00!
2022-04-20 12:35:23 +00:00
2022-01-29 22:50:58 +00:00
memcpy(r.guid, rig->guid, GUIDLEN);
2022-04-20 12:35:23 +00:00
2022-01-27 19:11:16 +00:00
memcpy(r.name, rig->rigName.toLocal8Bit(), sizeof(r.name));
2022-01-26 09:49:52 +00:00
memcpy(r.audio, QByteArrayLiteral("ICOM_VAUDIO").constData(), 11);
2022-01-27 19:11:16 +00:00
if (rig->hasWiFi && !rig->hasEthernet) {
r.conntype = 0x0707; // 0x0707 for wifi rig->
2022-01-26 09:49:52 +00:00
}
else {
2022-01-27 19:11:16 +00:00
r.conntype = 0x073f; // 0x073f for ethernet rig->
2021-03-22 09:10:03 +00:00
}
2022-01-26 09:49:52 +00:00
2022-01-27 19:11:16 +00:00
r.civ = rig->civAddr;
r.baudrate = (quint32)qToBigEndian(rig->baudRate);
2022-01-26 09:49:52 +00:00
/*
0x80 = 12K only
0x40 = 44.1K only
0x20 = 22.05K only
0x10 = 11.025K only
0x08 = 48K only
0x04 = 32K only
0x02 = 16K only
0x01 = 8K only
*/
2022-01-27 19:11:16 +00:00
if (rig->rxaudio == Q_NULLPTR) {
2022-01-26 09:49:52 +00:00
r.rxsample = 0x8b01; // all rx sample frequencies supported
2021-03-22 09:10:03 +00:00
}
2022-01-26 09:49:52 +00:00
else {
if (rxSampleRate == 48000) {
r.rxsample = 0x0800; // fixed rx sample frequency
}
else if (rxSampleRate == 32000) {
r.rxsample = 0x0400;
}
else if (rxSampleRate == 24000) {
r.rxsample = 0x0001;
}
else if (rxSampleRate == 16000) {
r.rxsample = 0x0200;
}
else if (rxSampleRate == 12000) {
r.rxsample = 0x8000;
}
2021-03-22 09:10:03 +00:00
}
2022-01-26 09:49:52 +00:00
2022-01-27 19:11:16 +00:00
if (rig->txaudio == Q_NULLPTR) {
2022-01-26 09:49:52 +00:00
r.txsample = 0x8b01; // all tx sample frequencies supported
r.enablea = 0x01; // 0x01 enables TX 24K mode?
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Client will have TX audio";
2021-03-22 09:10:03 +00:00
}
2022-01-26 09:49:52 +00:00
else {
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Disable tx audio for client";
r.txsample = 0;
2021-03-22 09:10:03 +00:00
}
2022-01-26 09:49:52 +00:00
// I still don't know what these are?
r.enableb = 0x01; // 0x01 doesn't seem to do anything?
r.enablec = 0x01; // 0x01 doesn't seem to do anything?
r.capf = 0x5001;
r.capg = 0x0190;
s.data.append(QByteArray::fromRawData((const char*)r.packet, sizeof(r)));
2021-03-22 09:10:03 +00:00
}
2021-02-28 20:10:07 +00:00
p.len = (quint32)sizeof(p)+s.data.length();
2022-04-20 12:35:23 +00:00
p.payloadsize = qToBigEndian((quint16)(sizeof(p) + s.data.length() - 0x10));
2022-01-26 09:49:52 +00:00
s.data.insert(0,QByteArray::fromRawData((const char*)p.packet, sizeof(p)));
2021-05-14 08:55:02 +00:00
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (c->txSeq == 0) {
c->txSeqBuf.clear();
}
else if (c->txSeqBuf.size() > BUFSIZE)
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
}
2022-05-05 07:57:50 +00:00
c->txSeqBuf.insert(c->txSeq, s);
c->txSeq++;
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram((const char*)s.data, s.data.length(), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-06-02 09:43:52 +00:00
2021-02-28 20:10:07 +00:00
if (c->idleTimer != Q_NULLPTR)
c->idleTimer->start(100);
return;
}
// When client has requested civ/audio connection, this will contain their details
// Also used to display currently connected used information.
2022-01-29 22:50:58 +00:00
void udpServer::sendConnectionInfo(CLIENT* c, quint8 guid[GUIDLEN])
{
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* radio : config->rigs) {
if (!memcmp(guid, radio->guid, GUIDLEN) || config->rigs.size()==1)
2022-01-26 09:49:52 +00:00
{
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending ConnectionInfo :" << c->txSeq;
conninfo_packet p;
memset(p.packet, 0x0, sizeof(p));
p.len = sizeof(p);
p.type = 0x00;
p.seq = c->txSeq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
//p.innerseq = c->authInnerSeq; // Innerseq not used in user packet
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
2022-04-20 12:35:23 +00:00
p.payloadsize = qToBigEndian((quint16)(sizeof(p) - 0x10));
p.requesttype = 0x00;
p.requestreply = 0x03;
2022-01-29 22:50:58 +00:00
memcpy(p.guid, radio->guid, GUIDLEN);
2022-01-27 19:11:16 +00:00
memcpy(p.name, radio->rigName.toLocal8Bit(), sizeof(p.name));
2022-01-26 09:49:52 +00:00
2022-01-27 19:11:16 +00:00
if (radio->rigAvailable) {
2022-01-26 09:49:52 +00:00
if (c->isStreaming) {
p.busy = 0x01;
}
else {
p.busy = 0x00;
}
}
else
{
p.busy = 0x02;
}
// This is the current streaming client (should we support multiple clients?)
if (c->isStreaming) {
memcpy(p.computer, c->clientName.constData(), c->clientName.length());
p.ipaddress = qToBigEndian(c->ipAddress.toIPv4Address());
}
2022-01-26 09:49:52 +00:00
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
2021-02-28 20:10:07 +00:00
2022-01-26 09:49:52 +00:00
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (c->txSeq == 0) {
c->txSeqBuf.clear();
}
else if (c->txSeqBuf.size() > BUFSIZE)
2022-01-26 09:49:52 +00:00
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
}
2022-05-05 07:57:50 +00:00
c->txSeqBuf.insert(c->txSeq, s);
2022-01-26 09:49:52 +00:00
c->txSeq++;
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
2021-02-28 20:10:07 +00:00
2022-01-26 09:49:52 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2022-01-26 09:49:52 +00:00
}
}
2021-02-28 20:10:07 +00:00
if (c->idleTimer != Q_NULLPTR)
c->idleTimer->start(100);
return;
}
void udpServer::sendTokenResponse(CLIENT* c, quint8 type)
{
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Token response for type: " << type;
token_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.len = sizeof(p);
p.type = 0x00;
p.seq = c->txSeq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
p.innerseq = c->authInnerSeq;
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
2022-04-20 12:35:23 +00:00
p.payloadsize = qToBigEndian((quint16)(sizeof(p) - 0x10));
2022-04-20 12:35:23 +00:00
memcpy(p.guid, c->guid, GUIDLEN);
p.requesttype = type;
p.requestreply = 0x02;
2021-02-28 20:10:07 +00:00
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
2021-06-02 09:43:52 +00:00
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (c->txSeq == 0) {
c->txSeqBuf.clear();
}
else if (c->txSeqBuf.size() > BUFSIZE)
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
}
2022-05-05 07:57:50 +00:00
c->txSeqBuf.insert(c->txSeq, s);
c->txSeq++;
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
2021-06-02 09:43:52 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-02-28 20:10:07 +00:00
2021-02-28 20:10:07 +00:00
if (c->idleTimer != Q_NULLPTR)
c->idleTimer->start(100);
return;
}
void udpServer::watchdog()
2021-02-28 20:10:07 +00:00
{
QDateTime now = QDateTime::currentDateTime();
foreach(CLIENT * client, audioClients)
{
if (client != Q_NULLPTR)
{
if (client->lastHeard.secsTo(now) > STALE_CONNECTION)
{
qInfo(logUdpServer()) << client->ipAddress.toString() << "(" << client->type << "): Deleting stale connection ";
deleteConnection(&audioClients, client);
}
}
else {
qInfo(logUdpServer()) << "Current client is NULL!";
}
}
foreach(CLIENT* client, civClients)
{
if (client != Q_NULLPTR)
{
if (client->lastHeard.secsTo(now) > STALE_CONNECTION)
{
qInfo(logUdpServer()) << client->ipAddress.toString() << "(" << client->type << "): Deleting stale connection ";
deleteConnection(&civClients, client);
}
}
else {
qInfo(logUdpServer()) << "Current client is NULL!";
}
}
foreach(CLIENT* client, controlClients)
{
if (client != Q_NULLPTR)
{
if (client->lastHeard.secsTo(now) > STALE_CONNECTION)
{
qInfo(logUdpServer()) << client->ipAddress.toString() << "(" << client->type << "): Deleting stale connection ";
deleteConnection(&controlClients, client);
}
}
else {
qInfo(logUdpServer()) << "Current client is NULL!";
}
}
if (!config->lan) {
status.message = QString("<pre>Server connections: Control:%1 CI-V:%2 Audio:%3</pre>").arg(controlClients.size()).arg(civClients.size()).arg(audioClients.size());
emit haveNetworkStatus(status);
}
}
void udpServer::sendStatus(CLIENT* c)
{
qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Status";
status_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.len = sizeof(p);
p.type = 0x00;
p.seq = c->txSeq;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
p.innerseq = c->authInnerSeq;
p.tokrequest = c->tokenRx;
p.token = c->tokenTx;
2022-04-20 12:35:23 +00:00
p.payloadsize = qToBigEndian((quint16)(sizeof(p) - 0x10));
p.requestreply = 0x02;
p.requesttype = 0x03;
memcpy(p.guid, c->guid, GUIDLEN); // May be MAC address OR guid.
2021-06-01 16:49:48 +00:00
p.civport = qToBigEndian(c->civPort);
p.audioport = qToBigEndian(c->audioPort);
// Send this to reject the request to tx/rx audio/civ
//memcpy(p + 0x30, QByteArrayLiteral("\xff\xff\xff\xfe").constData(), 4);
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (c->txSeq == 0) {
c->txSeqBuf.clear();
}
else if (c->txSeqBuf.size() > BUFSIZE)
{
c->txSeqBuf.remove(c->txSeqBuf.firstKey());
}
c->txSeq++;
2022-05-05 07:57:50 +00:00
c->txSeqBuf.insert(c->txSeq, s);
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
2021-06-02 09:43:52 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
}
2021-02-18 09:14:41 +00:00
void udpServer::dataForServer(QByteArray d)
{
2022-01-26 09:49:52 +00:00
rigCommander* sender = qobject_cast<rigCommander*>(QObject::sender());
if (sender == Q_NULLPTR)
2021-02-18 09:14:41 +00:00
{
2022-01-26 09:49:52 +00:00
return;
}
2022-01-26 09:49:52 +00:00
for (CLIENT* client : civClients)
{
if (client == Q_NULLPTR || !client->connected)
{
continue;
}
2022-01-27 19:11:16 +00:00
// Use the GUID to determine which radio the response is from
2022-04-20 12:35:23 +00:00
if (memcmp(sender->getGUID(), client->guid, GUIDLEN) && config->rigs.size()>1)
2022-01-26 09:49:52 +00:00
{
2022-01-27 19:11:16 +00:00
continue; // Rig guid doesn't match the one requested by the client.
}
int lastFE = d.lastIndexOf((quint8)0xfe);
//qInfo(logUdpServer()) << "Server got CIV data from" << config->rigs.first()->rigName << "length" << d.length() << d.toHex();
2022-01-27 19:11:16 +00:00
if (client->connected && d.length() > lastFE + 2 &&
((quint8)d[lastFE + 1] == client->civId || (quint8)d[lastFE + 2] == client->civId ||
(quint8)d[lastFE + 1] == 0x00 || (quint8)d[lastFE + 2] == 0x00 || (quint8)d[lastFE + 1] == 0xE1 || (quint8)d[lastFE + 2] == 0xE1))
{
data_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.len = (quint16)d.length() + sizeof(p);
p.seq = client->txSeq;
p.sentid = client->myId;
p.rcvdid = client->remoteId;
p.reply = (char)0xc1;
p.datalen = (quint16)d.length();
p.sendseq = client->innerSeq;
QByteArray t = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
t.append(d);
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = t;
2021-06-02 09:43:52 +00:00
2022-01-27 19:11:16 +00:00
if (client->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (client->txSeq == 0) {
client->txSeqBuf.clear();
}
else if (client->txSeqBuf.size() > BUFSIZE)
{
2022-01-27 19:11:16 +00:00
client->txSeqBuf.remove(client->txSeqBuf.firstKey());
}
2022-05-05 07:57:50 +00:00
client->txSeqBuf.insert(client->txSeq, s);
2022-01-27 19:11:16 +00:00
client->txSeq++;
2022-04-20 12:35:23 +00:00
//client->innerSeq = (qToBigEndian(qFromBigEndian(client->innerSeq) + 1));
2022-01-27 19:11:16 +00:00
client->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
2022-01-27 19:11:16 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
client->socket->writeDatagram(t, client->ipAddress, client->port);
udpMutex.unlock();
}
else {
2022-01-27 19:11:16 +00:00
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2022-01-26 09:49:52 +00:00
}
2022-01-27 19:11:16 +00:00
else {
2022-04-28 09:46:47 +00:00
qInfo(logUdpServer()) << "Got data for different ID" <<
QString("0x%1").arg((quint8)d[lastFE + 1],0,16) << ":" << QString("0x%1").arg((quint8)d[lastFE + 2],0,16);
2022-01-27 19:11:16 +00:00
}
2021-02-28 20:10:07 +00:00
}
return;
}
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
void udpServer::receiveAudioData(const audioPacket& d)
2021-02-28 20:10:07 +00:00
{
2022-01-29 22:50:58 +00:00
rigCommander* sender = qobject_cast<rigCommander*>(QObject::sender());
quint8 guid[GUIDLEN];
if (sender != Q_NULLPTR)
{
memcpy(guid, sender->getGUID(), GUIDLEN);
}
else {
memcpy(guid, d.guid, GUIDLEN);
}
2022-04-20 12:35:23 +00:00
//qInfo(logUdpServer()) << "Server got:" << d.data.length();
2021-02-28 20:10:07 +00:00
foreach(CLIENT * client, audioClients)
{
2022-04-10 22:13:51 +00:00
int len = 0;
while (len < d.data.length()) {
QByteArray partial;
partial = d.data.mid(len, 1364);
len = len + partial.length();
2022-04-20 12:35:23 +00:00
if (client != Q_NULLPTR && client->connected && (!memcmp(client->guid, guid, GUIDLEN) || config->rigs.size()== 1)) {
2022-04-10 22:13:51 +00:00
audio_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.len = (quint32)sizeof(p) + partial.length();
2022-04-10 22:13:51 +00:00
p.sentid = client->myId;
p.rcvdid = client->remoteId;
p.ident = 0x0080; // audio is always this?
p.datalen = (quint16)qToBigEndian((quint16)partial.length());
p.sendseq = (quint16)qToBigEndian((quint16)client->sendAudioSeq); // THIS IS BIG ENDIAN!
p.seq = client->txSeq;
QByteArray t = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
2022-04-11 10:26:52 +00:00
t.append(partial);
2022-04-10 22:13:51 +00:00
SEQBUFENTRY s;
s.seqNum = p.seq;
s.timeSent = QTime::currentTime();
s.retransmitCount = 0;
s.data = t;
if (client->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
2022-05-05 07:57:50 +00:00
if (client->txSeq == 0) {
client->txSeqBuf.clear();
}
else if (client->txSeqBuf.size() > BUFSIZE)
2022-04-10 22:13:51 +00:00
{
client->txSeqBuf.remove(client->txSeqBuf.firstKey());
}
2022-05-05 07:57:50 +00:00
client->txSeqBuf.insert(client->txSeq, s);
2022-04-10 22:13:51 +00:00
client->txSeq++;
client->sendAudioSeq++;
client->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
2022-04-10 22:13:51 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
client->socket->writeDatagram(t, client->ipAddress, client->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-06-02 09:43:52 +00:00
2022-04-10 22:13:51 +00:00
}
}
2021-02-18 09:14:41 +00:00
}
2021-02-28 20:10:07 +00:00
2021-02-18 09:14:41 +00:00
return;
}
/// <summary>
/// Find all gaps in received packets and then send requests for them.
/// This will run every 100ms so out-of-sequence packets will not trigger a retransmit request.
/// </summary>
/// <param name="c"></param>
2021-06-01 16:49:48 +00:00
void udpServer::sendRetransmitRequest(CLIENT* c)
2021-02-28 20:10:07 +00:00
{
// Find all gaps in received packets and then send requests for them.
// This will run every 100ms so out-of-sequence packets will not trigger a retransmit request.
2021-02-28 20:10:07 +00:00
2022-01-27 23:12:07 +00:00
if (c->rxMissing.isEmpty()) {
return;
}
else if (c->rxMissing.size() > MAX_MISSING) {
qInfo(logUdp()) << "Too many missing packets," << c->rxMissing.size() << "flushing all buffers";
2022-01-27 23:24:54 +00:00
c->rxMutex.lock();
c->rxSeqBuf.clear();
2022-01-27 23:28:34 +00:00
c->rxMutex.unlock();
c->missMutex.lock();
2022-01-27 23:24:54 +00:00
c->rxMissing.clear();
c->missMutex.unlock();
return;
}
2022-01-27 23:12:07 +00:00
2021-02-28 20:10:07 +00:00
QByteArray missingSeqs;
2022-01-27 23:12:07 +00:00
2022-01-30 10:29:23 +00:00
//QTime missingTime = QTime::currentTime();
if (c->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
2021-02-28 20:10:07 +00:00
{
2022-05-05 01:01:20 +00:00
auto it = c->rxMissing.begin();
while (it != c->rxMissing.end())
2021-02-28 20:10:07 +00:00
{
2022-05-05 00:49:21 +00:00
if (it.key() != 0x00)
{
2022-04-20 12:35:23 +00:00
if (it.value() < 4)
{
missingSeqs.append(it.key() & 0xff);
missingSeqs.append(it.key() >> 8 & 0xff);
missingSeqs.append(it.key() & 0xff);
missingSeqs.append(it.key() >> 8 & 0xff);
it.value()++;
2022-05-05 00:49:21 +00:00
it++;
2022-04-20 12:35:23 +00:00
}
2022-01-27 19:11:16 +00:00
2022-04-20 12:35:23 +00:00
else {
// We have tried 4 times to request this packet, time to give up!
2022-05-05 08:01:04 +00:00
qInfo(logUdp()) << this->metaObject()->className() << ": No response for missing packet" << QString("0x%1").arg(it.key(), 0, 16) << "deleting";
2022-04-20 12:35:23 +00:00
it = c->rxMissing.erase(it);
}
2022-05-05 00:49:21 +00:00
} else {
qInfo(logUdp()) << this->metaObject()->className() << ": found empty key in missing buffer";
it++;
}
2021-02-28 20:10:07 +00:00
}
if (missingSeqs.length() != 0)
2021-02-28 20:10:07 +00:00
{
control_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.type = 0x01;
p.seq = 0x0000;
p.sentid = c->myId;
p.rcvdid = c->remoteId;
if (missingSeqs.length() == 4) // This is just a single missing packet so send using a control.
{
p.len = sizeof(p);
p.seq = (missingSeqs[0] & 0xff) | (quint16)(missingSeqs[1] << 8);
2022-04-28 09:46:47 +00:00
qInfo(logUdp()) << this->metaObject()->className() << ": sending request for missing packet : " << QString("0x%1").arg(p.seq,0,16);
2021-06-02 09:43:52 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
2021-06-02 09:43:52 +00:00
}
else
{
qInfo(logUdp()) << this->metaObject()->className() << ": sending request for multiple missing packets : " << missingSeqs.toHex();
p.len = (quint32)sizeof(p) + missingSeqs.size();
missingSeqs.insert(0, p.packet, sizeof(p));
2022-01-07 14:42:32 +00:00
if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->socket->writeDatagram(missingSeqs, c->ipAddress, c->port);
udpMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock udpMutex()";
}
}
2021-02-28 20:10:07 +00:00
}
c->missMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock missMutex()";
2021-02-28 20:10:07 +00:00
}
}
/// <summary>
/// This function is passed a pointer to the list of connection objects and a pointer to the object itself
/// Needs to stop and delete all timers, remove the connection from the list and delete the connection.
/// </summary>
/// <param name="l"></param>
/// <param name="c"></param>
2021-06-01 16:49:48 +00:00
void udpServer::deleteConnection(QList<CLIENT*>* l, CLIENT* c)
{
2021-05-14 08:55:02 +00:00
2022-01-29 22:50:58 +00:00
quint8 guid[GUIDLEN];
memcpy(guid, c->guid, GUIDLEN);
2022-01-26 09:49:52 +00:00
int len = l->length();
2021-06-11 09:08:04 +00:00
qInfo(logUdpServer()) << "Deleting" << c->type << "connection to: " << c->ipAddress.toString() << ":" << QString::number(c->port);
if (c->idleTimer != Q_NULLPTR) {
c->idleTimer->stop();
delete c->idleTimer;
}
if (c->pingTimer != Q_NULLPTR) {
c->pingTimer->stop();
delete c->pingTimer;
}
2021-02-28 20:10:07 +00:00
if (c->retransmitTimer != Q_NULLPTR) {
c->retransmitTimer->stop();
delete c->retransmitTimer;
}
if (c->rxMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->rxSeqBuf.clear();
c->rxMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock rxMutex()";
}
if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->txSeqBuf.clear();
c->txMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock txMutex()";
}
if (c->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
c->rxMissing.clear();
c->missMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock missMutex()";
}
if (connMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD)))
{
QList<CLIENT*>::iterator it = l->begin();
while (it != l->end()) {
CLIENT* client = *it;
if (client != Q_NULLPTR && client == c) {
qInfo(logUdpServer()) << "Found" << client->type << "connection to: " << client->ipAddress.toString() << ":" << QString::number(client->port);
it = l->erase(it);
2022-01-26 09:49:52 +00:00
len--;
}
else {
++it;
}
}
delete c; // Is this needed or will the erase have done it?
c = Q_NULLPTR;
qInfo(logUdpServer()) << "Current Number of clients connected: " << l->length();
connMutex.unlock();
}
else {
qInfo(logUdpServer()) << "Unable to lock connMutex()";
}
2021-03-22 09:10:03 +00:00
2022-01-26 09:49:52 +00:00
if (len == 0) {
2022-04-20 12:35:23 +00:00
for (RIGCONFIG* radio : config->rigs) {
if (!memcmp(radio->guid, guid, GUIDLEN) || config->rigs.size() == 1)
2022-01-26 09:49:52 +00:00
{
2021-03-22 09:10:03 +00:00
2022-01-27 19:11:16 +00:00
if (radio->rxAudioThread != Q_NULLPTR) {
radio->rxAudioThread->quit();
radio->rxAudioThread->wait();
radio->rxaudio = Q_NULLPTR;
radio->rxAudioThread = Q_NULLPTR;
2022-01-26 09:49:52 +00:00
}
2021-03-22 09:10:03 +00:00
2022-01-27 19:11:16 +00:00
if (radio->txAudioThread != Q_NULLPTR) {
radio->txAudioThread->quit();
radio->txAudioThread->wait();
radio->txaudio = Q_NULLPTR;
radio->txAudioThread = Q_NULLPTR;
2022-01-26 09:49:52 +00:00
}
}
2021-03-22 09:10:03 +00:00
}
}
}