server now accepting civ/audio connection.

merge-requests/2/head
Phil Taylor 2021-02-17 23:10:26 +00:00
rodzic 6b99d122a2
commit e3b3d2a3f4
3 zmienionych plików z 545 dodań i 224 usunięć

Wyświetl plik

@ -298,18 +298,25 @@ void udpHandler::sendRequestSerialAndAudio()
0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
static_cast<quint8>(myId & 0xff), static_cast<quint8>(myId >> 8 & 0xff), static_cast<quint8>(myId >> 16 & 0xff), static_cast<quint8>(myId >> 24 & 0xff),
static_cast<quint8>(remoteId & 0xff), static_cast<quint8>(remoteId >> 8 & 0xff), static_cast<quint8>(remoteId >> 16 & 0xff), static_cast<quint8>(remoteId >> 24 & 0xff),
0x00, 0x00, 0x00, 0x80, 0x01, 0x03, 0x00, static_cast<quint8>(authInnerSendSeq & 0xff), static_cast<quint8>(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<quint8>(rxSampleRate >> 8 & 0xff), static_cast<quint8>(rxSampleRate & 0xff),
0x00, 0x00, static_cast<quint8>(txSampleRate >> 8 & 0xff), static_cast<quint8>(txSampleRate & 0xff),
0x00, 0x00, static_cast<quint8>(civPort >> 8 & 0xff), static_cast<quint8>(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);

Wyświetl plik

@ -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<quint32>(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<quint16>(r.mid(0x06, 2));
switch (r.length())
{
case (0x10):
if (r.mid(0, 8) == QByteArrayLiteral("\x10\x00\x00\x00\x03\x00\x00\x00")) {
qDebug() << current->ipAddress.toString() << ": Received 'are you there'";
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
sendIAmHere(current);
} // This is This is "Are you ready" in response to "I am here".
else if (r.mid(0, 8) == QByteArrayLiteral("\x10\x00\x00\x00\x06\x00\x01\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'Are you ready'";
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
sendIAmReady(current);
} // This is a retransmit request
else if (r.mid(0, 6) == QByteArrayLiteral("\x10\x00\x00\x00\x01\x00"))
{
// Just send an idle for now!
qDebug() << current->ipAddress.toString() << ": Received 'retransmit' request for " << gotSeq;
sendIdle(current, gotSeq);
} // This is a disconnect request
else if (r.mid(0, 6) == QByteArrayLiteral("\x10\x00\x00\x00\x05\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'disconnect' request";
sendIdle(current, gotSeq);
current->idleTimer->stop();
current->pingTimer->stop();
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<quint32>(r.mid(0x11, 4));
sendPing(current, gotSeq, true);
}
else if (r[16] == (char)0x01) {
// A Reply to our ping!
if (gotSeq == current->pingSeq) {
current->pingSeq++;
}
else {
qDebug() << current->ipAddress.toString() << ": Server got out of sequence ping reply. Got: " << gotSeq << " expecting: " << current->pingSeq;
}
}
}
break;
case (0x40):
// Token request
current->authInnerSeq = qFromLittleEndian<quint32>(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<quint32>(r.mid(0x16, 4));
current->tokenRx = qFromLittleEndian<quint16>(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<quint16>(r.mid(0x76, 2));
current->txSampleRate = qFromBigEndian<quint16>(r.mid(0x7a, 2));
//current->civPort = qFromBigEndian<quint16>(r.mid(0x7e, 2)); // Ignore port sent from client and tell it which to use
//current->audioPort = qFromBigEndian<quint16>(r.mid(0x82, 2));
current->txBufferLen = qFromBigEndian<quint16>(r.mid(0x86, 2));
current->authInnerSeq = qFromLittleEndian<quint32>(r.mid(0x16, 4));
current->connSeq = qFromLittleEndian<quint32>(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<quint32>(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<quint16>(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<quint16>(r.mid(0x06, 2));
if (r[0x15] == (char)0x02) {
// Request for new token
//current->tokenTx = (quint16)rand();
sendIdle(current, gotSeq);
current->authSeq++;
sendCapabilities(current);
current->authSeq++;
sendConnectionInfo(current);
}
else if(r[0x15] == (char)0x01) {
// De-auth request
sendIdle(current, gotSeq);
current->authSeq++;
}
else if (r.mid(0x13,3) == QByteArrayLiteral("\x30\01\x05")) {
qDebug() << current->ipAddress.toString() << ": Received 'token renewal' request";
sendTokenRenewal(current);
}
break;
case (0x80):
if (r.mid(0, 8) == QByteArrayLiteral("\x80\x00\x00\x00\x00\x00\x01\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'login'";
bool userOk = false;
foreach(SERVERUSER user, config.users)
{
QByteArray usercomp;
passcode(user.username, usercomp);
QByteArray passcomp;
passcode(user.password, passcomp);
if (r.mid(0x40, usercomp.length()) == usercomp && r.mid(0x50, passcomp.length()) == passcomp)
{
userOk = true;
break;
}
}
// Generate login response
current->clientName = parseNullTerminatedString(r, 0x60);
current->authInnerSeq = qFromLittleEndian<quint16>(r.mid(0x17, 2));
current->authSeq = qFromLittleEndian<quint16>(r.mid(0x06, 2));
current->tokenRx = qFromLittleEndian<quint16>(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<quint32>(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<quint16>(r.mid(0x06, 2));
switch (r.length())
{
case (0x10):
if (r.mid(0, 8) == QByteArrayLiteral("\x10\x00\x00\x00\x03\x00\x00\x00")) {
qDebug() << current->ipAddress.toString() << ": Received 'are you there'";
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
sendIAmHere(current);
} // This is This is "Are you ready" in response to "I am here".
else if (r.mid(0, 8) == QByteArrayLiteral("\x10\x00\x00\x00\x06\x00\x01\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'Are you ready'";
current->remoteId = qFromLittleEndian<quint32>(r.mid(8, 4));
sendIAmReady(current);
} // This is a retransmit request
else if (r.mid(0, 6) == QByteArrayLiteral("\x10\x00\x00\x00\x01\x00"))
{
// Just send an idle for now!
qDebug() << current->ipAddress.toString() << ": Received 'retransmit' request for " << gotSeq;
sendIdle(current, gotSeq);
} // This is a disconnect request
else if (r.mid(0, 6) == QByteArrayLiteral("\x10\x00\x00\x00\x05\x00"))
{
qDebug() << current->ipAddress.toString() << ": Received 'disconnect' request";
sendIdle(current, gotSeq);
current->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<quint32>(r.mid(0x11, 4));
sendPing(current, gotSeq, true);
}
else if (r[16] == (char)0x01) {
// A Reply to our ping!
if (gotSeq == current->pingSeq) {
current->pingSeq++;
}
else {
qDebug() << current->ipAddress.toString() << ": 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<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff)
};
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<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >>16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff)
};
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<quint8>(seq & 0xff),static_cast<quint8>(seq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >>8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
static_cast<quint8>(reply), static_cast<quint8>(pingSeq & 0xff), static_cast<quint8>(pingSeq >> 8 & 0xff), static_cast<quint8>(pingSeq >> 16 & 0xff), static_cast<quint8>(pingSeq >>24 & 0xff)
};
// 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<quint8>(seq & 0xff),static_cast<quint8>(seq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId >> 24 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
};
c->socket->writeDatagram(QByteArray::fromRawData((const char*)p, sizeof(p)), c->ipAddress, c->port);
return;
}
void udpServer::sendLoginResponse(CLIENT* c,bool allowed)
#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<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >> 8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >> 16 & 0xff), static_cast<quint8>(c->myId >> 24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >> 24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00,
static_cast<quint8>(c->authInnerSeq & 0xff), static_cast<quint8>(c->authInnerSeq >> 8 & 0xff), 0x00,
static_cast<quint8>(c->tokenRx >> 0 & 0xff), static_cast<quint8>(c->tokenRx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx >> 16 & 0xff), static_cast<quint8>(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<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >> 16 & 0xff), static_cast<quint8>(c->myId >>24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x98, 0x02, 0x02, 0x00,
static_cast<quint8>(c->authInnerSeq & 0xff), static_cast<quint8>(c->authInnerSeq >> 8 & 0xff), 0x00,
static_cast<quint8>(c->tokenRx >> 0 & 0xff), static_cast<quint8>(c->tokenRx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx >> 16 & 0xff), static_cast<quint8>(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<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >>8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >>16 & 0xff), static_cast<quint8>(c->myId >> 24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >>24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
static_cast<quint8>(c->authInnerSeq & 0xff), static_cast<quint8>(c->authInnerSeq >> 8 & 0xff), 0x00,
static_cast<quint8>(c->tokenRx >> 0 & 0xff), static_cast<quint8>(c->tokenRx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx >> 16 & 0xff), static_cast<quint8>(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<quint8>(c->txSeq & 0xff), static_cast<quint8>(c->txSeq >> 8 & 0xff),
static_cast<quint8>(c->myId & 0xff), static_cast<quint8>(c->myId >> 8 & 0xff), static_cast<quint8>(c->myId >> 16 & 0xff), static_cast<quint8>(c->myId >> 24 & 0xff),
static_cast<quint8>(c->remoteId & 0xff), static_cast<quint8>(c->remoteId >> 8 & 0xff), static_cast<quint8>(c->remoteId >> 16 & 0xff), static_cast<quint8>(c->remoteId >> 24 & 0xff),
/*0x10*/ 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00,
static_cast<quint8>(c->authInnerSeq & 0xff), static_cast<quint8>(c->authInnerSeq >> 8 & 0xff), 0x00,
static_cast<quint8>(c->tokenRx >> 0 & 0xff), static_cast<quint8>(c->tokenRx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx & 0xff), static_cast<quint8>(c->tokenTx >> 8 & 0xff),
static_cast<quint8>(c->tokenTx >> 16 & 0xff), static_cast<quint8>(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);
}

Wyświetl plik

@ -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;