2021-02-16 16:16:46 +00:00
# include "udpserver.h"
2021-02-23 21:21:22 +00:00
# include "logcategories.h"
2021-02-16 16:16:46 +00:00
2021-02-18 13:49:19 +00:00
# define STALE_CONNECTION 15
2021-02-16 16:16:46 +00:00
udpServer : : udpServer ( SERVERCONFIG config ) :
config ( config )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " Starting udp server " ;
2021-02-16 16:16:46 +00:00
}
void udpServer : : init ( )
{
srand ( time ( NULL ) ) ; // Generate random key
2021-02-23 20:49:26 +00:00
timeStarted . start ( ) ;
2021-02-16 16:16:46 +00:00
// 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 ( ) ) ;
}
}
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 ) ) {
macAddress = netInterface . hardwareAddress ( ) ;
}
}
2021-02-16 16:16:46 +00:00
uint32_t addr = localIP . toIPv4Address ( ) ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " My IP Address: " < < QHostAddress ( addr ) . toString ( ) < < " My MAC Address: " < < macAddress ;
2021-02-16 16:16:46 +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 ) ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " Server Binding Control to: " < < config . controlPort ;
2021-02-16 16:16:46 +00:00
udpControl = new QUdpSocket ( this ) ;
2021-06-01 16:49:48 +00:00
udpControl - > bind ( config . controlPort ) ;
2021-02-28 20:10:07 +00:00
QUdpSocket : : connect ( udpControl , & QUdpSocket : : readyRead , this , & udpServer : : controlReceived ) ;
2021-02-17 23:10:26 +00:00
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " Server Binding CIV to: " < < config . civPort ;
2021-02-16 16:16:46 +00:00
udpCiv = new QUdpSocket ( this ) ;
2021-02-17 23:10:26 +00:00
udpCiv - > bind ( config . civPort ) ;
2021-02-28 20:10:07 +00:00
QUdpSocket : : connect ( udpCiv , & QUdpSocket : : readyRead , this , & udpServer : : civReceived ) ;
2021-02-16 16:16:46 +00:00
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " Server Binding Audio to: " < < config . audioPort ;
2021-02-28 20:10:07 +00:00
udpAudio = new QUdpSocket ( this ) ;
udpAudio - > bind ( config . audioPort ) ;
2021-02-16 16:16:46 +00:00
QUdpSocket : : connect ( udpAudio , & QUdpSocket : : readyRead , this , & udpServer : : audioReceived ) ;
}
udpServer : : ~ udpServer ( )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " Closing udpServer " ;
2021-02-16 16:16:46 +00:00
2021-05-14 08:55:02 +00:00
connMutex . lock ( ) ;
2021-02-16 16:16:46 +00:00
2021-02-17 23:10:26 +00:00
foreach ( CLIENT * client , controlClients )
2021-02-16 16:16:46 +00:00
{
2021-02-18 13:49:19 +00:00
if ( client - > idleTimer ! = Q_NULLPTR )
{
client - > idleTimer - > stop ( ) ;
delete client - > idleTimer ;
}
if ( client - > pingTimer ! = Q_NULLPTR ) {
client - > pingTimer - > stop ( ) ;
delete client - > pingTimer ;
}
if ( client - > wdTimer ! = Q_NULLPTR ) {
client - > wdTimer - > stop ( ) ;
delete client - > wdTimer ;
}
2021-02-28 20:10:07 +00:00
if ( client - > retransmitTimer ! = Q_NULLPTR ) {
client - > retransmitTimer - > stop ( ) ;
delete client - > retransmitTimer ;
}
2021-02-18 13:49:19 +00:00
delete client ;
controlClients . removeAll ( client ) ;
2021-02-16 16:16:46 +00:00
}
2021-02-17 23:10:26 +00:00
foreach ( CLIENT * client , civClients )
2021-02-16 16:16:46 +00:00
{
2021-02-18 13:49:19 +00:00
if ( client - > idleTimer ! = Q_NULLPTR )
{
client - > idleTimer - > stop ( ) ;
delete client - > idleTimer ;
}
if ( client - > pingTimer ! = Q_NULLPTR ) {
client - > pingTimer - > stop ( ) ;
delete client - > pingTimer ;
}
2021-02-28 20:10:07 +00:00
if ( client - > retransmitTimer ! = Q_NULLPTR ) {
client - > retransmitTimer - > stop ( ) ;
delete client - > retransmitTimer ;
}
2021-02-18 13:49:19 +00:00
delete client ;
civClients . removeAll ( client ) ;
2021-02-16 16:16:46 +00:00
}
2021-02-17 23:10:26 +00:00
foreach ( CLIENT * client , audioClients )
2021-02-16 16:16:46 +00:00
{
2021-02-18 13:49:19 +00:00
if ( client - > idleTimer ! = Q_NULLPTR )
{
client - > idleTimer - > stop ( ) ;
delete client - > idleTimer ;
}
if ( client - > pingTimer ! = Q_NULLPTR ) {
client - > pingTimer - > stop ( ) ;
delete client - > pingTimer ;
}
2021-02-28 20:10:07 +00:00
if ( client - > retransmitTimer ! = Q_NULLPTR ) {
client - > retransmitTimer - > stop ( ) ;
delete client - > retransmitTimer ;
}
2021-02-18 13:49:19 +00:00
delete client ;
audioClients . removeAll ( client ) ;
2021-02-16 16:16:46 +00:00
}
2021-02-17 23:10:26 +00:00
2021-03-22 09:10:03 +00:00
if ( rxAudioTimer ! = Q_NULLPTR ) {
rxAudioTimer - > stop ( ) ;
delete rxAudioTimer ;
rxAudioTimer = Q_NULLPTR ;
}
2021-02-17 23:10:26 +00:00
2021-03-22 09:10:03 +00:00
if ( rxAudioThread ! = Q_NULLPTR ) {
rxAudioThread - > quit ( ) ;
rxAudioThread - > wait ( ) ;
}
if ( txAudioThread ! = Q_NULLPTR ) {
txAudioThread - > quit ( ) ;
txAudioThread - > wait ( ) ;
}
2021-02-18 13:49:19 +00:00
2021-02-17 23:10:26 +00:00
if ( udpControl ! = Q_NULLPTR ) {
udpControl - > close ( ) ;
delete udpControl ;
}
if ( udpCiv ! = Q_NULLPTR ) {
udpCiv - > close ( ) ;
delete udpCiv ;
}
if ( udpAudio ! = Q_NULLPTR ) {
udpAudio - > close ( ) ;
delete udpAudio ;
}
2021-05-14 08:55:02 +00:00
connMutex . unlock ( ) ;
2021-06-01 16:49:48 +00:00
2021-02-16 16:16:46 +00:00
}
2021-02-28 20:10:07 +00:00
void udpServer : : receiveRigCaps ( rigCapabilities caps )
{
this - > rigCaps = caps ;
}
# define RETRANSMIT_PERIOD 100
2021-02-16 16:16:46 +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 ;
2021-02-18 13:49:19 +00:00
if ( datagram . senderAddress ( ) . isNull ( ) | | datagram . senderPort ( ) = = 65535 | | datagram . senderPort ( ) = = 0 )
2021-02-18 09:14:41 +00:00
return ;
2021-02-16 16:16:46 +00:00
foreach ( CLIENT * client , controlClients )
{
2021-02-18 13:49:19 +00:00
if ( client ! = Q_NULLPTR )
2021-02-16 16:16:46 +00:00
{
2021-02-18 13:49:19 +00:00
if ( client - > ipAddress = = datagram . senderAddress ( ) & & client - > port = = datagram . senderPort ( ) )
{
current = client ;
}
2021-02-16 16:16:46 +00:00
}
}
if ( current = = Q_NULLPTR )
{
current = new CLIENT ( ) ;
2021-05-14 08:55:02 +00:00
current - > type = " Control " ;
2021-02-16 16:16:46 +00:00
current - > connected = true ;
2021-02-17 23:10:26 +00:00
current - > isStreaming = false ;
current - > timeConnected = QDateTime : : currentDateTime ( ) ;
2021-02-16 16:16:46 +00:00
current - > ipAddress = datagram . senderAddress ( ) ;
current - > port = datagram . senderPort ( ) ;
2021-02-17 23:10:26 +00:00
current - > civPort = config . civPort ;
current - > audioPort = config . audioPort ;
2021-02-16 16:16:46 +00:00
current - > myId = controlId ;
current - > remoteId = qFromLittleEndian < quint32 > ( r . mid ( 8 , 4 ) ) ;
current - > socket = udpControl ;
2021-02-17 23:10:26 +00:00
current - > pingSeq = ( quint8 ) rand ( ) < < 8 | ( quint8 ) rand ( ) ;
2021-02-28 20:10:07 +00:00
2021-02-16 16:16:46 +00:00
current - > pingTimer = new QTimer ( ) ;
2021-02-18 13:49:19 +00:00
connect ( current - > pingTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : sendPing , this , & controlClients , current , ( quint16 ) 0x00 , false ) ) ;
2021-02-16 16:16:46 +00:00
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 ) ) ;
2021-02-16 16:16:46 +00:00
current - > idleTimer - > start ( 100 ) ;
2021-02-28 20:10:07 +00:00
current - > wdTimer = new QTimer ( ) ;
connect ( current - > wdTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : watchdog , this , current ) ) ;
current - > wdTimer - > start ( 1000 ) ;
current - > retransmitTimer = new QTimer ( ) ;
connect ( current - > retransmitTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : sendRetransmitRequest , this , current ) ) ;
current - > retransmitTimer - > start ( RETRANSMIT_PERIOD ) ;
2021-02-23 20:49:26 +00:00
current - > commonCap = 0x8010 ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : New Control connection created " ;
2021-05-14 08:55:02 +00:00
connMutex . lock ( ) ;
2021-02-16 16:16:46 +00:00
controlClients . append ( current ) ;
2021-05-14 08:55:02 +00:00
connMutex . unlock ( ) ;
2021-02-16 16:16:46 +00:00
}
2021-02-17 23:10:26 +00:00
current - > lastHeard = QDateTime : : currentDateTime ( ) ;
2021-02-16 16:16:46 +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 = = 0x05 )
2021-02-16 16:16:46 +00:00
{
2021-06-01 16:49:48 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Received 'disconnect' request " ;
sendControl ( current , 0x00 , in - > seq ) ;
//current->wdTimer->stop(); // Keep watchdog running to delete stale connection.
deleteConnection ( & controlClients , current ) ;
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-02-16 16:16:46 +00:00
{
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 ) {
if ( in - > seq = = current - > pingSeq | | in - > seq = = current - > pingSeq - 1 )
2021-02-21 21:05:58 +00:00
{
2021-06-01 16:49:48 +00:00
// A Reply to our ping!
if ( in - > seq = = current - > pingSeq ) {
current - > pingSeq + + ;
}
else {
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : got out of sequence ping reply. Got: " < < in - > seq < < " expecting: " < < current - > pingSeq ;
2021-02-21 21:05:58 +00:00
}
2021-02-16 16:16:46 +00:00
}
}
}
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 ;
current - > identa = in - > identa ;
current - > identb = in - > identb ;
if ( in - > res = = 0x02 ) {
// Request for new token
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Received create token request " ;
sendCapabilities ( current ) ;
sendConnectionInfo ( current ) ;
2021-02-16 16:16:46 +00:00
}
2021-06-01 16:49:48 +00:00
else if ( in - > res = = 0x01 ) {
// Token disconnect
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Received token disconnect request " ;
sendTokenResponse ( current , in - > res ) ;
}
else if ( in - > res = = 0x04 ) {
// Disconnect audio/civ
sendTokenResponse ( current , in - > res ) ;
current - > isStreaming = false ;
sendConnectionInfo ( current ) ;
}
else {
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Received token request " ;
sendTokenResponse ( current , in - > res ) ;
}
break ;
}
case ( LOGIN_SIZE ) :
{
login_packet_t in = ( login_packet_t ) r . constData ( ) ;
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Received 'login' " ;
bool userOk = false ;
foreach ( SERVERUSER user , config . users )
2021-02-16 16:16:46 +00:00
{
2021-06-01 16:49:48 +00:00
QByteArray usercomp ;
passcode ( user . username , usercomp ) ;
QByteArray passcomp ;
passcode ( user . password , passcomp ) ;
if ( ! strcmp ( in - > username , usercomp . constData ( ) ) & & ! strcmp ( in - > password , passcomp . constData ( ) ) )
2021-02-16 16:16:46 +00:00
{
2021-06-01 16:49:48 +00:00
userOk = true ;
current - > user = user ;
break ;
2021-02-23 20:49:26 +00:00
}
2021-06-01 16:49:48 +00:00
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 ( userOk ) {
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : User " < < current - > user . username < < " login OK " ;
sendLoginResponse ( current , true ) ;
}
else {
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Incorrect username/password " ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
sendLoginResponse ( current , false ) ;
}
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 ;
current - > identa = in - > identa ;
current - > identb = in - > identb ;
sendStatus ( current ) ;
current - > authInnerSeq = 0x00 ;
sendConnectionInfo ( current ) ;
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : rxCodec: " < < current - > rxCodec < < " txCodec: " < < current - > txCodec < <
" rxSampleRate " < < current - > rxSampleRate < <
" txSampleRate " < < current - > rxSampleRate < <
" txBufferLen " < < current - > txBufferLen ;
if ( ! config . lan ) {
// Radio is connected by USB/Serial and we assume that audio is connected as well.
// Create audio TX/RX threads if they don't already exist (first client chooses samplerate/codec)
if ( txaudio = = Q_NULLPTR )
{
bool uLaw = false ;
quint8 channels = 1 ;
quint8 samples = 8 ;
txSampleRate = current - > txSampleRate ;
txCodec = current - > txCodec ;
if ( current - > txCodec = = 0x01 | | current - > txCodec = = 0x20 ) {
uLaw = true ;
}
if ( current - > txCodec = = 0x08 | | current - > txCodec = = 0x10 | | current - > txCodec = = 0x20 ) {
channels = 2 ;
}
if ( current - > txCodec = = 0x04 | | current - > txCodec = = 0x10 ) {
samples = 16 ;
}
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
txaudio = new audioHandler ( ) ;
txAudioThread = new QThread ( this ) ;
txaudio - > moveToThread ( txAudioThread ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
txAudioThread - > start ( ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
connect ( this , SIGNAL ( setupTxAudio ( quint8 , quint8 , quint16 , quint16 , bool , bool , int , quint8 ) ) , txaudio , SLOT ( init ( quint8 , quint8 , quint16 , quint16 , bool , bool , int , quint8 ) ) ) ;
connect ( txAudioThread , SIGNAL ( finished ( ) ) , txaudio , SLOT ( deleteLater ( ) ) ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
emit setupTxAudio ( samples , channels , current - > txSampleRate , current - > txBufferLen , uLaw , false , config . audioOutput , config . resampleQuality ) ;
hasTxAudio = datagram . senderAddress ( ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
connect ( this , SIGNAL ( haveAudioData ( audioPacket ) ) , txaudio , SLOT ( incomingAudio ( audioPacket ) ) ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
}
if ( rxaudio = = Q_NULLPTR )
{
bool uLaw = false ;
quint8 channels = 1 ;
quint8 samples = 8 ;
rxSampleRate = current - > rxSampleRate ;
rxCodec = current - > rxCodec ;
if ( current - > rxCodec = = 0x01 | | current - > rxCodec = = 0x20 ) {
uLaw = true ;
}
if ( current - > rxCodec = = 0x08 | | current - > rxCodec = = 0x10 | | current - > rxCodec = = 0x20 ) {
channels = 2 ;
}
if ( current - > rxCodec = = 0x04 | | current - > rxCodec = = 0x10 ) {
samples = 16 ;
}
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
rxaudio = new audioHandler ( ) ;
rxAudioThread = new QThread ( this ) ;
rxaudio - > moveToThread ( rxAudioThread ) ;
rxAudioThread - > start ( ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
connect ( this , SIGNAL ( setupRxAudio ( quint8 , quint8 , quint16 , quint16 , bool , bool , int , quint8 ) ) , rxaudio , SLOT ( init ( quint8 , quint8 , quint16 , quint16 , bool , bool , int , quint8 ) ) ) ;
connect ( rxAudioThread , SIGNAL ( finished ( ) ) , txaudio , SLOT ( deleteLater ( ) ) ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 17:03:46 +00:00
emit setupRxAudio ( samples , channels , current - > rxSampleRate , 250 , uLaw , true , config . audioInput , config . resampleQuality ) ;
2021-03-22 09:10:03 +00:00
2021-06-01 16:49:48 +00:00
rxAudioTimer = new QTimer ( ) ;
rxAudioTimer - > setTimerType ( Qt : : PreciseTimer ) ;
connect ( rxAudioTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : sendRxAudio , this ) ) ;
2021-06-01 17:03:46 +00:00
rxAudioTimer - > start ( 10 ) ;
2021-03-22 09:10:03 +00:00
}
2021-02-16 16:16:46 +00:00
}
2021-06-01 16:49:48 +00:00
break ;
}
default :
{
break ;
}
2021-02-16 16:16:46 +00:00
}
2021-02-28 20:10:07 +00:00
commonReceived ( & controlClients , current , r ) ;
2021-02-16 16:16:46 +00:00
}
}
void udpServer : : civReceived ( )
{
while ( udpCiv - > hasPendingDatagrams ( ) ) {
QNetworkDatagram datagram = udpCiv - > receiveDatagram ( ) ;
QByteArray r = datagram . data ( ) ;
2021-02-16 20:55:30 +00:00
2021-02-17 23:10:26 +00:00
CLIENT * current = Q_NULLPTR ;
2021-02-18 13:49:19 +00:00
if ( datagram . senderAddress ( ) . isNull ( ) | | datagram . senderPort ( ) = = 65535 | | datagram . senderPort ( ) = = 0 )
2021-02-18 09:14:41 +00:00
return ;
2021-02-18 13:49:19 +00:00
QDateTime now = QDateTime : : currentDateTime ( ) ;
2021-02-17 23:10:26 +00:00
foreach ( CLIENT * client , civClients )
{
2021-02-18 13:49:19 +00:00
if ( client ! = Q_NULLPTR )
2021-02-17 23:10:26 +00:00
{
2021-02-18 13:49:19 +00:00
if ( client - > ipAddress = = datagram . senderAddress ( ) & & client - > port = = datagram . senderPort ( ) )
{
current = client ;
}
2021-02-17 23:10:26 +00:00
}
}
if ( current = = Q_NULLPTR )
{
current = new CLIENT ( ) ;
2021-05-14 08:55:02 +00:00
current - > type = " CIV " ;
current - > civId = 0 ;
2021-02-17 23:10:26 +00:00
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
2021-02-17 23:10:26 +00:00
current - > pingTimer = new QTimer ( ) ;
2021-02-18 13:49:19 +00:00
connect ( current - > pingTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : sendPing , this , & civClients , current , ( quint16 ) 0x00 , false ) ) ;
2021-02-17 23:10:26 +00:00
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 - > wdTimer = new QTimer ( ) ;
connect ( current - > wdTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : watchdog , this , current ) ) ;
current - > wdTimer - > start ( 1000 ) ;
current - > retransmitTimer = new QTimer ( ) ;
connect ( current - > retransmitTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : sendRetransmitRequest , this , current ) ) ;
current - > retransmitTimer - > start ( RETRANSMIT_PERIOD ) ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): New connection created " ;
2021-05-14 08:55:02 +00:00
connMutex . lock ( ) ;
2021-02-17 23:10:26 +00:00
civClients . append ( current ) ;
2021-05-14 08:55:02 +00:00
connMutex . unlock ( ) ;
2021-02-17 23:10:26 +00:00
}
switch ( r . length ( ) )
{
2021-05-14 08:55:02 +00:00
/* case (CONTROL_SIZE):
2021-02-17 23:10:26 +00:00
{
2021-02-23 20:49:26 +00:00
}
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-02-23 20:49:26 +00:00
{
2021-06-01 16:49:48 +00:00
// It is a ping request/response
2021-02-23 20:49:26 +00:00
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 ) {
if ( in - > seq = = current - > pingSeq | | in - > seq = = current - > pingSeq - 1 )
2021-02-23 20:49:26 +00:00
{
2021-06-01 16:49:48 +00:00
// A Reply to our ping!
if ( in - > seq = = current - > pingSeq ) {
current - > pingSeq + + ;
}
else {
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : got out of sequence ping reply. Got: " < < in - > seq < < " expecting: " < < current - > pingSeq ;
2021-02-23 20:49:26 +00:00
}
2021-02-17 23:10:26 +00:00
}
}
}
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-02-23 20:49:26 +00:00
{
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 ] > ( quint8 ) 0xdf & & ( quint8 ) r [ lastFE + 2 ] < ( quint8 ) 0xef ) {
// This is (should be) the remotes CIV id.
current - > civId = ( quint8 ) r [ lastFE + 2 ] ;
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Detected remote CI-V: " < < hex < < current - > civId ;
}
else if ( current - > civId ! = 0 & & r . length ( ) > lastFE + 2 & & ( 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 ] ;
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Detected different remote CI-V: " < < hex < < current - > civId ;
2021-02-28 20:10:07 +00:00
}
2021-05-14 08:55:02 +00:00
2021-06-01 16:49:48 +00:00
emit haveDataFromServer ( r . mid ( 0x15 ) ) ;
}
else {
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : Datalen mismatch " < < quint16 ( in - > datalen + 0x15 ) < < " : " < < ( quint16 ) in - > len ;
2021-02-23 20:49:26 +00:00
}
2021-02-18 09:14:41 +00:00
}
2021-02-23 20:49:26 +00:00
}
2021-06-01 16:49:48 +00:00
//break;
}
2021-02-17 23:10:26 +00:00
}
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
2021-02-16 16:16:46 +00:00
}
}
void udpServer : : audioReceived ( )
{
while ( udpAudio - > hasPendingDatagrams ( ) ) {
QNetworkDatagram datagram = udpAudio - > receiveDatagram ( ) ;
QByteArray r = datagram . data ( ) ;
2021-02-17 23:10:26 +00:00
CLIENT * current = Q_NULLPTR ;
2021-02-18 13:49:19 +00:00
if ( datagram . senderAddress ( ) . isNull ( ) | | datagram . senderPort ( ) = = 65535 | | datagram . senderPort ( ) = = 0 )
2021-02-18 09:14:41 +00:00
return ;
2021-02-18 13:49:19 +00:00
QDateTime now = QDateTime : : currentDateTime ( ) ;
2021-02-17 23:10:26 +00:00
foreach ( CLIENT * client , audioClients )
{
2021-02-18 13:49:19 +00:00
if ( client ! = Q_NULLPTR )
2021-02-17 23:10:26 +00:00
{
2021-02-18 13:49:19 +00:00
if ( client - > ipAddress = = datagram . senderAddress ( ) & & client - > port = = datagram . senderPort ( ) )
{
current = client ;
}
2021-02-17 23:10:26 +00:00
}
}
if ( current = = Q_NULLPTR )
{
current = new CLIENT ( ) ;
2021-05-14 08:55:02 +00:00
current - > type = " Audio " ;
2021-02-17 23:10:26 +00:00
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
2021-02-17 23:10:26 +00:00
current - > pingTimer = new QTimer ( ) ;
2021-02-18 13:49:19 +00:00
connect ( current - > pingTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : sendPing , this , & audioClients , current , ( quint16 ) 0x00 , false ) ) ;
2021-02-17 23:10:26 +00:00
current - > pingTimer - > start ( 100 ) ;
2021-02-28 20:10:07 +00:00
current - > wdTimer = new QTimer ( ) ;
connect ( current - > wdTimer , & QTimer : : timeout , this , std : : bind ( & udpServer : : watchdog , this , current ) ) ;
current - > wdTimer - > start ( 1000 ) ;
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 ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): New connection created " ;
2021-05-14 08:55:02 +00:00
connMutex . lock ( ) ;
2021-02-17 23:10:26 +00:00
audioClients . append ( current ) ;
2021-05-14 08:55:02 +00:00
connMutex . unlock ( ) ;
2021-02-17 23:10:26 +00:00
}
2021-05-14 08:55:02 +00:00
2021-02-17 23:10:26 +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-02-17 23:10:26 +00:00
{
2021-06-01 16:49:48 +00:00
// It is a ping request/response
2021-02-23 20:49:26 +00:00
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 ) {
if ( in - > seq = = current - > pingSeq | | in - > seq = = current - > pingSeq - 1 )
2021-02-23 20:49:26 +00:00
{
2021-06-01 16:49:48 +00:00
// A Reply to our ping!
if ( in - > seq = = current - > pingSeq ) {
current - > pingSeq + + ;
}
else {
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " : got out of sequence ping reply. Got: " < < in - > seq < < " expecting: " < < current - > pingSeq ;
2021-02-23 20:49:26 +00:00
}
2021-02-17 23:10:26 +00:00
}
}
2021-02-23 20:49:26 +00:00
}
2021-06-01 16:49:48 +00:00
break ;
}
default :
{
/* Audio packets start as follows:
PCM 16 bit and PCM8 / uLAW stereo : 0x44 , 0x02 for first packet and 0x6c , 0x05 for second .
uLAW 8 bit / PCM 8 bit 0xd8 , 0x03 for all packets
PCM 16 bit 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-06-01 16:49:48 +00:00
if ( in - > type ! = 0x01 & & in - > len > = 0xAC ) {
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;
emit haveAudioData ( tempAudio ) ;
2021-03-22 09:10:03 +00:00
}
2021-02-17 23:10:26 +00:00
}
2021-06-01 16:49:48 +00:00
break ;
}
2021-03-22 09:10:03 +00:00
2021-02-17 23:10:26 +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-02-16 16:16:46 +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!
2021-05-21 23:52:01 +00:00
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
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): Invalid packet received, len: " < < r . length ( ) ;
2021-02-28 20:10:07 +00:00
return ;
}
2021-02-17 23:10:26 +00:00
2021-02-28 20:10:07 +00:00
switch ( r . length ( ) )
2021-02-17 23:10:26 +00:00
{
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' " ;
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
}
2021-06-01 16:49:48 +00:00
} // This is a retransmit request
else if ( in - > type = = 0x01 )
2021-02-28 20:10:07 +00:00
{
2021-06-01 16:49:48 +00:00
// Single packet request
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): Received 'retransmit' request for " < < in - > seq ;
auto match = std : : find_if ( current - > txSeqBuf . begin ( ) , current - > txSeqBuf . end ( ) , [ & cs = in - > seq ] ( SEQBUFENTRY & s ) {
return s . seqNum = = cs ;
} ) ;
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 retransmit of " < < hex < < match - > seqNum ;
match - > retransmitCount + + ;
udpMutex . lock ( ) ;
current - > socket - > writeDatagram ( match - > data , current - > ipAddress , current - > port ) ;
udpMutex . unlock ( ) ;
}
else {
// Just send an idle!
sendControl ( current , 0x00 , in - > seq ) ;
}
2021-02-28 20:10:07 +00:00
}
2021-06-01 16:49:48 +00:00
break ;
}
default :
{
//break;
}
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 )
{
auto match = std : : find_if ( current - > txSeqBuf . begin ( ) , current - > txSeqBuf . end ( ) , [ & cs = in - > seq ] ( SEQBUFENTRY & s ) {
return s . seqNum = = cs ;
} ) ;
if ( match = = current - > txSeqBuf . end ( ) ) {
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): Requested packet " < < hex < < in - > seq < < " not found " ;
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.
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): Sending retransmit of " < < hex < < match - > seqNum ;
2021-02-28 20:10:07 +00:00
match - > retransmitCount + + ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
current - > socket - > writeDatagram ( match - > data , current - > ipAddress , current - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
match + + ;
}
}
}
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") {
2021-05-15 17:53:16 +00:00
// qInfo(logUdpServer()) << "Got:" << in->seq;
2021-05-14 08:55:02 +00:00
//}
current - > rxMutex . lock ( ) ;
if ( current - > rxSeqBuf . isEmpty ( ) )
2021-02-28 20:10:07 +00:00
{
current - > rxSeqBuf . append ( in - > seq ) ;
}
else
{
std : : sort ( current - > rxSeqBuf . begin ( ) , current - > rxSeqBuf . end ( ) ) ;
if ( in - > seq < current - > rxSeqBuf . front ( ) )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): ******* seq number may have rolled over ****** previous highest: " < < hex < < current - > rxSeqBuf . back ( ) < < " current: " < < hex < < in - > seq ;
2021-02-28 20:10:07 +00:00
// Looks like it has rolled over so clear buffer and start again.
current - > rxSeqBuf . clear ( ) ;
2021-05-14 08:55:02 +00:00
current - > rxMutex . unlock ( ) ; // Must unlock the Mutex!
2021-02-28 20:10:07 +00:00
return ;
}
if ( ! current - > rxSeqBuf . contains ( in - > seq ) )
{
// Add incoming packet to the received buffer and if it is in the missing buffer, remove it.
2021-05-14 08:55:02 +00:00
2021-02-28 20:10:07 +00:00
current - > rxSeqBuf . append ( in - > seq ) ;
// Check whether this is one of our missing ones!
2021-05-14 08:55:02 +00:00
current - > missMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
auto s = std : : find_if ( current - > rxMissing . begin ( ) , current - > rxMissing . end ( ) , [ & cs = in - > seq ] ( SEQBUFENTRY & s ) { return s . seqNum = = cs ; } ) ;
if ( s ! = current - > rxMissing . end ( ) )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < current - > ipAddress . toString ( ) < < " ( " < < current - > type < < " ): Missing SEQ has been received! " < < hex < < in - > seq ;
2021-02-28 20:10:07 +00:00
s = current - > rxMissing . erase ( s ) ;
}
2021-05-14 08:55:02 +00:00
current - > missMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
}
2021-05-14 08:55:02 +00:00
current - > rxMutex . unlock ( ) ;
2021-02-17 23:10:26 +00:00
}
2021-02-28 20:10:07 +00:00
}
void udpServer : : sendControl ( CLIENT * c , quint8 type , quint16 seq )
{
2021-02-17 23:10:26 +00:00
2021-05-15 17:53:16 +00:00
//qInfo(logUdpServer()) << c->ipAddress.toString() << ": Sending control packet: " << type;
2021-02-28 20:10:07 +00:00
2021-02-23 20:49:26 +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!
2021-02-23 20:49:26 +00:00
p . len = sizeof ( p ) ;
p . type = type ;
p . sentid = c - > myId ;
p . rcvdid = c - > remoteId ;
2021-02-17 23:10:26 +00:00
2021-02-28 20:10:07 +00:00
if ( seq = = 0x00 )
{
p . seq = c - > txSeq ;
2021-05-14 08:55:02 +00:00
c - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
c - > txSeqBuf . last ( ) . seqNum = seq ;
c - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
c - > txSeqBuf . last ( ) . retransmitCount = 0 ;
c - > txSeqBuf . last ( ) . data = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > socket - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
c - > txSeq + + ;
2021-05-14 08:55:02 +00:00
//if (c->idleTimer != Q_NULLPTR) {
// c->idleTimer->start(100);
//}
c - > txMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
else {
p . seq = seq ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > socket - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
2021-02-16 16:16:46 +00:00
return ;
}
2021-02-17 23:10:26 +00:00
2021-06-01 16:49:48 +00:00
void udpServer : : sendPing ( QList < CLIENT * > * l , CLIENT * c , quint16 seq , bool reply )
2021-02-16 16:16:46 +00:00
{
2021-02-18 13:49:19 +00:00
// Also use to detect "stale" connections
QDateTime now = QDateTime : : currentDateTime ( ) ;
if ( c - > lastHeard . secsTo ( now ) > STALE_CONNECTION )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Deleting stale connection " ;
2021-02-18 13:49:19 +00:00
deleteConnection ( l , c ) ;
return ;
}
2021-05-15 17:53:16 +00:00
//qInfo(logUdpServer()) << c->ipAddress.toString() << ": Sending Ping";
2021-02-16 16:16:46 +00:00
2021-02-23 20:49:26 +00:00
quint32 pingTime = 0 ;
2021-02-16 16:16:46 +00:00
if ( reply ) {
2021-02-23 20:49:26 +00:00
pingTime = c - > rxPingTime ;
2021-02-16 16:16:46 +00:00
}
else {
2021-02-23 20:49:26 +00:00
pingTime = ( quint32 ) timeStarted . 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.
2021-02-16 16:16:46 +00:00
}
2021-02-17 23:10:26 +00:00
// First byte of pings "from" server can be either 0x00 or packet length!
2021-02-23 20:49:26 +00:00
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 ) ;
}
2021-02-23 20:49:26 +00:00
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 ;
2021-02-16 16:16:46 +00:00
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-23 20:49:26 +00:00
c - > socket - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
2021-02-16 16:16:46 +00:00
return ;
}
2021-02-28 20:10:07 +00:00
void udpServer : : sendLoginResponse ( CLIENT * c , bool allowed )
2021-02-16 16:16:46 +00:00
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Sending Login response: " < < c - > txSeq ;
2021-02-17 23:10:26 +00:00
2021-02-23 20:49:26 +00:00
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 ;
2021-02-23 20:49:26 +00:00
p . sentid = c - > myId ;
p . rcvdid = c - > remoteId ;
p . innerseq = c - > authInnerSeq ;
p . tokrequest = c - > tokenRx ;
p . token = c - > tokenTx ;
p . code = 0x0250 ;
2021-02-16 16:16:46 +00:00
if ( ! allowed ) {
2021-02-23 20:49:26 +00:00
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 ( ) ;
if ( c - > wdTimer ! = Q_NULLPTR )
c - > wdTimer - > stop ( ) ;
2021-02-16 16:16:46 +00:00
}
else {
2021-06-01 16:49:48 +00:00
strcpy ( p . connection , " WFVIEW " ) ;
2021-02-16 16:16:46 +00:00
}
2021-02-28 20:10:07 +00:00
2021-05-14 08:55:02 +00:00
c - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
c - > txSeqBuf . last ( ) . seqNum = c - > txSeq ;
c - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
c - > txSeqBuf . last ( ) . retransmitCount = 0 ;
c - > txSeqBuf . last ( ) . data = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > socket - > writeDatagram ( c - > txSeqBuf . last ( ) . data , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-23 20:49:26 +00:00
c - > txSeq + + ;
2021-02-28 20:10:07 +00:00
if ( c - > idleTimer ! = Q_NULLPTR )
c - > idleTimer - > start ( 100 ) ;
2021-05-14 08:55:02 +00:00
c - > txMutex . unlock ( ) ;
2021-02-16 16:16:46 +00:00
return ;
}
void udpServer : : sendCapabilities ( CLIENT * c )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Sending Capabilities : " < < c - > txSeq ;
2021-02-17 23:10:26 +00:00
2021-02-23 20:49:26 +00:00
capabilities_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 ;
2021-03-22 09:10:03 +00:00
p . innerseq = c - > authInnerSeq ;
2021-02-23 20:49:26 +00:00
p . tokrequest = c - > tokenRx ;
p . token = c - > tokenTx ;
p . code = 0x0298 ;
p . res = 0x02 ;
p . capa = 0x01 ;
p . commoncap = c - > commonCap ;
2021-03-22 09:10:03 +00:00
memcpy ( p . macaddress , macAddress . toLocal8Bit ( ) , 6 ) ;
2021-02-28 20:10:07 +00:00
// IRU seems to expect an "Icom" mac address so replace the first 3 octets of our Mac with one in their range!
memcpy ( p . macaddress , QByteArrayLiteral ( " \x00 \x90 \xc7 " ) . constData ( ) , 3 ) ;
2021-02-23 20:49:26 +00:00
2021-03-22 09:10:03 +00:00
memcpy ( p . name , rigCaps . modelName . toLocal8Bit ( ) , rigCaps . modelName . length ( ) ) ;
2021-02-28 20:10:07 +00:00
memcpy ( p . audio , QByteArrayLiteral ( " ICOM_VAUDIO " ) . constData ( ) , 11 ) ;
if ( rigCaps . hasWiFi & & ! rigCaps . hasEthernet ) {
p . conntype = 0x0707 ; // 0x0707 for wifi rig.
}
else {
2021-03-22 09:10:03 +00:00
p . conntype = 0x073f ; // 0x073f for ethernet rig.
2021-02-28 20:10:07 +00:00
}
p . civ = rigCaps . civ ;
2021-05-21 15:30:52 +00:00
p . baudrate = ( quint32 ) qToBigEndian ( config . baudRate ) ;
2021-03-01 16:28:15 +00:00
/*
0x80 = 12 K only
0x40 = 44.1 K only
0x20 = 22.05 K only
0x10 = 11.025 K only
0x08 = 48 K only
0x04 = 32 K only
0x02 = 16 K only
0x01 = 8 K only
*/
2021-03-22 09:10:03 +00:00
if ( rxaudio = = Q_NULLPTR ) {
p . rxsample = 0x8b01 ; // all rx sample frequencies supported
}
else {
if ( rxSampleRate = = 48000 ) {
p . rxsample = 0x0800 ; // fixed rx sample frequency
}
else if ( rxSampleRate = = 32000 ) {
p . rxsample = 0x0400 ;
}
else if ( rxSampleRate = = 24000 ) {
p . rxsample = 0x0001 ;
}
else if ( rxSampleRate = = 16000 ) {
p . rxsample = 0x0200 ;
}
else if ( rxSampleRate = = 12000 ) {
p . rxsample = 0x8000 ;
}
}
if ( txaudio = = Q_NULLPTR ) {
p . txsample = 0x8b01 ; // all tx sample frequencies supported
p . enablea = 0x01 ; // 0x01 enables TX 24K mode?
2021-05-22 10:32:57 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Client will have TX audio " ;
2021-03-22 09:10:03 +00:00
}
else {
2021-05-22 10:32:57 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Disable tx audio for client " ;
p . txsample = 0 ;
2021-03-22 09:10:03 +00:00
}
2021-02-28 20:10:07 +00:00
// I still don't know what these are?
2021-03-01 16:28:15 +00:00
p . enableb = 0x01 ; // 0x01 doesn't seem to do anything?
p . enablec = 0x01 ; // 0x01 doesn't seem to do anything?
2021-06-01 16:49:48 +00:00
p . capf = 0x5001 ;
2021-02-28 20:10:07 +00:00
p . capg = 0x0190 ;
2021-05-14 08:55:02 +00:00
c - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
c - > txSeqBuf . last ( ) . seqNum = p . seq ;
c - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
c - > txSeqBuf . last ( ) . retransmitCount = 0 ;
c - > txSeqBuf . last ( ) . data = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > socket - > writeDatagram ( c - > txSeqBuf . last ( ) . data , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
if ( c - > idleTimer ! = Q_NULLPTR )
c - > idleTimer - > start ( 100 ) ;
2021-02-17 23:10:26 +00:00
c - > txSeq + + ;
2021-05-14 08:55:02 +00:00
c - > txMutex . unlock ( ) ;
2021-02-16 16:16:46 +00:00
return ;
}
2021-02-17 23:10:26 +00:00
// When client has requested civ/audio connection, this will contain their details
// Also used to display currently connected used information.
2021-02-16 16:16:46 +00:00
void udpServer : : sendConnectionInfo ( CLIENT * c )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Sending ConnectionInfo : " < < c - > txSeq ;
2021-02-23 20:49:26 +00:00
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 ;
2021-02-28 20:10:07 +00:00
//p.innerseq = c->authInnerSeq; // Innerseq not used in user packet
2021-02-23 20:49:26 +00:00
p . tokrequest = c - > tokenRx ;
p . token = c - > tokenTx ;
p . code = 0x0380 ;
p . commoncap = c - > commonCap ;
2021-03-22 09:10:03 +00:00
p . identa = c - > identa ;
p . identb = c - > identb ;
2021-02-16 16:16:46 +00:00
// 0x1a-0x1f is authid (random number?
2021-02-17 23:10:26 +00:00
// memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7);
2021-02-16 16:16:46 +00:00
2021-03-22 09:10:03 +00:00
memcpy ( p . packet + 0x40 , rigCaps . modelName . toLocal8Bit ( ) , rigCaps . modelName . length ( ) ) ;
2021-02-17 23:10:26 +00:00
// This is the current streaming client (should we support multiple clients?)
if ( c - > isStreaming ) {
2021-02-23 20:49:26 +00:00
p . busy = 0x01 ;
memcpy ( p . computer , c - > clientName . constData ( ) , c - > clientName . length ( ) ) ;
p . ipaddress = qToBigEndian ( c - > ipAddress . toIPv4Address ( ) ) ;
2021-03-22 09:10:03 +00:00
p . identa = c - > identa ;
p . identb = c - > identb ;
2021-02-17 23:10:26 +00:00
}
2021-02-28 20:10:07 +00:00
2021-05-14 08:55:02 +00:00
c - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
c - > txSeqBuf . last ( ) . seqNum = p . seq ;
c - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
c - > txSeqBuf . last ( ) . retransmitCount = 0 ;
c - > txSeqBuf . last ( ) . data = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-23 20:49:26 +00:00
c - > socket - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
if ( c - > idleTimer ! = Q_NULLPTR )
c - > idleTimer - > start ( 100 ) ;
2021-02-17 23:10:26 +00:00
c - > txSeq + + ;
2021-05-14 08:55:02 +00:00
c - > txMutex . unlock ( ) ;
2021-02-16 16:16:46 +00:00
return ;
}
2021-02-17 23:10:26 +00:00
void udpServer : : sendTokenResponse ( CLIENT * c , quint8 type )
2021-02-16 16:16:46 +00:00
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Sending Token response for type: " < < type ;
2021-02-17 23:10:26 +00:00
2021-02-23 20:49:26 +00:00
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 ;
p . code = 0x0230 ;
2021-03-22 09:10:03 +00:00
p . identa = c - > identa ;
p . identb = c - > identb ;
p . commoncap = c - > commonCap ;
2021-02-23 20:49:26 +00:00
p . res = type ;
2021-05-14 08:55:02 +00:00
c - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
c - > txSeqBuf . last ( ) . seqNum = p . seq ;
c - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
c - > txSeqBuf . last ( ) . retransmitCount = 0 ;
c - > txSeqBuf . last ( ) . data = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-23 20:49:26 +00:00
c - > socket - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
if ( c - > idleTimer ! = Q_NULLPTR )
c - > idleTimer - > start ( 100 ) ;
2021-02-16 16:16:46 +00:00
c - > txSeq + + ;
2021-05-14 08:55:02 +00:00
c - > txMutex . unlock ( ) ;
2021-02-17 23:10:26 +00:00
return ;
}
2021-02-28 20:10:07 +00:00
# define PURGE_SECONDS 60
2021-02-18 13:49:19 +00:00
2021-02-28 20:10:07 +00:00
void udpServer : : watchdog ( CLIENT * c )
{
2021-06-01 16:49:48 +00:00
if ( c - > txMutex . tryLock ( ) ) {
//qInfo(logUdpServer()) << c->ipAddress.toString() << ":" << c->port << ":Buffers tx:"<< c->txSeqBuf.length() << " rx:" << c->rxSeqBuf.length();
// Erase old entries from the tx packet buffer. Keep the first 100 sent packets as we seem to get asked for these?
if ( ! c - > txSeqBuf . isEmpty ( ) )
{
c - > txSeqBuf . erase ( std : : remove_if ( c - > txSeqBuf . begin ( ) , c - > txSeqBuf . end ( ) , [ ] ( const SEQBUFENTRY & v )
{ return v . timeSent . secsTo ( QTime : : currentTime ( ) ) > PURGE_SECONDS ; } ) , c - > txSeqBuf . end ( ) ) ;
}
c - > txMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
// Erase old entries from the missing packets buffer
2021-06-01 16:49:48 +00:00
if ( c - > missMutex . tryLock ( ) ) {
if ( ! c - > rxMissing . isEmpty ( ) ) {
c - > rxMissing . erase ( std : : remove_if ( c - > rxMissing . begin ( ) , c - > rxMissing . end ( ) , [ ] ( const SEQBUFENTRY & v )
{ return v . timeSent . secsTo ( QTime : : currentTime ( ) ) > PURGE_SECONDS ; } ) , c - > rxMissing . end ( ) ) ;
}
c - > missMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
2021-06-01 16:49:48 +00:00
if ( c - > rxMutex . tryLock ( ) ) {
if ( ! c - > rxSeqBuf . isEmpty ( ) ) {
std : : sort ( c - > rxSeqBuf . begin ( ) , c - > rxSeqBuf . end ( ) ) ;
2021-02-17 23:10:26 +00:00
2021-06-01 16:49:48 +00:00
if ( c - > rxSeqBuf . length ( ) > 400 )
{
c - > rxSeqBuf . remove ( 0 , 200 ) ;
}
2021-02-28 20:10:07 +00:00
}
2021-06-01 16:49:48 +00:00
c - > rxMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
2021-02-16 16:16:46 +00:00
}
2021-02-17 23:10:26 +00:00
void udpServer : : sendStatus ( CLIENT * c )
{
2021-02-18 13:49:19 +00:00
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Sending Status " ;
2021-02-17 23:10:26 +00:00
2021-02-23 20:49:26 +00:00
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 ;
p . code = 0x0240 ;
p . res = 0x03 ;
p . unknown = 0x1000 ;
p . unusede = ( char ) 0x80 ;
2021-03-22 09:10:03 +00:00
p . identa = c - > identa ;
p . identb = c - > identb ;
2021-02-23 20:49:26 +00:00
2021-06-01 16:49:48 +00:00
p . civport = qToBigEndian ( c - > civPort ) ;
p . audioport = qToBigEndian ( c - > audioPort ) ;
2021-02-17 23:10:26 +00:00
// Send this to reject the request to tx/rx audio/civ
//memcpy(p + 0x30, QByteArrayLiteral("\xff\xff\xff\xfe").constData(), 4);
2021-02-16 16:16:46 +00:00
2021-02-17 23:10:26 +00:00
c - > txSeq + + ;
2021-05-14 08:55:02 +00:00
c - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
c - > txSeqBuf . last ( ) . seqNum = p . seq ;
c - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
c - > txSeqBuf . last ( ) . retransmitCount = 0 ;
c - > txSeqBuf . last ( ) . data = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-05-14 08:55:02 +00:00
c - > txMutex . unlock ( ) ;
2021-02-16 16:16:46 +00:00
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > socket - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-16 16:16:46 +00:00
2021-02-17 23:10:26 +00:00
}
2021-02-18 09:14:41 +00:00
void udpServer : : dataForServer ( QByteArray d )
{
2021-05-15 17:53:16 +00:00
//qInfo(logUdpServer()) << "Server got:" << d;
2021-02-18 09:14:41 +00:00
foreach ( CLIENT * client , civClients )
{
2021-05-14 08:55:02 +00:00
int lastFE = d . lastIndexOf ( ( quint8 ) 0xfe ) ;
2021-06-01 16:49:48 +00:00
if ( client ! = Q_NULLPTR & & client - > connected & & d . length ( ) > lastFE + 2 & & ( ( quint8 ) d [ lastFE + 1 ] = = client - > civId | | ( quint8 ) d [ lastFE + 2 ] = = client - > civId ) ) {
2021-02-23 20:49:26 +00:00
data_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
p . len = ( quint16 ) d . length ( ) + sizeof ( p ) ;
2021-02-23 20:49:26 +00:00
p . seq = client - > txSeq ;
p . sentid = client - > myId ;
p . rcvdid = client - > remoteId ;
p . reply = ( char ) 0xc1 ;
2021-02-28 20:10:07 +00:00
p . datalen = ( quint16 ) d . length ( ) ;
p . sendseq = client - > innerSeq ;
2021-02-23 20:49:26 +00:00
QByteArray t = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-02-18 13:49:19 +00:00
t . append ( d ) ;
2021-05-14 08:55:02 +00:00
client - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
client - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
client - > txSeqBuf . last ( ) . seqNum = p . seq ;
client - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
client - > txSeqBuf . last ( ) . retransmitCount = 0 ;
client - > txSeqBuf . last ( ) . data = t ;
2021-05-14 08:55:02 +00:00
client - > txMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
2021-05-15 17:53:16 +00:00
//qInfo(logUdpServer()) << "Sending:" << d;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
client - > socket - > writeDatagram ( t , client - > ipAddress , client - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-18 13:49:19 +00:00
client - > txSeq + + ;
2021-02-28 20:10:07 +00:00
client - > innerSeq + + ;
}
}
return ;
}
2021-03-22 09:10:03 +00:00
void udpServer : : sendRxAudio ( )
{
2021-05-28 09:45:09 +00:00
QByteArray audio ;
2021-05-27 13:42:28 +00:00
if ( rxaudio ) {
2021-05-28 09:45:09 +00:00
audio . clear ( ) ;
2021-03-22 09:10:03 +00:00
rxaudio - > getNextAudioChunk ( audio ) ;
int len = 0 ;
while ( len < audio . length ( ) ) {
audioPacket partial ;
2021-05-27 10:41:08 +00:00
partial . data = audio . mid ( len , 1364 ) ;
2021-03-22 09:10:03 +00:00
receiveAudioData ( partial ) ;
2021-05-27 10:41:08 +00:00
len = len + partial . data . length ( ) ;
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
{
2021-05-15 17:53:16 +00:00
//qInfo(logUdpServer()) << "Server got:" << d.data.length();
2021-02-28 20:10:07 +00:00
foreach ( CLIENT * client , audioClients )
{
if ( client ! = Q_NULLPTR & & client - > connected ) {
audio_packet p ;
memset ( p . packet , 0x0 , sizeof ( p ) ) ; // We can't be sure it is initialized with 0x00!
2021-05-27 10:41:08 +00:00
p . len = sizeof ( p ) + d . data . length ( ) ;
2021-02-28 20:10:07 +00:00
p . sentid = client - > myId ;
p . rcvdid = client - > remoteId ;
p . ident = 0x0080 ; // audio is always this?
2021-05-27 10:41:08 +00:00
p . datalen = ( quint16 ) qToBigEndian ( ( quint16 ) d . data . length ( ) ) ;
2021-02-28 20:10:07 +00:00
p . sendseq = ( quint16 ) qToBigEndian ( ( quint16 ) client - > sendAudioSeq ) ; // THIS IS BIG ENDIAN!
2021-03-22 09:10:03 +00:00
p . seq = client - > txSeq ;
2021-02-28 20:10:07 +00:00
QByteArray t = QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) ;
2021-05-27 10:41:08 +00:00
t . append ( d . data ) ;
2021-05-14 08:55:02 +00:00
client - > txMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
client - > txSeqBuf . append ( SEQBUFENTRY ( ) ) ;
client - > txSeqBuf . last ( ) . seqNum = p . seq ;
client - > txSeqBuf . last ( ) . timeSent = QTime : : currentTime ( ) ;
client - > txSeqBuf . last ( ) . retransmitCount = 0 ;
client - > txSeqBuf . last ( ) . data = t ;
2021-05-14 08:55:02 +00:00
client - > txMutex . unlock ( ) ;
2021-06-01 16:49:48 +00:00
if ( udpMutex . tryLock ( ) ) {
client - > socket - > writeDatagram ( t , client - > ipAddress , client - > port ) ;
udpMutex . unlock ( ) ;
}
else {
qDebug ( logUdpServer ( ) ) < < " Failed to lock udpMutex() " ;
}
2021-02-28 20:10:07 +00:00
client - > txSeq + + ;
client - > sendAudioSeq + + ;
2021-02-18 13:49:19 +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 ;
}
2021-03-13 09:50:43 +00:00
/// <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
{
2021-05-14 08:55:02 +00:00
c - > missMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
QByteArray missingSeqs ;
auto i = std : : adjacent_find ( c - > rxSeqBuf . begin ( ) , c - > rxSeqBuf . end ( ) , [ ] ( quint16 l , quint16 r ) { return l + 1 < r ; } ) ;
while ( i ! = c - > rxSeqBuf . end ( ) )
{
if ( i + 1 ! = c - > rxSeqBuf . end ( ) )
{
if ( * ( i + 1 ) - * i < 30 )
{
for ( quint16 j = * i + 1 ; j < * ( i + 1 ) ; j + + )
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Found missing seq between " < < * i < < " : " < < * ( i + 1 ) < < " ( " < < j < < " ) " ;
2021-02-28 20:10:07 +00:00
auto s = std : : find_if ( c - > rxMissing . begin ( ) , c - > rxMissing . end ( ) , [ & cs = j ] ( SEQBUFENTRY & s ) { return s . seqNum = = cs ; } ) ;
if ( s = = c - > rxMissing . end ( ) )
{
// We haven't seen this missing packet before
2021-06-01 16:49:48 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): Adding to missing buffer (len= " < < c - > rxMissing . length ( ) < < " ): " < < j ;
2021-02-28 20:10:07 +00:00
c - > rxMissing . append ( SEQBUFENTRY ( ) ) ;
c - > rxMissing . last ( ) . seqNum = j ;
c - > rxMissing . last ( ) . retransmitCount = 0 ;
c - > rxMissing . last ( ) . timeSent = QTime : : currentTime ( ) ;
//packetsLost++;
}
else {
if ( s - > retransmitCount = = 4 & & j ! = 0 )
{
// We have tried 4 times to request this packet, time to give up!
s = c - > rxMissing . erase ( s ) ;
2021-05-14 08:55:02 +00:00
c - > rxMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > rxSeqBuf . append ( j ) ; // Final thing is to add to received buffer!
2021-05-14 08:55:02 +00:00
c - > rxMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
}
}
}
else {
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " : Too many missing, flushing buffers " ;
2021-05-14 08:55:02 +00:00
c - > rxMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > rxSeqBuf . clear ( ) ;
2021-05-14 08:55:02 +00:00
c - > rxMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
missingSeqs . clear ( ) ;
break ;
}
}
i + + ;
}
for ( auto it = c - > rxMissing . begin ( ) ; it ! = c - > rxMissing . end ( ) ; + + it )
{
if ( it - > retransmitCount < 10 )
{
missingSeqs . append ( it - > seqNum & 0xff ) ;
missingSeqs . append ( it - > seqNum > > 8 & 0xff ) ;
missingSeqs . append ( it - > seqNum & 0xff ) ;
missingSeqs . append ( it - > seqNum > > 8 & 0xff ) ;
it - > retransmitCount + + ;
}
}
if ( missingSeqs . length ( ) ! = 0 )
{
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 . seq = ( missingSeqs [ 0 ] & 0xff ) | ( quint16 ) ( missingSeqs [ 1 ] < < 8 ) ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): sending request for missing packet : " < < hex < < p . seq ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > socket - > writeDatagram ( QByteArray : : fromRawData ( ( const char * ) p . packet , sizeof ( p ) ) , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
else
{
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < c - > ipAddress . toString ( ) < < " ( " < < c - > type < < " ): sending request for multiple missing packets : " < < missingSeqs . toHex ( ) ;
2021-02-28 20:10:07 +00:00
missingSeqs . insert ( 0 , p . packet , sizeof ( p . packet ) ) ;
2021-05-14 08:55:02 +00:00
udpMutex . lock ( ) ;
2021-02-28 20:10:07 +00:00
c - > socket - > writeDatagram ( missingSeqs , c - > ipAddress , c - > port ) ;
2021-05-14 08:55:02 +00:00
udpMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
}
2021-05-14 08:55:02 +00:00
c - > missMutex . unlock ( ) ;
2021-02-28 20:10:07 +00:00
}
2021-03-13 09:50:43 +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-02-18 13:49:19 +00:00
{
2021-05-14 08:55:02 +00:00
connMutex . lock ( ) ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " Deleting connection to: " < < c - > ipAddress . toString ( ) < < " : " < < QString : : number ( c - > port ) ;
2021-02-18 14:15:03 +00:00
if ( c - > idleTimer ! = Q_NULLPTR ) {
c - > idleTimer - > stop ( ) ;
delete c - > idleTimer ;
}
if ( c - > pingTimer ! = Q_NULLPTR ) {
c - > pingTimer - > stop ( ) ;
delete c - > pingTimer ;
}
if ( c - > wdTimer ! = Q_NULLPTR ) {
c - > wdTimer - > stop ( ) ;
delete c - > wdTimer ;
}
2021-02-28 20:10:07 +00:00
if ( c - > retransmitTimer ! = Q_NULLPTR ) {
c - > retransmitTimer - > stop ( ) ;
delete c - > retransmitTimer ;
}
2021-02-18 13:49:19 +00:00
QList < CLIENT * > : : iterator it = l - > begin ( ) ;
while ( it ! = l - > end ( ) ) {
CLIENT * client = * it ;
if ( client ! = Q_NULLPTR & & client = = c ) {
it = l - > erase ( it ) ;
}
else {
+ + it ;
}
}
2021-02-18 14:15:03 +00:00
delete c ; // Is this needed or will the erase have done it?
2021-02-18 13:49:19 +00:00
c = Q_NULLPTR ;
2021-05-15 17:53:16 +00:00
qInfo ( logUdpServer ( ) ) < < " Current Number of clients connected: " < < l - > length ( ) ;
2021-03-22 09:10:03 +00:00
if ( l - > length ( ) = = 0 ) {
if ( rxAudioTimer ! = Q_NULLPTR ) {
rxAudioTimer - > stop ( ) ;
delete rxAudioTimer ;
rxAudioTimer = Q_NULLPTR ;
}
if ( rxAudioThread ! = Q_NULLPTR ) {
rxAudioThread - > quit ( ) ;
rxAudioThread - > wait ( ) ;
rxaudio = Q_NULLPTR ;
rxAudioThread = Q_NULLPTR ;
}
if ( txAudioThread ! = Q_NULLPTR ) {
txAudioThread - > quit ( ) ;
txAudioThread - > wait ( ) ;
txaudio = Q_NULLPTR ;
txAudioThread = Q_NULLPTR ;
}
2021-06-01 16:49:48 +00:00
2021-03-22 09:10:03 +00:00
}
2021-05-14 08:55:02 +00:00
connMutex . unlock ( ) ;
2021-02-18 13:49:19 +00:00
}