From 67d360fef439d77a77a2a3cc4096d6e52207dc57 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Tue, 21 Jan 2025 15:00:05 +0000 Subject: [PATCH 01/17] Add --enabletcp option for server --- src/main.cpp | 13 +++++++++++++ src/server.cpp | 2 ++ src/server.h | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 98e5ab09ae..d71209b1f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -96,6 +96,7 @@ int main ( int argc, char** argv ) bool bUseTranslation = true; bool bCustomPortNumberGiven = false; bool bEnableIPv6 = false; + bool bEnableTcp = false; int iNumServerChannels = DEFAULT_USED_NUM_CHANNELS; quint16 iPortNumber = DEFAULT_PORT_NUMBER; int iJsonRpcPortNumber = INVALID_PORT; @@ -251,6 +252,16 @@ int main ( int argc, char** argv ) // Server only: + // Enable TCP server --------------------------------------------------- + if ( GetFlagArgument ( argv, i, "--enabletcp", "--enabletcp" ) ) + { + bEnableTcp = true; + qInfo() << "- TCP server enabled"; + CommandLineOptions << "--enabletcp"; + ServerOnlyOptions << "--enabletcp"; + continue; + } + // Disconnect all clients on quit -------------------------------------- if ( GetFlagArgument ( argv, i, "-d", "--discononquit" ) ) { @@ -993,6 +1004,7 @@ int main ( int argc, char** argv ) bDisableRecording, bDelayPan, bEnableIPv6, + bEnableTcp, eLicenceType ); #ifndef NO_JSON_RPC @@ -1117,6 +1129,7 @@ QString UsageArguments ( char** argv ) " --norecord set server not to record by default when recording is configured\n" " -s, --server start Server\n" " --serverbindip IP address the Server will bind to (rather than all)\n" + " --enabletcp enable TCP server for Jamulus protocol\n" " -T, --multithreading use multithreading to make better use of\n" " multi-core CPUs and support more Clients\n" " -u, --numchannels maximum number of channels\n" diff --git a/src/server.cpp b/src/server.cpp index a477771fde..2f9ab65172 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -44,6 +44,7 @@ CServer::CServer ( const int iNewMaxNumChan, const bool bDisableRecording, const bool bNDelayPan, const bool bNEnableIPv6, + const bool bNEnableTcp, const ELicenceType eNLicenceType ) : bUseDoubleSystemFrameSize ( bNUseDoubleSystemFrameSize ), bUseMultithreading ( bNUseMultithreading ), @@ -69,6 +70,7 @@ CServer::CServer ( const int iNewMaxNumChan, bAutoRunMinimized ( false ), bDelayPan ( bNDelayPan ), bEnableIPv6 ( bNEnableIPv6 ), + bEnableTcp ( bNEnableTcp ), eLicenceType ( eNLicenceType ), bDisconnectAllClientsOnQuit ( bNDisconnectAllClientsOnQuit ), pSignalHandler ( CSignalHandler::getSingletonP() ) diff --git a/src/server.h b/src/server.h index cbdbb04373..18fb97a360 100644 --- a/src/server.h +++ b/src/server.h @@ -104,6 +104,7 @@ class CServer : public QObject, public CServerSlots const bool bDisableRecording, const bool bNDelayPan, const bool bNEnableIPv6, + const bool bNEnableTcp, const ELicenceType eNLicenceType ); virtual ~CServer(); @@ -299,6 +300,9 @@ class CServer : public QObject, public CServerSlots // enable IPv6 bool bEnableIPv6; + // enable TCP Server + bool bEnableTcp; + // messaging QString strWelcomeMessage; ELicenceType eLicenceType; From 3513a6e0b7e94ef30ec65ff14a8d1f1baf8fb5ed Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Fri, 22 Mar 2024 23:52:50 +0000 Subject: [PATCH 02/17] Initial skeleton for TCP protocol server --- Jamulus.pro | 2 + src/protocol.cpp | 10 +++ src/protocol.h | 2 + src/server.cpp | 5 ++ src/server.h | 2 + src/tcpserver.cpp | 178 ++++++++++++++++++++++++++++++++++++++++++++++ src/tcpserver.h | 78 ++++++++++++++++++++ 7 files changed, 277 insertions(+) create mode 100644 src/tcpserver.cpp create mode 100644 src/tcpserver.h diff --git a/Jamulus.pro b/Jamulus.pro index 28f3bacd74..3f00695463 100644 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -399,6 +399,7 @@ HEADERS += src/plugins/audioreverb.h \ src/serverlogging.h \ src/settings.h \ src/socket.h \ + src/tcpserver.h \ src/util.h \ src/recorder/jamrecorder.h \ src/recorder/creaperproject.h \ @@ -507,6 +508,7 @@ SOURCES += src/plugins/audioreverb.cpp \ src/settings.cpp \ src/signalhandler.cpp \ src/socket.cpp \ + src/tcpserver.cpp \ src/util.cpp \ src/recorder/jamrecorder.cpp \ src/recorder/creaperproject.cpp \ diff --git a/src/protocol.cpp b/src/protocol.cpp index 47be8bc265..aebb30c3a8 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -2582,6 +2582,16 @@ bool CProtocol::EvaluateCLRegisterServerResp ( const CHostAddress& InetAddr, con /******************************************************************************\ * Message generation and parsing * \******************************************************************************/ +int CProtocol::GetBodyLength ( const CVector& vecbyData ) +{ + int iCurPos = 5; // position of length calculation + + // 2 bytes length + const int iLenBy = static_cast ( GetValFromStream ( vecbyData, iCurPos, 2 ) ); + + return iLenBy + 2; // remaining length to read, including CRC +} + bool CProtocol::ParseMessageFrame ( const CVector& vecbyData, const int iNumBytesIn, CVector& vecbyMesBodyData, diff --git a/src/protocol.h b/src/protocol.h index b76e66607b..bee41da93c 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -154,6 +154,8 @@ class CProtocol : public QObject void CreateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector& vecLevelList, const int iNumClients ); void CreateCLRegisterServerResp ( const CHostAddress& InetAddr, const ESvrRegResult eResult ); + static int GetBodyLength ( const CVector& vecbyData ); + static bool ParseMessageFrame ( const CVector& vecbyData, const int iNumBytesIn, CVector& vecbyMesBodyData, diff --git a/src/server.cpp b/src/server.cpp index 2f9ab65172..b985bc2cd3 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -51,6 +51,7 @@ CServer::CServer ( const int iNewMaxNumChan, iMaxNumChannels ( iNewMaxNumChan ), iCurNumChannels ( 0 ), Socket ( this, iPortNumber, iQosNumber, strServerBindIP, bNEnableIPv6 ), + TcpServer ( this, strServerBindIP, iPortNumber, bNEnableIPv6 ), Logging(), iFrameCount ( 0 ), bWriteStatusHTMLFile ( false ), @@ -306,6 +307,10 @@ CServer::CServer ( const int iNewMaxNumChan, // start the socket (it is important to start the socket after all // initializations and connections) Socket.Start(); + if ( bEnableTcp ) + { + TcpServer.Start(); + } } template diff --git a/src/server.h b/src/server.h index 18fb97a360..791927b2ee 100644 --- a/src/server.h +++ b/src/server.h @@ -42,6 +42,7 @@ #include "util.h" #include "serverlogging.h" #include "serverlist.h" +#include "tcpserver.h" #include "recorder/jamcontroller.h" #include "threadpool.h" @@ -271,6 +272,7 @@ class CServer : public QObject, public CServerSlots // actual working objects CHighPrioSocket Socket; + CTcpServer TcpServer; // logging CServerLogging Logging; diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp new file mode 100644 index 0000000000..a165abb942 --- /dev/null +++ b/src/tcpserver.cpp @@ -0,0 +1,178 @@ +/******************************************************************************\ + * Copyright (c) 2024 + * + * Author(s): + * Tony Mountifield + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + \******************************************************************************/ + +#include "tcpserver.h" + +#include "server.h" +#include "channel.h" + +CTcpServer::CTcpServer ( CServer* pNServP, const QString& strServerBindIP, int iPort, bool bEnableIPv6 ) : + pServer ( pNServP ), + strServerBindIP ( strServerBindIP ), + iPort ( iPort ), + bEnableIPv6 ( bEnableIPv6 ), + pTcpServer ( new QTcpServer ( this ) ) +{ + //// connect ( this, &CTcpServer::ProtocolCLMessageReceived, pServer, &CServer::OnProtocolCLMessageReceived ); + connect ( pTcpServer, &QTcpServer::newConnection, this, &CTcpServer::OnNewConnection ); +} + +CTcpServer::~CTcpServer() +{ + if ( pTcpServer->isListening() ) + { + qInfo() << "- stopping Jamulus-TCP server"; + pTcpServer->close(); + } +} + +bool CTcpServer::Start() +{ + if ( iPort < 0 ) + { + return false; + } + + // default to any-address for either both IP protocols or just IPv4 + QHostAddress hostAddress = bEnableIPv6 ? QHostAddress::Any : QHostAddress::AnyIPv4; + + if ( !bEnableIPv6 ) + { + if ( !strServerBindIP.isEmpty() ) + { + hostAddress = QHostAddress ( strServerBindIP ); + } + } + + if ( pTcpServer->listen ( hostAddress, iPort ) ) + { + qInfo() << qUtf8Printable ( + QString ( "- Jamulus-TCP: Server started on %1:%2" ).arg ( pTcpServer->serverAddress().toString() ).arg ( pTcpServer->serverPort() ) ); + return true; + } + qInfo() << "- Jamulus-TCP: Unable to start server:" << pTcpServer->errorString(); + return false; +} + +void CTcpServer::OnNewConnection() +{ + QTcpSocket* pSocket = pTcpServer->nextPendingConnection(); + if ( !pSocket ) + { + return; + } + + // express IPv4 address as IPv4 + CHostAddress peerAddress ( pSocket->peerAddress(), pSocket->peerPort() ); + + if ( peerAddress.InetAddr.protocol() == QAbstractSocket::IPv6Protocol ) + { + bool ok; + quint32 ip4 = peerAddress.InetAddr.toIPv4Address ( &ok ); + if ( ok ) + { + peerAddress.InetAddr.setAddress ( ip4 ); + } + } + + CTcpConnection* pTcpConnection = new CTcpConnection ( pSocket, peerAddress ); + + qDebug() << "- Jamulus-TCP: received connection from:" << peerAddress.InetAddr.toString(); + + // allocate memory for network receive and send buffer in samples + CVector vecbyRecBuf; + vecbyRecBuf.Init ( MAX_SIZE_BYTES_NETW_BUF ); + + connect ( pSocket, &QTcpSocket::disconnected, [this, pTcpConnection]() { + qDebug() << "- Jamulus-TCP: connection from:" << pTcpConnection->tcpAddress.InetAddr.toString() << "closed"; + pTcpConnection->pTcpSocket->deleteLater(); + delete pTcpConnection; + } ); + + connect ( pSocket, &QTcpSocket::readyRead, [this, pTcpConnection, vecbyRecBuf]() { + // handle received Jamulus protocol packet + + // check if this is a protocol message + int iRecCounter; + int iRecID; + CVector vecbyMesBodyData; + + long iNumBytesRead = pTcpConnection->pTcpSocket->read ( (char*) &vecbyRecBuf[0], MESS_HEADER_LENGTH_BYTE ); + if ( iNumBytesRead == -1 ) + { + return; + } + + if ( iNumBytesRead < MESS_HEADER_LENGTH_BYTE ) + { + qDebug() << "-- short read: expected" << MESS_HEADER_LENGTH_BYTE << "bytes, got" << iNumBytesRead; + return; + } + + long iPayloadLength = CProtocol::GetBodyLength ( vecbyRecBuf ); + + long iNumBytesRead2 = pTcpConnection->pTcpSocket->read ( (char*) &vecbyRecBuf[MESS_HEADER_LENGTH_BYTE], iPayloadLength ); + if ( iNumBytesRead2 == -1 ) + { + return; + } + + if ( iNumBytesRead2 < iPayloadLength ) + { + qDebug() << "-- short read: expected" << iPayloadLength << "bytes, got" << iNumBytesRead2; + return; + } + + iNumBytesRead += iNumBytesRead2; + + qDebug() << "- Jamulus-TCP: received protocol message of length" << iNumBytesRead; + + if ( !CProtocol::ParseMessageFrame ( vecbyRecBuf, iNumBytesRead, vecbyMesBodyData, iRecCounter, iRecID ) ) + { + qDebug() << "- Jamulus-TCP: message parsed OK, ID =" << iRecID; + + // this is a protocol message, check the type of the message + if ( CProtocol::IsConnectionLessMessageID ( iRecID ) ) + { + //### TODO: BEGIN ###// + // a copy of the vector is used -> avoid malloc in real-time routine + //// emit ProtocolCLMessageReceived ( iRecID, vecbyMesBodyData, peerAddress, pSocket ); + //### TODO: END ###// + } + else + { + //### TODO: BEGIN ###// + // a copy of the vector is used -> avoid malloc in real-time routine + // emit ProtocolMessageReceived ( iRecCounter, iRecID, vecbyMesBodyData, peerAddress, pSocket ); + //### TODO: END ###// + } + } + } ); +} + +#if 0 +void CTcpServer::Send ( QTcpSocket* pSocket ) { + // pSocket->write ( ); +} +#endif diff --git a/src/tcpserver.h b/src/tcpserver.h new file mode 100644 index 0000000000..2d57eb7a8a --- /dev/null +++ b/src/tcpserver.h @@ -0,0 +1,78 @@ +/******************************************************************************\ + * Copyright (c) 2024 + * + * Author(s): + * Tony Mountifield + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * +\******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "global.h" +#include "protocol.h" +#include "util.h" + +// The header files channel.h and server.h require to include this header file +// so we get a cyclic dependency. To solve this issue, a prototype of the +// channel class and server class is defined here. +class CServer; // forward declaration of CServer +class CChannel; // forward declaration of CChannel + +/* Classes ********************************************************************/ +class CTcpServer : public QObject +{ + Q_OBJECT + +public: + CTcpServer ( CServer* pNServP, const QString& strServerBindIP, int iPort, bool bEnableIPv6 ); + virtual ~CTcpServer(); + + bool Start(); + +private: + CServer* pServer; // for server + const QString strServerBindIP; + const int iPort; + const bool bEnableIPv6; + QTcpServer* pTcpServer; + +signals: + void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, QTcpSocket* pTcpSocket ); + +protected slots: + void OnNewConnection(); +}; + +class CTcpConnection +{ +public: + CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress ) : pTcpSocket ( pTcpSocket ), tcpAddress ( tcpAddress ) {} + ~CTcpConnection() {} + + QTcpSocket* pTcpSocket; + CHostAddress tcpAddress; + CHostAddress udpAddress; +}; From 4e513ce97392c434fad23939769a1764cb0f18f4 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Mon, 25 Mar 2024 17:16:21 +0000 Subject: [PATCH 03/17] Add handling of CL msgs for Server and client list --- src/channel.h | 12 ++++++++---- src/client.cpp | 16 ++++++++++++---- src/client.h | 4 ++-- src/protocol.cpp | 32 +++++++++++++++++++------------- src/protocol.h | 25 ++++++++++++++++--------- src/server.cpp | 16 ++++++++++++---- src/server.h | 11 +++++++---- src/serverlist.cpp | 10 +++++++--- src/serverlist.h | 2 +- src/socket.h | 3 ++- src/tcpserver.cpp | 7 ++++--- src/tcpserver.h | 8 ++++---- src/testbench.h | 4 ++-- 13 files changed, 96 insertions(+), 54 deletions(-) diff --git a/src/channel.h b/src/channel.h index 1567268307..9adc57e916 100644 --- a/src/channel.h +++ b/src/channel.h @@ -86,6 +86,9 @@ class CChannel : public QObject void SetAddress ( const CHostAddress& NAddr ) { InetAddr = NAddr; } const CHostAddress& GetAddress() const { return InetAddr; } + void SetTcpConnection ( CTcpConnection* pConnection ) { pTcpConnection = pConnection; } + CTcpConnection* GetTcpConnection() { return pTcpConnection; } + void ResetInfo() { bIsIdentified = false; @@ -186,7 +189,8 @@ class CChannel : public QObject } // connection parameters - CHostAddress InetAddr; + CHostAddress InetAddr; + CTcpConnection* pTcpConnection; // channel info CChannelCoreInfo ChannelInfo; @@ -255,9 +259,9 @@ public slots: PutProtocolData ( iRecCounter, iRecID, vecbyMesBodyData, RecHostAddr ); } - void OnProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr ) + void OnProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr, CTcpConnection* pTcpConnection ) { - emit DetectedCLMessage ( vecbyMesBodyData, iRecID, RecHostAddr ); + emit DetectedCLMessage ( vecbyMesBodyData, iRecID, RecHostAddr, pTcpConnection ); } void OnNewConnection() { emit NewConnection(); } @@ -282,7 +286,7 @@ public slots: void RecorderStateReceived ( ERecorderState eRecorderState ); void Disconnected(); - void DetectedCLMessage ( CVector vecbyMesBodyData, int iRecID, CHostAddress RecHostAddr ); + void DetectedCLMessage ( CVector vecbyMesBodyData, int iRecID, CHostAddress RecHostAddr, CTcpConnection* pTcpConnection ); void ParseMessageBody ( CVector vecbyMesBodyData, int iRecCounter, int iRecID ); }; diff --git a/src/client.cpp b/src/client.cpp index 417f08a404..4b836cbd4a 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -249,11 +249,19 @@ void CClient::OnSendProtMessage ( CVector vecMessage ) Socket.SendPacket ( vecMessage, Channel.GetAddress() ); } -void CClient::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage ) +void CClient::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ) { // the protocol queries me to call the function to send the message // send it through the network - Socket.SendPacket ( vecMessage, InetAddr ); + if ( pTcpConnection ) + { + // send to the connected socket directly + pTcpConnection->pTcpSocket->write ( (const char*) &( (CVector) vecMessage )[0], vecMessage.Size() ); + } + else + { + Socket.SendPacket ( vecMessage, InetAddr ); + } } void CClient::OnInvalidPacketReceived ( CHostAddress RecHostAddr ) @@ -268,10 +276,10 @@ void CClient::OnInvalidPacketReceived ( CHostAddress RecHostAddr ) } } -void CClient::OnDetectedCLMessage ( CVector vecbyMesBodyData, int iRecID, CHostAddress RecHostAddr ) +void CClient::OnDetectedCLMessage ( CVector vecbyMesBodyData, int iRecID, CHostAddress RecHostAddr, CTcpConnection* pTcpConnection ) { // connection less messages are always processed - ConnLessProtocol.ParseConnectionLessMessageBody ( vecbyMesBodyData, iRecID, RecHostAddr ); + ConnLessProtocol.ParseConnectionLessMessageBody ( vecbyMesBodyData, iRecID, RecHostAddr, pTcpConnection ); } void CClient::OnJittBufSizeChanged ( int iNewJitBufSize ) diff --git a/src/client.h b/src/client.h index 6139ef599e..6f021e3125 100644 --- a/src/client.h +++ b/src/client.h @@ -427,7 +427,7 @@ protected slots: void OnSendProtMessage ( CVector vecMessage ); void OnInvalidPacketReceived ( CHostAddress RecHostAddr ); - void OnDetectedCLMessage ( CVector vecbyMesBodyData, int iRecID, CHostAddress RecHostAddr ); + void OnDetectedCLMessage ( CVector vecbyMesBodyData, int iRecID, CHostAddress RecHostAddr, CTcpConnection* pTcpConnection ); void OnReqJittBufSize() { CreateServerJitterBufferMessage(); } void OnJittBufSizeChanged ( int iNewJitBufSize ); @@ -442,7 +442,7 @@ protected slots: } void OnCLPingReceived ( CHostAddress InetAddr, int iMs ); - void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage ); + void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ); void OnCLPingWithNumClientsReceived ( CHostAddress InetAddr, int iMs, int iNumClients ); diff --git a/src/protocol.cpp b/src/protocol.cpp index aebb30c3a8..c127497062 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -605,7 +605,10 @@ void CProtocol::CreateAndImmSendAcknMess ( const int& iID, const int& iCnt ) emit MessReadyForSending ( vecAcknMessage ); } -void CProtocol::CreateAndImmSendConLessMessage ( const int iID, const CVector& vecData, const CHostAddress& InetAddr ) +void CProtocol::CreateAndImmSendConLessMessage ( const int iID, + const CVector& vecData, + const CHostAddress& InetAddr, + CTcpConnection* pTcpConnection ) { CVector vecNewMessage; @@ -614,7 +617,7 @@ void CProtocol::CreateAndImmSendConLessMessage ( const int iID, const CVector& vecbyMesBodyData, const int iRecCounter, const int iRecID ) @@ -838,7 +841,10 @@ void CProtocol::ParseMessageBody ( const CVector& vecbyMesBodyData, con } } -void CProtocol::ParseConnectionLessMessageBody ( const CVector& vecbyMesBodyData, const int iRecID, const CHostAddress& InetAddr ) +void CProtocol::ParseConnectionLessMessageBody ( const CVector& vecbyMesBodyData, + const int iRecID, + const CHostAddress& InetAddr, + CTcpConnection* pTcpConnection ) { //### TEST: BEGIN ###// // Test channel implementation: randomly delete protocol messages (50 % loss) @@ -870,7 +876,7 @@ void CProtocol::ParseConnectionLessMessageBody ( const CVector& vecbyMe break; case PROTMESSID_CLM_REQ_SERVER_LIST: - EvaluateCLReqServerListMes ( InetAddr ); + EvaluateCLReqServerListMes ( InetAddr, pTcpConnection ); break; case PROTMESSID_CLM_SEND_EMPTY_MESSAGE: @@ -906,7 +912,7 @@ void CProtocol::ParseConnectionLessMessageBody ( const CVector& vecbyMe break; case PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST: - EvaluateCLReqConnClientsListMes ( InetAddr ); + EvaluateCLReqConnClientsListMes ( InetAddr, pTcpConnection ); break; case PROTMESSID_CLM_CHANNEL_LEVEL_LIST: @@ -2005,7 +2011,7 @@ bool CProtocol::EvaluateCLUnregisterServerMes ( const CHostAddress& InetAddr ) return false; // no error } -void CProtocol::CreateCLServerListMes ( const CHostAddress& InetAddr, const CVector vecServerInfo ) +void CProtocol::CreateCLServerListMes ( const CHostAddress& InetAddr, const CVector vecServerInfo, CTcpConnection* pTcpConnection ) { const int iNumServers = vecServerInfo.Size(); @@ -2060,7 +2066,7 @@ void CProtocol::CreateCLServerListMes ( const CHostAddress& InetAddr, const CVec PutStringUTF8OnStream ( vecData, iPos, strUTF8City ); } - CreateAndImmSendConLessMessage ( PROTMESSID_CLM_SERVER_LIST, vecData, InetAddr ); + CreateAndImmSendConLessMessage ( PROTMESSID_CLM_SERVER_LIST, vecData, InetAddr, pTcpConnection ); } bool CProtocol::EvaluateCLServerListMes ( const CHostAddress& InetAddr, const CVector& vecData ) @@ -2225,10 +2231,10 @@ void CProtocol::CreateCLReqServerListMes ( const CHostAddress& InetAddr ) CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_SERVER_LIST, CVector ( 0 ), InetAddr ); } -bool CProtocol::EvaluateCLReqServerListMes ( const CHostAddress& InetAddr ) +bool CProtocol::EvaluateCLReqServerListMes ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ) { // invoke message action - emit CLReqServerList ( InetAddr ); + emit CLReqServerList ( InetAddr, pTcpConnection ); return false; // no error } @@ -2363,7 +2369,7 @@ bool CProtocol::EvaluateCLReqVersionAndOSMes ( const CHostAddress& InetAddr ) return false; // no error } -void CProtocol::CreateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector& vecChanInfo ) +void CProtocol::CreateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector& vecChanInfo, CTcpConnection* pTcpConnection ) { const int iNumClients = vecChanInfo.Size(); @@ -2411,7 +2417,7 @@ void CProtocol::CreateCLConnClientsListMes ( const CHostAddress& InetAddr, const PutStringUTF8OnStream ( vecData, iPos, strUTF8City ); } - CreateAndImmSendConLessMessage ( PROTMESSID_CLM_CONN_CLIENTS_LIST, vecData, InetAddr ); + CreateAndImmSendConLessMessage ( PROTMESSID_CLM_CONN_CLIENTS_LIST, vecData, InetAddr, pTcpConnection ); } bool CProtocol::EvaluateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector& vecData ) @@ -2478,10 +2484,10 @@ void CProtocol::CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr ) CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST, CVector ( 0 ), InetAddr ); } -bool CProtocol::EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr ) +bool CProtocol::EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ) { // invoke message action - emit CLReqConnClientsList ( InetAddr ); + emit CLReqConnClientsList ( InetAddr, pTcpConnection ); return false; // no error } diff --git a/src/protocol.h b/src/protocol.h index bee41da93c..8c52f0787e 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -31,6 +31,7 @@ #include #include "global.h" #include "util.h" +#include "tcpserver.h" /* Definitions ****************************************************************/ // protocol message IDs @@ -141,7 +142,7 @@ class CProtocol : public QObject void CreateCLRegisterServerMes ( const CHostAddress& InetAddr, const CHostAddress& LInetAddr, const CServerCoreInfo& ServerInfo ); void CreateCLRegisterServerExMes ( const CHostAddress& InetAddr, const CHostAddress& LInetAddr, const CServerCoreInfo& ServerInfo ); void CreateCLUnregisterServerMes ( const CHostAddress& InetAddr ); - void CreateCLServerListMes ( const CHostAddress& InetAddr, const CVector vecServerInfo ); + void CreateCLServerListMes ( const CHostAddress& InetAddr, const CVector vecServerInfo, CTcpConnection* pTcpConnection ); void CreateCLRedServerListMes ( const CHostAddress& InetAddr, const CVector vecServerInfo ); void CreateCLReqServerListMes ( const CHostAddress& InetAddr ); void CreateCLSendEmptyMesMes ( const CHostAddress& InetAddr, const CHostAddress& TargetInetAddr ); @@ -149,7 +150,7 @@ class CProtocol : public QObject void CreateCLDisconnection ( const CHostAddress& InetAddr ); void CreateCLVersionAndOSMes ( const CHostAddress& InetAddr ); void CreateCLReqVersionAndOSMes ( const CHostAddress& InetAddr ); - void CreateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector& vecChanInfo ); + void CreateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector& vecChanInfo, CTcpConnection* pTcpConnection ); void CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr ); void CreateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector& vecLevelList, const int iNumClients ); void CreateCLRegisterServerResp ( const CHostAddress& InetAddr, const ESvrRegResult eResult ); @@ -164,7 +165,10 @@ class CProtocol : public QObject void ParseMessageBody ( const CVector& vecbyMesBodyData, const int iRecCounter, const int iRecID ); - void ParseConnectionLessMessageBody ( const CVector& vecbyMesBodyData, const int iRecID, const CHostAddress& InetAddr ); + void ParseConnectionLessMessageBody ( const CVector& vecbyMesBodyData, + const int iRecID, + const CHostAddress& InetAddr, + CTcpConnection* pTcpConnection ); static bool IsConnectionLessMessageID ( const int iID ) { return ( iID >= 1000 ) && ( iID < 2000 ); } @@ -243,7 +247,10 @@ class CProtocol : public QObject void CreateAndSendMessage ( const int iID, const CVector& vecData ); - void CreateAndImmSendConLessMessage ( const int iID, const CVector& vecData, const CHostAddress& InetAddr ); + void CreateAndImmSendConLessMessage ( const int iID, + const CVector& vecData, + const CHostAddress& InetAddr, + CTcpConnection* pTcpConnection = nullptr ); bool EvaluateJitBufMes ( const CVector& vecData ); bool EvaluateReqJitBufMes(); @@ -272,13 +279,13 @@ class CProtocol : public QObject bool EvaluateCLUnregisterServerMes ( const CHostAddress& InetAddr ); bool EvaluateCLServerListMes ( const CHostAddress& InetAddr, const CVector& vecData ); bool EvaluateCLRedServerListMes ( const CHostAddress& InetAddr, const CVector& vecData ); - bool EvaluateCLReqServerListMes ( const CHostAddress& InetAddr ); + bool EvaluateCLReqServerListMes ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ); bool EvaluateCLSendEmptyMesMes ( const CVector& vecData ); bool EvaluateCLDisconnectionMes ( const CHostAddress& InetAddr ); bool EvaluateCLVersionAndOSMes ( const CHostAddress& InetAddr, const CVector& vecData ); bool EvaluateCLReqVersionAndOSMes ( const CHostAddress& InetAddr ); bool EvaluateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector& vecData ); - bool EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr ); + bool EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ); bool EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector& vecData ); bool EvaluateCLRegisterServerResp ( const CHostAddress& InetAddr, const CVector& vecData ); @@ -303,7 +310,7 @@ public slots: signals: // transmitting void MessReadyForSending ( CVector vecMessage ); - void CLMessReadyForSending ( CHostAddress InetAddr, CVector vecMessage ); + void CLMessReadyForSending ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ); // receiving void ChangeJittBufSize ( int iNewJitBufSize ); @@ -338,13 +345,13 @@ public slots: void CLUnregisterServerReceived ( CHostAddress InetAddr ); void CLServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo ); void CLRedServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo ); - void CLReqServerList ( CHostAddress InetAddr ); + void CLReqServerList ( CHostAddress InetAddr, CTcpConnection* pTcpConnection ); void CLSendEmptyMes ( CHostAddress TargetInetAddr ); void CLDisconnection ( CHostAddress InetAddr ); void CLVersionAndOSReceived ( CHostAddress InetAddr, COSUtil::EOpSystemType eOSType, QString strVersion ); void CLReqVersionAndOS ( CHostAddress InetAddr ); void CLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo ); - void CLReqConnClientsList ( CHostAddress InetAddr ); + void CLReqConnClientsList ( CHostAddress InetAddr, CTcpConnection* pTcpConnection ); void CLChannelLevelListReceived ( CHostAddress InetAddr, CVector vecLevelList ); void CLRegisterServerResp ( CHostAddress InetAddr, ESvrRegResult eStatus ); }; diff --git a/src/server.cpp b/src/server.cpp index b985bc2cd3..80c41dee41 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -468,11 +468,19 @@ void CServer::OnServerFull ( CHostAddress RecHostAddr ) ConnLessProtocol.CreateCLServerFullMes ( RecHostAddr ); } -void CServer::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage ) +void CServer::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ) { // the protocol queries me to call the function to send the message // send it through the network - Socket.SendPacket ( vecMessage, InetAddr ); + if ( pTcpConnection ) + { + // send to the connected socket directly + pTcpConnection->pTcpSocket->write ( (const char*) &( (CVector) vecMessage )[0], vecMessage.Size() ); + } + else + { + Socket.SendPacket ( vecMessage, InetAddr ); + } } void CServer::OnCLDisconnection ( CHostAddress InetAddr ) @@ -1429,12 +1437,12 @@ void CServer::DumpChannels ( const QString& title ) } } -void CServer::OnProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr ) +void CServer::OnProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr, CTcpConnection* pTcpConnection ) { QMutexLocker locker ( &Mutex ); // connection less messages are always processed - ConnLessProtocol.ParseConnectionLessMessageBody ( vecbyMesBodyData, iRecID, RecHostAddr ); + ConnLessProtocol.ParseConnectionLessMessageBody ( vecbyMesBodyData, iRecID, RecHostAddr, pTcpConnection ); } void CServer::OnProtocolMessageReceived ( int iRecCounter, int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr ) diff --git a/src/server.h b/src/server.h index 791927b2ee..b60355b473 100644 --- a/src/server.h +++ b/src/server.h @@ -340,9 +340,9 @@ public slots: void OnServerFull ( CHostAddress RecHostAddr ); - void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage ); + void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ); - void OnProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr ); + void OnProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr, CTcpConnection* pTcpConnection ); void OnProtocolMessageReceived ( int iRecCounter, int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr ); @@ -362,11 +362,14 @@ public slots: } } - void OnCLReqServerList ( CHostAddress InetAddr ) { ServerListManager.RetrieveAll ( InetAddr ); } + void OnCLReqServerList ( CHostAddress InetAddr, CTcpConnection* pTcpConnection ) { ServerListManager.RetrieveAll ( InetAddr, pTcpConnection ); } void OnCLReqVersionAndOS ( CHostAddress InetAddr ) { ConnLessProtocol.CreateCLVersionAndOSMes ( InetAddr ); } - void OnCLReqConnClientsList ( CHostAddress InetAddr ) { ConnLessProtocol.CreateCLConnClientsListMes ( InetAddr, CreateChannelList() ); } + void OnCLReqConnClientsList ( CHostAddress InetAddr, CTcpConnection* pTcpConnection ) + { + ConnLessProtocol.CreateCLConnClientsListMes ( InetAddr, CreateChannelList(), pTcpConnection ); + } void OnCLRegisterServerReceived ( CHostAddress InetAddr, CHostAddress LInetAddr, CServerCoreInfo ServerInfo ) { diff --git a/src/serverlist.cpp b/src/serverlist.cpp index 4dabe4c7ef..582513045c 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -663,7 +663,7 @@ void CServerListManager::Remove ( const CHostAddress& InetAddr ) and allow the client connect dialogue instead to use the IP and Port from which the list was received. */ -void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr ) +void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ) { QMutexLocker locker ( &Mutex ); @@ -722,8 +722,12 @@ void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr ) // send the server list to the client, since we do not know that the client // has a UDP fragmentation issue, we send both lists, the reduced and the // normal list after each other - pConnLessProtocol->CreateCLRedServerListMes ( InetAddr, vecServerInfo ); - pConnLessProtocol->CreateCLServerListMes ( InetAddr, vecServerInfo ); + if ( !pTcpConnection ) + { + // no need for reduced list if on TCP + pConnLessProtocol->CreateCLRedServerListMes ( InetAddr, vecServerInfo ); + } + pConnLessProtocol->CreateCLServerListMes ( InetAddr, vecServerInfo, pTcpConnection ); } } diff --git a/src/serverlist.h b/src/serverlist.h index cdf1d0f7e6..8edb843123 100644 --- a/src/serverlist.h +++ b/src/serverlist.h @@ -168,7 +168,7 @@ class CServerListManager : public QObject void Append ( const CHostAddress& InetAddr, const CHostAddress& LInetAddr, const CServerCoreInfo& ServerInfo, const QString strVersion = "" ); void Remove ( const CHostAddress& InetAddr ); - void RetrieveAll ( const CHostAddress& InetAddr ); + void RetrieveAll ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ); void StoreRegistrationResult ( ESvrRegResult eStatus ); diff --git a/src/socket.h b/src/socket.h index 77fdf24452..a8919fcc01 100644 --- a/src/socket.h +++ b/src/socket.h @@ -31,6 +31,7 @@ #include "global.h" #include "protocol.h" #include "util.h" +#include "tcpserver.h" #ifndef _WIN32 # include # include @@ -103,7 +104,7 @@ class CSocket : public QObject void ProtocolMessageReceived ( int iRecCounter, int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr ); - void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr ); + void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, CTcpConnection* pTcpConnection = nullptr ); }; /* Socket which runs in a separate high priority thread --------------------- */ diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp index a165abb942..2a461b129d 100644 --- a/src/tcpserver.cpp +++ b/src/tcpserver.cpp @@ -24,6 +24,7 @@ #include "tcpserver.h" +#include "protocol.h" #include "server.h" #include "channel.h" @@ -34,7 +35,7 @@ CTcpServer::CTcpServer ( CServer* pNServP, const QString& strServerBindIP, int i bEnableIPv6 ( bEnableIPv6 ), pTcpServer ( new QTcpServer ( this ) ) { - //// connect ( this, &CTcpServer::ProtocolCLMessageReceived, pServer, &CServer::OnProtocolCLMessageReceived ); + connect ( this, &CTcpServer::ProtocolCLMessageReceived, pServer, &CServer::OnProtocolCLMessageReceived ); connect ( pTcpServer, &QTcpServer::newConnection, this, &CTcpServer::OnNewConnection ); } @@ -157,14 +158,14 @@ void CTcpServer::OnNewConnection() { //### TODO: BEGIN ###// // a copy of the vector is used -> avoid malloc in real-time routine - //// emit ProtocolCLMessageReceived ( iRecID, vecbyMesBodyData, peerAddress, pSocket ); + emit ProtocolCLMessageReceived ( iRecID, vecbyMesBodyData, pTcpConnection->tcpAddress, pTcpConnection ); //### TODO: END ###// } else { //### TODO: BEGIN ###// // a copy of the vector is used -> avoid malloc in real-time routine - // emit ProtocolMessageReceived ( iRecCounter, iRecID, vecbyMesBodyData, peerAddress, pSocket ); + // emit ProtocolMessageReceived ( iRecCounter, iRecID, vecbyMesBodyData, pTcpConnection->tcpAddress, pTcpConnection ); //### TODO: END ###// } } diff --git a/src/tcpserver.h b/src/tcpserver.h index 2d57eb7a8a..d052f6e2b6 100644 --- a/src/tcpserver.h +++ b/src/tcpserver.h @@ -32,14 +32,14 @@ #include #include "global.h" -#include "protocol.h" #include "util.h" // The header files channel.h and server.h require to include this header file // so we get a cyclic dependency. To solve this issue, a prototype of the // channel class and server class is defined here. -class CServer; // forward declaration of CServer -class CChannel; // forward declaration of CChannel +class CServer; // forward declaration of CServer +class CChannel; // forward declaration of CChannel +class CTcpConnection; // forward declaration of CTcpConnection /* Classes ********************************************************************/ class CTcpServer : public QObject @@ -60,7 +60,7 @@ class CTcpServer : public QObject QTcpServer* pTcpServer; signals: - void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, QTcpSocket* pTcpSocket ); + void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, CTcpConnection* pTcpConnection ); protected slots: void OnNewConnection(); diff --git a/src/testbench.h b/src/testbench.h index 3e5568ff9e..704b785d93 100644 --- a/src/testbench.h +++ b/src/testbench.h @@ -218,7 +218,7 @@ public slots: vecServerInfo[0].strCity = GenRandomString(); vecServerInfo[0].strName = GenRandomString(); - Protocol.CreateCLServerListMes ( CurHostAddress, vecServerInfo ); + Protocol.CreateCLServerListMes ( CurHostAddress, vecServerInfo, nullptr ); break; case 20: // PROTMESSID_CLM_REQ_SERVER_LIST @@ -261,7 +261,7 @@ public slots: vecChanInfo[0].iChanID = GenRandomIntInRange ( -2, 20 ); vecChanInfo[0].strName = GenRandomString(); - Protocol.CreateCLConnClientsListMes ( CurHostAddress, vecChanInfo ); + Protocol.CreateCLConnClientsListMes ( CurHostAddress, vecChanInfo, nullptr ); break; case 29: // PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST From 174eb504efd645328147649aab679a0eba3b246e Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Tue, 21 Jan 2025 17:52:46 +0000 Subject: [PATCH 04/17] Create CLM_TCP_SUPPORTED and related methods --- src/protocol.cpp | 23 +++++++++++++++++++++++ src/protocol.h | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/src/protocol.cpp b/src/protocol.cpp index c127497062..eaac676830 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -432,6 +432,12 @@ CONNECTION LESS MESSAGES five times for one registration request at 500ms intervals. Beyond this, it should "ping" every 15 minutes (standard re-registration timeout). + + +- PROTMESSID_CLM_TCP_SUPPORTED: TCP supported message + + note: does not have any data -> n = 0 + */ #include "protocol.h" @@ -922,6 +928,10 @@ void CProtocol::ParseConnectionLessMessageBody ( const CVector& vecbyMe case PROTMESSID_CLM_REGISTER_SERVER_RESP: EvaluateCLRegisterServerResp ( InetAddr, vecbyMesBodyData ); break; + + case PROTMESSID_CLM_TCP_SUPPORTED: + EvaluateCLTcpSupportedMes ( InetAddr ); + break; } } @@ -2585,6 +2595,19 @@ bool CProtocol::EvaluateCLRegisterServerResp ( const CHostAddress& InetAddr, con return false; // no error } +void CProtocol::CreateCLTcpSupportedMes ( const CHostAddress& InetAddr ) +{ + CreateAndImmSendConLessMessage ( PROTMESSID_CLM_TCP_SUPPORTED, CVector ( 0 ), InetAddr ); +} + +bool CProtocol::EvaluateCLTcpSupportedMes ( const CHostAddress& InetAddr ) +{ + // invoke message action + emit CLTcpSupported ( InetAddr ); + + return false; // no error +} + /******************************************************************************\ * Message generation and parsing * \******************************************************************************/ diff --git a/src/protocol.h b/src/protocol.h index 8c52f0787e..9865f19589 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -84,6 +84,7 @@ #define PROTMESSID_CLM_REGISTER_SERVER_RESP 1016 // status of server registration request #define PROTMESSID_CLM_REGISTER_SERVER_EX 1017 // register server with extended information #define PROTMESSID_CLM_RED_SERVER_LIST 1018 // reduced server list +#define PROTMESSID_CLM_TCP_SUPPORTED 1019 // TCP is supported // special IDs #define PROTMESSID_SPECIAL_SPLIT_MESSAGE 2001 // a container for split messages @@ -154,6 +155,7 @@ class CProtocol : public QObject void CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr ); void CreateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector& vecLevelList, const int iNumClients ); void CreateCLRegisterServerResp ( const CHostAddress& InetAddr, const ESvrRegResult eResult ); + void CreateCLTcpSupportedMes ( const CHostAddress& InetAddr ); static int GetBodyLength ( const CVector& vecbyData ); @@ -288,6 +290,7 @@ class CProtocol : public QObject bool EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ); bool EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector& vecData ); bool EvaluateCLRegisterServerResp ( const CHostAddress& InetAddr, const CVector& vecData ); + bool EvaluateCLTcpSupportedMes ( const CHostAddress& InetAddr ); int iOldRecID; int iOldRecCnt; @@ -354,4 +357,5 @@ public slots: void CLReqConnClientsList ( CHostAddress InetAddr, CTcpConnection* pTcpConnection ); void CLChannelLevelListReceived ( CHostAddress InetAddr, CVector vecLevelList ); void CLRegisterServerResp ( CHostAddress InetAddr, ESvrRegResult eStatus ); + void CLTcpSupported ( CHostAddress InetAddr ); }; From 0ae51e238f07d36700807408aaa7754d1c6a9d56 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Mon, 9 Mar 2026 16:00:33 +0000 Subject: [PATCH 05/17] Add CLM_TCP_SUPPORTED message generation when TCP enabled --- src/server.cpp | 7 +++++++ src/server.h | 6 ++++++ src/serverlist.cpp | 12 +++++++++++- src/serverlist.h | 2 ++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/server.cpp b/src/server.cpp index 80c41dee41..39b3000687 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -65,6 +65,7 @@ CServer::CServer ( const int iNewMaxNumChan, strServerListFilter, iNewMaxNumChan, bNEnableIPv6, + bNEnableTcp, &ConnLessProtocol ), JamController ( this ), bDisableRecording ( bDisableRecording ), @@ -386,6 +387,12 @@ void CServer::OnNewConnection ( int iChID, int iTotChans, CHostAddress RecHostAd { QMutexLocker locker ( &Mutex ); + // if TCP is enabled, we need to announce this first, before sending Client ID + if ( bEnableTcp ) + { + ConnLessProtocol.CreateCLTcpSupportedMes ( vecChannels[iChID].GetAddress() ); + } + // inform the client about its own ID at the server (note that this // must be the first message to be sent for a new connection) vecChannels[iChID].CreateClientIDMes ( iChID ); diff --git a/src/server.h b/src/server.h index b60355b473..9c86ad289b 100644 --- a/src/server.h +++ b/src/server.h @@ -369,6 +369,12 @@ public slots: void OnCLReqConnClientsList ( CHostAddress InetAddr, CTcpConnection* pTcpConnection ) { ConnLessProtocol.CreateCLConnClientsListMes ( InetAddr, CreateChannelList(), pTcpConnection ); + + // if TCP is enabled but this request is on UDP, say TCP is supported + if ( bEnableTcp && !pTcpConnection ) + { + ConnLessProtocol.CreateCLTcpSupportedMes ( InetAddr ); + } } void OnCLRegisterServerReceived ( CHostAddress InetAddr, CHostAddress LInetAddr, CServerCoreInfo ServerInfo ) diff --git a/src/serverlist.cpp b/src/serverlist.cpp index 582513045c..5d07498a61 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -128,9 +128,11 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum, const QString& strServerPublicIP, const int iNumChannels, const bool bNEnableIPv6, + const bool bNEnableTcp, CProtocol* pNConLProt ) : DirectoryType ( AT_NONE ), bEnableIPv6 ( bNEnableIPv6 ), + bEnableTcp ( bNEnableTcp ), ServerListFileName ( strServerListFileName ), strDirectoryAddress ( "" ), bIsDirectory ( false ), @@ -709,7 +711,9 @@ void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr, CTcpConnect } // do not send a "ping" to a server local to the directory (no need) - if ( !serverIsInternal ) + // also only do so if processing a request over UDP, not TCP, + // as the client will always try UDP before TCP. + if ( !serverIsInternal && !pTcpConnection ) { // create "send empty message" for all other registered servers // this causes the server (vecServerInfo[iIdx].HostAddr) @@ -728,6 +732,12 @@ void CServerListManager::RetrieveAll ( const CHostAddress& InetAddr, CTcpConnect pConnLessProtocol->CreateCLRedServerListMes ( InetAddr, vecServerInfo ); } pConnLessProtocol->CreateCLServerListMes ( InetAddr, vecServerInfo, pTcpConnection ); + + // if TCP is enabled but this request is on UDP, say TCP is supported + if ( bEnableTcp && !pTcpConnection ) + { + pConnLessProtocol->CreateCLTcpSupportedMes ( InetAddr ); + } } } diff --git a/src/serverlist.h b/src/serverlist.h index 8edb843123..fe7012a461 100644 --- a/src/serverlist.h +++ b/src/serverlist.h @@ -141,6 +141,7 @@ class CServerListManager : public QObject const QString& strServerPublicIP, const int iNumChannels, const bool bNEnableIPv6, + const bool bNEnableTcp, CProtocol* pNConLProt ); void SetServerName ( const QString& strNewName ); @@ -192,6 +193,7 @@ class CServerListManager : public QObject EDirectoryType DirectoryType; bool bEnableIPv6; + bool bEnableTcp; CHostAddress ServerPublicIP; CHostAddress ServerPublicIP6; From a8baca9f2a413d8c7980446cf24b272b8c7e3ff1 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Mon, 16 Mar 2026 11:28:54 +0000 Subject: [PATCH 06/17] Add flag to request TCP client use --- src/client.h | 10 ++++++++-- src/clientdlg.h | 7 +++++-- src/clientrpc.cpp | 2 +- src/connectdlg.cpp | 6 +++--- src/connectdlg.h | 4 ++-- src/protocol.cpp | 11 ++++++----- src/protocol.h | 7 ++++--- src/testbench.h | 4 ++-- 8 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/client.h b/src/client.h index 6f021e3125..1e8857d0ec 100644 --- a/src/client.h +++ b/src/client.h @@ -278,9 +278,15 @@ class CClient : public QObject void CreateCLServerListReqVerAndOSMes ( const CHostAddress& InetAddr ) { ConnLessProtocol.CreateCLReqVersionAndOSMes ( InetAddr ); } - void CreateCLServerListReqConnClientsListMes ( const CHostAddress& InetAddr ) { ConnLessProtocol.CreateCLReqConnClientsListMes ( InetAddr ); } + void CreateCLServerListReqConnClientsListMes ( const CHostAddress& InetAddr, bool bUseTcpClient ) + { + ConnLessProtocol.CreateCLReqConnClientsListMes ( InetAddr, bUseTcpClient ); + } - void CreateCLReqServerListMes ( const CHostAddress& InetAddr ) { ConnLessProtocol.CreateCLReqServerListMes ( InetAddr ); } + void CreateCLReqServerListMes ( const CHostAddress& InetAddr, bool bUseTcpClient ) + { + ConnLessProtocol.CreateCLReqServerListMes ( InetAddr, bUseTcpClient ); + } int EstimatedOverallDelay ( const int iPingTimeMs ); diff --git a/src/clientdlg.h b/src/clientdlg.h index a5d327676a..9abb70f974 100644 --- a/src/clientdlg.h +++ b/src/clientdlg.h @@ -202,13 +202,16 @@ public slots: void OnNewLocalInputText ( QString strChatText ) { pClient->CreateChatTextMes ( strChatText ); } - void OnReqServerListQuery ( CHostAddress InetAddr ) { pClient->CreateCLReqServerListMes ( InetAddr ); } + void OnReqServerListQuery ( CHostAddress InetAddr, bool bUseTcpClient ) { pClient->CreateCLReqServerListMes ( InetAddr, bUseTcpClient ); } void OnCreateCLServerListPingMes ( CHostAddress InetAddr ) { pClient->CreateCLServerListPingMes ( InetAddr ); } void OnCreateCLServerListReqVerAndOSMes ( CHostAddress InetAddr ) { pClient->CreateCLServerListReqVerAndOSMes ( InetAddr ); } - void OnCreateCLServerListReqConnClientsListMes ( CHostAddress InetAddr ) { pClient->CreateCLServerListReqConnClientsListMes ( InetAddr ); } + void OnCreateCLServerListReqConnClientsListMes ( CHostAddress InetAddr, bool bUseTcpClient ) + { + pClient->CreateCLServerListReqConnClientsListMes ( InetAddr, bUseTcpClient ); + } void OnCLServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo ) { diff --git a/src/clientrpc.cpp b/src/clientrpc.cpp index c2efc59b25..367f2e3669 100644 --- a/src/clientrpc.cpp +++ b/src/clientrpc.cpp @@ -171,7 +171,7 @@ CClientRpc::CClientRpc ( CClient* pClient, CClientSettings* pSettings, CRpcServe if ( NetworkUtil::ParseNetworkAddress ( jsonDirectoryIp.toString(), haDirectoryAddress, false ) ) { // send the request for the server list - pClient->CreateCLReqServerListMes ( haDirectoryAddress ); + pClient->CreateCLReqServerListMes ( haDirectoryAddress, false ); // UDP response["result"] = "ok"; } else diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp index 5c16bbc3db..d61ebc04e4 100644 --- a/src/connectdlg.cpp +++ b/src/connectdlg.cpp @@ -336,7 +336,7 @@ void CConnectDlg::RequestServerList() false ) ) { // send the request for the server list - emit ReqServerListQuery ( haDirectoryAddress ); + emit ReqServerListQuery ( haDirectoryAddress, false ); // UDP // start timer, if this message did not get any respond to retransmit // the server list request message @@ -379,7 +379,7 @@ void CConnectDlg::OnTimerReRequestServList() { // note that this is a connection less message which may get lost // and therefore it makes sense to re-transmit it - emit ReqServerListQuery ( haDirectoryAddress ); + emit ReqServerListQuery ( haDirectoryAddress, false ); // UDP } } @@ -981,7 +981,7 @@ void CConnectDlg::SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr, // connected clients, if not then request the client names if ( iNumClients != pCurListViewItem->childCount() ) { - emit CreateCLServerListReqConnClientsListMes ( InetAddr ); + emit CreateCLServerListReqConnClientsListMes ( InetAddr, false ); // UDP } // this is the first time a ping time was received, set item to visible diff --git a/src/connectdlg.h b/src/connectdlg.h index 435169edf7..ff880c389d 100644 --- a/src/connectdlg.h +++ b/src/connectdlg.h @@ -135,8 +135,8 @@ public slots: void OnCurrentServerItemChanged ( QTreeWidgetItem* current, QTreeWidgetItem* previous ); signals: - void ReqServerListQuery ( CHostAddress InetAddr ); + void ReqServerListQuery ( CHostAddress InetAddr, bool bUseTcpClient ); void CreateCLServerListPingMes ( CHostAddress InetAddr ); void CreateCLServerListReqVerAndOSMes ( CHostAddress InetAddr ); - void CreateCLServerListReqConnClientsListMes ( CHostAddress InetAddr ); + void CreateCLServerListReqConnClientsListMes ( CHostAddress InetAddr, bool bUseTcpClient ); }; diff --git a/src/protocol.cpp b/src/protocol.cpp index eaac676830..6c37968ae9 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -614,7 +614,8 @@ void CProtocol::CreateAndImmSendAcknMess ( const int& iID, const int& iCnt ) void CProtocol::CreateAndImmSendConLessMessage ( const int iID, const CVector& vecData, const CHostAddress& InetAddr, - CTcpConnection* pTcpConnection ) + CTcpConnection* pTcpConnection, + bool bUseTcpClient ) { CVector vecNewMessage; @@ -2236,9 +2237,9 @@ bool CProtocol::EvaluateCLRedServerListMes ( const CHostAddress& InetAddr, const return false; // no error } -void CProtocol::CreateCLReqServerListMes ( const CHostAddress& InetAddr ) +void CProtocol::CreateCLReqServerListMes ( const CHostAddress& InetAddr, bool bUseTcpClient ) { - CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_SERVER_LIST, CVector ( 0 ), InetAddr ); + CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_SERVER_LIST, CVector ( 0 ), InetAddr, nullptr, bUseTcpClient ); } bool CProtocol::EvaluateCLReqServerListMes ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ) @@ -2489,9 +2490,9 @@ bool CProtocol::EvaluateCLConnClientsListMes ( const CHostAddress& InetAddr, con return false; // no error } -void CProtocol::CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr ) +void CProtocol::CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr, bool bUseTcpClient ) { - CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST, CVector ( 0 ), InetAddr ); + CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST, CVector ( 0 ), InetAddr, nullptr, bUseTcpClient ); } bool CProtocol::EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr, CTcpConnection* pTcpConnection ) diff --git a/src/protocol.h b/src/protocol.h index 9865f19589..7411a35af0 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -145,14 +145,14 @@ class CProtocol : public QObject void CreateCLUnregisterServerMes ( const CHostAddress& InetAddr ); void CreateCLServerListMes ( const CHostAddress& InetAddr, const CVector vecServerInfo, CTcpConnection* pTcpConnection ); void CreateCLRedServerListMes ( const CHostAddress& InetAddr, const CVector vecServerInfo ); - void CreateCLReqServerListMes ( const CHostAddress& InetAddr ); + void CreateCLReqServerListMes ( const CHostAddress& InetAddr, bool bUseTcpClient ); void CreateCLSendEmptyMesMes ( const CHostAddress& InetAddr, const CHostAddress& TargetInetAddr ); void CreateCLEmptyMes ( const CHostAddress& InetAddr ); void CreateCLDisconnection ( const CHostAddress& InetAddr ); void CreateCLVersionAndOSMes ( const CHostAddress& InetAddr ); void CreateCLReqVersionAndOSMes ( const CHostAddress& InetAddr ); void CreateCLConnClientsListMes ( const CHostAddress& InetAddr, const CVector& vecChanInfo, CTcpConnection* pTcpConnection ); - void CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr ); + void CreateCLReqConnClientsListMes ( const CHostAddress& InetAddr, bool bUseTcpClient ); void CreateCLChannelLevelListMes ( const CHostAddress& InetAddr, const CVector& vecLevelList, const int iNumClients ); void CreateCLRegisterServerResp ( const CHostAddress& InetAddr, const ESvrRegResult eResult ); void CreateCLTcpSupportedMes ( const CHostAddress& InetAddr ); @@ -252,7 +252,8 @@ class CProtocol : public QObject void CreateAndImmSendConLessMessage ( const int iID, const CVector& vecData, const CHostAddress& InetAddr, - CTcpConnection* pTcpConnection = nullptr ); + CTcpConnection* pTcpConnection = nullptr, + bool bUseTcpClient = false ); bool EvaluateJitBufMes ( const CVector& vecData ); bool EvaluateReqJitBufMes(); diff --git a/src/testbench.h b/src/testbench.h index 704b785d93..6191a8659e 100644 --- a/src/testbench.h +++ b/src/testbench.h @@ -222,7 +222,7 @@ public slots: break; case 20: // PROTMESSID_CLM_REQ_SERVER_LIST - Protocol.CreateCLReqServerListMes ( CurHostAddress ); + Protocol.CreateCLReqServerListMes ( CurHostAddress, false ); break; case 21: // PROTMESSID_CLM_SEND_EMPTY_MESSAGE @@ -265,7 +265,7 @@ public slots: break; case 29: // PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST - Protocol.CreateCLReqConnClientsListMes ( CurHostAddress ); + Protocol.CreateCLReqConnClientsListMes ( CurHostAddress, false ); break; case 30: // PROTMESSID_CLM_CHANNEL_LEVEL_LIST From 0e0eeacb8fb83e67fa33bf6740775bcd9a58d855 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Mon, 16 Mar 2026 14:22:38 +0000 Subject: [PATCH 07/17] Add handlers for TCP Supported message --- src/client.cpp | 2 ++ src/client.h | 2 ++ src/clientdlg.cpp | 2 ++ src/clientdlg.h | 5 +++++ src/connectdlg.cpp | 5 +++++ src/connectdlg.h | 2 ++ 6 files changed, 18 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index 4b836cbd4a..2f87ff029d 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -145,6 +145,8 @@ CClient::CClient ( const quint16 iPortNumber, QObject::connect ( &ConnLessProtocol, &CProtocol::CLRedServerListReceived, this, &CClient::CLRedServerListReceived ); + QObject::connect ( &ConnLessProtocol, &CProtocol::CLTcpSupported, this, &CClient::CLTcpSupported ); + QObject::connect ( &ConnLessProtocol, &CProtocol::CLConnClientsListMesReceived, this, &CClient::CLConnClientsListMesReceived ); QObject::connect ( &ConnLessProtocol, &CProtocol::CLPingReceived, this, &CClient::OnCLPingReceived ); diff --git a/src/client.h b/src/client.h index 1e8857d0ec..e7fa66674e 100644 --- a/src/client.h +++ b/src/client.h @@ -477,6 +477,8 @@ protected slots: void CLRedServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo ); + void CLTcpSupported ( CHostAddress InetAddr ); + void CLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo ); void CLPingTimeWithNumClientsReceived ( CHostAddress InetAddr, int iPingTime, int iNumClients ); diff --git a/src/clientdlg.cpp b/src/clientdlg.cpp index 6063547896..9e90ce1bcb 100644 --- a/src/clientdlg.cpp +++ b/src/clientdlg.cpp @@ -509,6 +509,8 @@ CClientDlg::CClientDlg ( CClient* pNCliP, QObject::connect ( pClient, &CClient::CLRedServerListReceived, this, &CClientDlg::OnCLRedServerListReceived ); + QObject::connect ( pClient, &CClient::CLTcpSupported, this, &CClientDlg::OnCLTcpSupported ); + QObject::connect ( pClient, &CClient::CLConnClientsListMesReceived, this, &CClientDlg::OnCLConnClientsListMesReceived ); QObject::connect ( pClient, &CClient::CLPingTimeWithNumClientsReceived, this, &CClientDlg::OnCLPingTimeWithNumClientsReceived ); diff --git a/src/clientdlg.h b/src/clientdlg.h index 9abb70f974..b5071fa54a 100644 --- a/src/clientdlg.h +++ b/src/clientdlg.h @@ -223,6 +223,11 @@ public slots: ConnectDlg.SetServerList ( InetAddr, vecServerInfo, true ); } + void OnCLTcpSupported ( CHostAddress InetAddr ) + { + ConnectDlg.SetTcpSupported ( InetAddr ); + } + void OnCLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo ) { ConnectDlg.SetConnClientsList ( InetAddr, vecChanInfo ); diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp index d61ebc04e4..fabc6a943b 100644 --- a/src/connectdlg.cpp +++ b/src/connectdlg.cpp @@ -544,6 +544,11 @@ void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector& vecChanInfo ) { // find the server with the correct address diff --git a/src/connectdlg.h b/src/connectdlg.h index ff880c389d..5f34428b08 100644 --- a/src/connectdlg.h +++ b/src/connectdlg.h @@ -69,6 +69,8 @@ class CConnectDlg : public CBaseDlg, private Ui_CConnectDlgBase void SetServerList ( const CHostAddress& InetAddr, const CVector& vecServerInfo, const bool bIsReducedServerList = false ); + void SetTcpSupported ( const CHostAddress& InetAddr ); + void SetConnClientsList ( const CHostAddress& InetAddr, const CVector& vecChanInfo ); void SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr, const int iPingTime, const int iNumClients ); From 900f32330117cfe51b604ce07b0215dc0918e6d2 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Mon, 16 Mar 2026 15:02:49 +0000 Subject: [PATCH 08/17] Propagate TCP client flag down to OnSendCLProtMessage --- src/client.cpp | 13 +++++++++---- src/client.h | 2 +- src/clientdlg.h | 5 +---- src/connectdlg.cpp | 5 +---- src/protocol.cpp | 2 +- src/protocol.h | 2 +- src/server.cpp | 8 +++++++- src/server.h | 2 +- 8 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 2f87ff029d..4e3c7dd450 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -251,14 +251,19 @@ void CClient::OnSendProtMessage ( CVector vecMessage ) Socket.SendPacket ( vecMessage, Channel.GetAddress() ); } -void CClient::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ) +void CClient::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection, bool bUseTcpClient ) { + if ( pTcpConnection ) + { + qWarning() << "Client send cannot use TCP server"; + return; + } + // the protocol queries me to call the function to send the message // send it through the network - if ( pTcpConnection ) + if ( bUseTcpClient ) { - // send to the connected socket directly - pTcpConnection->pTcpSocket->write ( (const char*) &( (CVector) vecMessage )[0], vecMessage.Size() ); + // create a TCP client connection and send message } else { diff --git a/src/client.h b/src/client.h index e7fa66674e..eac46c5518 100644 --- a/src/client.h +++ b/src/client.h @@ -448,7 +448,7 @@ protected slots: } void OnCLPingReceived ( CHostAddress InetAddr, int iMs ); - void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ); + void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection, bool bUseTcpClient ); void OnCLPingWithNumClientsReceived ( CHostAddress InetAddr, int iMs, int iNumClients ); diff --git a/src/clientdlg.h b/src/clientdlg.h index b5071fa54a..b36e297593 100644 --- a/src/clientdlg.h +++ b/src/clientdlg.h @@ -223,10 +223,7 @@ public slots: ConnectDlg.SetServerList ( InetAddr, vecServerInfo, true ); } - void OnCLTcpSupported ( CHostAddress InetAddr ) - { - ConnectDlg.SetTcpSupported ( InetAddr ); - } + void OnCLTcpSupported ( CHostAddress InetAddr ) { ConnectDlg.SetTcpSupported ( InetAddr ); } void OnCLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo ) { diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp index fabc6a943b..354e3982d2 100644 --- a/src/connectdlg.cpp +++ b/src/connectdlg.cpp @@ -544,10 +544,7 @@ void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector& vecChanInfo ) { diff --git a/src/protocol.cpp b/src/protocol.cpp index 6c37968ae9..93650319a9 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -624,7 +624,7 @@ void CProtocol::CreateAndImmSendConLessMessage ( const int iID, GenMessageFrame ( vecNewMessage, 0, iID, vecData ); // immediately send message - emit CLMessReadyForSending ( InetAddr, vecNewMessage, pTcpConnection ); + emit CLMessReadyForSending ( InetAddr, vecNewMessage, pTcpConnection, bUseTcpClient ); } void CProtocol::ParseMessageBody ( const CVector& vecbyMesBodyData, const int iRecCounter, const int iRecID ) diff --git a/src/protocol.h b/src/protocol.h index 7411a35af0..d48d46eb2e 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -314,7 +314,7 @@ public slots: signals: // transmitting void MessReadyForSending ( CVector vecMessage ); - void CLMessReadyForSending ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ); + void CLMessReadyForSending ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection, bool bUseTcpClient ); // receiving void ChangeJittBufSize ( int iNewJitBufSize ); diff --git a/src/server.cpp b/src/server.cpp index 39b3000687..f1f4f87417 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -475,8 +475,14 @@ void CServer::OnServerFull ( CHostAddress RecHostAddr ) ConnLessProtocol.CreateCLServerFullMes ( RecHostAddr ); } -void CServer::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ) +void CServer::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection, bool bUseTcpClient ) { + if ( bUseTcpClient ) + { + qWarning() << "Server send cannot use TCP client"; + return; + } + // the protocol queries me to call the function to send the message // send it through the network if ( pTcpConnection ) diff --git a/src/server.h b/src/server.h index 9c86ad289b..418d956486 100644 --- a/src/server.h +++ b/src/server.h @@ -340,7 +340,7 @@ public slots: void OnServerFull ( CHostAddress RecHostAddr ); - void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection ); + void OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecMessage, CTcpConnection* pTcpConnection, bool bUseTcpClient ); void OnProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress RecHostAddr, CTcpConnection* pTcpConnection ); From fa575d8e19edb1a46886d1eac9284979b54d8e1b Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Thu, 19 Mar 2026 12:16:50 +0000 Subject: [PATCH 09/17] Delete QTcpServer object when done --- src/tcpserver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp index 2a461b129d..085b53088a 100644 --- a/src/tcpserver.cpp +++ b/src/tcpserver.cpp @@ -46,6 +46,7 @@ CTcpServer::~CTcpServer() qInfo() << "- stopping Jamulus-TCP server"; pTcpServer->close(); } + pTcpServer->deleteLater(); } bool CTcpServer::Start() From d04f9780e29f8f1f686745c9c02b1f10b3981933 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Fri, 20 Mar 2026 18:31:08 +0000 Subject: [PATCH 10/17] Added some debug output --- src/tcpserver.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp index 085b53088a..be27512433 100644 --- a/src/tcpserver.cpp +++ b/src/tcpserver.cpp @@ -98,10 +98,10 @@ void CTcpServer::OnNewConnection() } } - CTcpConnection* pTcpConnection = new CTcpConnection ( pSocket, peerAddress ); - qDebug() << "- Jamulus-TCP: received connection from:" << peerAddress.InetAddr.toString(); + CTcpConnection* pTcpConnection = new CTcpConnection ( pSocket, peerAddress ); + // allocate memory for network receive and send buffer in samples CVector vecbyRecBuf; vecbyRecBuf.Init ( MAX_SIZE_BYTES_NETW_BUF ); @@ -120,12 +120,16 @@ void CTcpServer::OnNewConnection() int iRecID; CVector vecbyMesBodyData; + qDebug() << "- readyRead(), bytesAvailable() =" << pTcpConnection->pTcpSocket->bytesAvailable(); + long iNumBytesRead = pTcpConnection->pTcpSocket->read ( (char*) &vecbyRecBuf[0], MESS_HEADER_LENGTH_BYTE ); if ( iNumBytesRead == -1 ) { return; } + qDebug() << "- iNumBytesRead =" << iNumBytesRead; + if ( iNumBytesRead < MESS_HEADER_LENGTH_BYTE ) { qDebug() << "-- short read: expected" << MESS_HEADER_LENGTH_BYTE << "bytes, got" << iNumBytesRead; @@ -140,6 +144,8 @@ void CTcpServer::OnNewConnection() return; } + qDebug() << "- iNumBytesRead2 =" << iNumBytesRead2; + if ( iNumBytesRead2 < iPayloadLength ) { qDebug() << "-- short read: expected" << iPayloadLength << "bytes, got" << iNumBytesRead2; @@ -170,6 +176,8 @@ void CTcpServer::OnNewConnection() //### TODO: END ###// } } + + qDebug() << "- end of readyRead(), bytesAvailable() =" << pTcpConnection->pTcpSocket->bytesAvailable(); } ); } From dfcd05549e1488fa7a7bf3d426fcbd28c4b5623a Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Fri, 20 Mar 2026 22:30:43 +0000 Subject: [PATCH 11/17] Update copyright years --- src/tcpserver.cpp | 2 +- src/tcpserver.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp index be27512433..7d2764e993 100644 --- a/src/tcpserver.cpp +++ b/src/tcpserver.cpp @@ -1,5 +1,5 @@ /******************************************************************************\ - * Copyright (c) 2024 + * Copyright (c) 2024-2026 * * Author(s): * Tony Mountifield diff --git a/src/tcpserver.h b/src/tcpserver.h index d052f6e2b6..ea00e50c8d 100644 --- a/src/tcpserver.h +++ b/src/tcpserver.h @@ -1,5 +1,5 @@ /******************************************************************************\ - * Copyright (c) 2024 + * Copyright (c) 2024-2026 * * Author(s): * Tony Mountifield From a1d0c916657012234a3008bb753908f41ba48243 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Sat, 21 Mar 2026 00:28:24 +0000 Subject: [PATCH 12/17] Separate CTcpConnection code from CTcpServer --- Jamulus.pro | 2 + src/protocol.h | 2 +- src/server.h | 1 + src/socket.h | 2 +- src/tcpconnection.cpp | 145 ++++++++++++++++++++++++++++++++++++++++++ src/tcpconnection.h | 68 ++++++++++++++++++++ src/tcpserver.cpp | 90 +------------------------- src/tcpserver.h | 23 ++----- 8 files changed, 228 insertions(+), 105 deletions(-) create mode 100644 src/tcpconnection.cpp create mode 100644 src/tcpconnection.h diff --git a/Jamulus.pro b/Jamulus.pro index 3f00695463..fd1239707b 100644 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -400,6 +400,7 @@ HEADERS += src/plugins/audioreverb.h \ src/settings.h \ src/socket.h \ src/tcpserver.h \ + src/tcpconnection.h \ src/util.h \ src/recorder/jamrecorder.h \ src/recorder/creaperproject.h \ @@ -509,6 +510,7 @@ SOURCES += src/plugins/audioreverb.cpp \ src/signalhandler.cpp \ src/socket.cpp \ src/tcpserver.cpp \ + src/tcpconnection.cpp \ src/util.cpp \ src/recorder/jamrecorder.cpp \ src/recorder/creaperproject.cpp \ diff --git a/src/protocol.h b/src/protocol.h index d48d46eb2e..b08c5615b5 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -31,7 +31,7 @@ #include #include "global.h" #include "util.h" -#include "tcpserver.h" +#include "tcpconnection.h" /* Definitions ****************************************************************/ // protocol message IDs diff --git a/src/server.h b/src/server.h index 418d956486..b91bb8e976 100644 --- a/src/server.h +++ b/src/server.h @@ -43,6 +43,7 @@ #include "serverlogging.h" #include "serverlist.h" #include "tcpserver.h" +#include "tcpconnection.h" #include "recorder/jamcontroller.h" #include "threadpool.h" diff --git a/src/socket.h b/src/socket.h index a8919fcc01..2a9c6216a1 100644 --- a/src/socket.h +++ b/src/socket.h @@ -31,7 +31,7 @@ #include "global.h" #include "protocol.h" #include "util.h" -#include "tcpserver.h" +#include "tcpconnection.h" #ifndef _WIN32 # include # include diff --git a/src/tcpconnection.cpp b/src/tcpconnection.cpp new file mode 100644 index 0000000000..8a960e6c4b --- /dev/null +++ b/src/tcpconnection.cpp @@ -0,0 +1,145 @@ +/******************************************************************************\ + * Copyright (c) 2024-2026 + * + * Author(s): + * Tony Mountifield + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + \******************************************************************************/ + +#include "tcpserver.h" + +#include "protocol.h" +#include "server.h" +#include "channel.h" + +CTcpConnection::CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress, CServer* pServer ) : + pTcpSocket ( pTcpSocket ), + tcpAddress ( tcpAddress ), + pServer ( pServer ) +{ + vecbyRecBuf.Init ( MAX_SIZE_BYTES_NETW_BUF ); + iPos = 0; + iPayloadRemain = 0; + + connect ( pTcpSocket, &QTcpSocket::disconnected, this, &CTcpConnection::OnDisconnected ); + connect ( pTcpSocket, &QTcpSocket::readyRead, this, &CTcpConnection::OnReadyRead ); + if ( pServer ) + { + connect ( this, &CTcpConnection::ProtocolCLMessageReceived, pServer, &CServer::OnProtocolCLMessageReceived ); + } +} + +void CTcpConnection::OnDisconnected() +{ + qDebug() << "- Jamulus-TCP: disconnected from:" << tcpAddress.InetAddr.toString(); + pTcpSocket->deleteLater(); + delete this; +} + +void CTcpConnection::OnReadyRead() +{ + long iBytesAvail = pTcpSocket->bytesAvailable(); + + qDebug() << "- readyRead(), bytesAvailable() =" << iBytesAvail; + + while ( iBytesAvail > 0 ) + { + if ( iPos < MESS_HEADER_LENGTH_BYTE ) + { + // reading message header + long iNumBytesRead = pTcpSocket->read ( (char*) &vecbyRecBuf[iPos], MESS_HEADER_LENGTH_BYTE - iPos ); + if ( iNumBytesRead == -1 ) + { + return; + } + + qDebug() << "-- (hdr) iNumBytesRead =" << iNumBytesRead; + + iPos += iNumBytesRead; + iBytesAvail -= iNumBytesRead; + + if ( iPos >= MESS_HEADER_LENGTH_BYTE ) + { + // now have a complete header + iPayloadRemain = CProtocol::GetBodyLength ( vecbyRecBuf ); + + Q_ASSERT ( iPayloadRemain <= MAX_SIZE_BYTES_NETW_BUF - MESS_HEADER_LENGTH_BYTE ); + + iPayloadRemain -= iPos - MESS_HEADER_LENGTH_BYTE; + } + } + else + { + // reading message body + long iNumBytesRead = pTcpSocket->read ( (char*) &vecbyRecBuf[iPos], iPayloadRemain ); + if ( iNumBytesRead == -1 ) + { + return; + } + + qDebug() << "-- (body) iNumBytesRead =" << iNumBytesRead; + + iPos += iNumBytesRead; + iPayloadRemain -= iNumBytesRead; + iBytesAvail -= iNumBytesRead; + + Q_ASSERT ( iPayloadRemain >= 0 ); + + if ( iPayloadRemain == 0 ) + { + // have a complete payload + qDebug() << "- Jamulus-TCP: received protocol message of length" << iPos; + + // check if this is a protocol message + int iRecCounter; + int iRecID; + CVector vecbyMesBodyData; + + if ( !CProtocol::ParseMessageFrame ( vecbyRecBuf, iPos, vecbyMesBodyData, iRecCounter, iRecID ) ) + { + qDebug() << "- Jamulus-TCP: message parsed OK, ID =" << iRecID; + + // this is a protocol message, check the type of the message + if ( CProtocol::IsConnectionLessMessageID ( iRecID ) ) + { + //### TODO: BEGIN ###// + // a copy of the vector is used -> avoid malloc in real-time routine + emit ProtocolCLMessageReceived ( iRecID, vecbyMesBodyData, tcpAddress, this ); + //### TODO: END ###// + } + else + { + //### TODO: BEGIN ###// + // a copy of the vector is used -> avoid malloc in real-time routine + // emit ProtocolMessageReceived ( iRecCounter, iRecID, vecbyMesBodyData, pTcpConnection->tcpAddress, pTcpConnection ); + //### TODO: END ###// + } + } + else + { + qDebug() << "- Jamulus-TCP: failed to parse frame"; + } + + iPos = 0; // ready for next message, if any + } + } + } + + qDebug() << "- end of readyRead(), bytesAvailable() =" << pTcpSocket->bytesAvailable(); +} diff --git a/src/tcpconnection.h b/src/tcpconnection.h new file mode 100644 index 0000000000..46527c15cb --- /dev/null +++ b/src/tcpconnection.h @@ -0,0 +1,68 @@ +/******************************************************************************\ + * Copyright (c) 2024-2026 + * + * Author(s): + * Tony Mountifield + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * +\******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "global.h" +#include "util.h" + +// The header files channel.h and server.h require to include this header file +// so we get a cyclic dependency. To solve this issue, a prototype of the +// channel class and server class is defined here. +class CServer; // forward declaration of CServer +// class CChannel; // forward declaration of CChannel + +/* Classes ********************************************************************/ +class CTcpConnection : public QObject +{ + Q_OBJECT + +public: + CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress, CServer* pServer = nullptr ); + ~CTcpConnection() {} + + QTcpSocket* pTcpSocket; + CHostAddress tcpAddress; + CHostAddress udpAddress; + +private: + CServer* pServer; + int iPos; + int iPayloadRemain; + CVector vecbyRecBuf; + +signals: + void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, CTcpConnection* pTcpConnection ); + +protected slots: + void OnDisconnected(); + void OnReadyRead(); +}; diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp index 7d2764e993..d659914680 100644 --- a/src/tcpserver.cpp +++ b/src/tcpserver.cpp @@ -23,10 +23,11 @@ \******************************************************************************/ #include "tcpserver.h" +//#include "tcpconnection.h" #include "protocol.h" #include "server.h" -#include "channel.h" +//#include "channel.h" CTcpServer::CTcpServer ( CServer* pNServP, const QString& strServerBindIP, int iPort, bool bEnableIPv6 ) : pServer ( pNServP ), @@ -35,7 +36,6 @@ CTcpServer::CTcpServer ( CServer* pNServP, const QString& strServerBindIP, int i bEnableIPv6 ( bEnableIPv6 ), pTcpServer ( new QTcpServer ( this ) ) { - connect ( this, &CTcpServer::ProtocolCLMessageReceived, pServer, &CServer::OnProtocolCLMessageReceived ); connect ( pTcpServer, &QTcpServer::newConnection, this, &CTcpServer::OnNewConnection ); } @@ -100,89 +100,5 @@ void CTcpServer::OnNewConnection() qDebug() << "- Jamulus-TCP: received connection from:" << peerAddress.InetAddr.toString(); - CTcpConnection* pTcpConnection = new CTcpConnection ( pSocket, peerAddress ); - - // allocate memory for network receive and send buffer in samples - CVector vecbyRecBuf; - vecbyRecBuf.Init ( MAX_SIZE_BYTES_NETW_BUF ); - - connect ( pSocket, &QTcpSocket::disconnected, [this, pTcpConnection]() { - qDebug() << "- Jamulus-TCP: connection from:" << pTcpConnection->tcpAddress.InetAddr.toString() << "closed"; - pTcpConnection->pTcpSocket->deleteLater(); - delete pTcpConnection; - } ); - - connect ( pSocket, &QTcpSocket::readyRead, [this, pTcpConnection, vecbyRecBuf]() { - // handle received Jamulus protocol packet - - // check if this is a protocol message - int iRecCounter; - int iRecID; - CVector vecbyMesBodyData; - - qDebug() << "- readyRead(), bytesAvailable() =" << pTcpConnection->pTcpSocket->bytesAvailable(); - - long iNumBytesRead = pTcpConnection->pTcpSocket->read ( (char*) &vecbyRecBuf[0], MESS_HEADER_LENGTH_BYTE ); - if ( iNumBytesRead == -1 ) - { - return; - } - - qDebug() << "- iNumBytesRead =" << iNumBytesRead; - - if ( iNumBytesRead < MESS_HEADER_LENGTH_BYTE ) - { - qDebug() << "-- short read: expected" << MESS_HEADER_LENGTH_BYTE << "bytes, got" << iNumBytesRead; - return; - } - - long iPayloadLength = CProtocol::GetBodyLength ( vecbyRecBuf ); - - long iNumBytesRead2 = pTcpConnection->pTcpSocket->read ( (char*) &vecbyRecBuf[MESS_HEADER_LENGTH_BYTE], iPayloadLength ); - if ( iNumBytesRead2 == -1 ) - { - return; - } - - qDebug() << "- iNumBytesRead2 =" << iNumBytesRead2; - - if ( iNumBytesRead2 < iPayloadLength ) - { - qDebug() << "-- short read: expected" << iPayloadLength << "bytes, got" << iNumBytesRead2; - return; - } - - iNumBytesRead += iNumBytesRead2; - - qDebug() << "- Jamulus-TCP: received protocol message of length" << iNumBytesRead; - - if ( !CProtocol::ParseMessageFrame ( vecbyRecBuf, iNumBytesRead, vecbyMesBodyData, iRecCounter, iRecID ) ) - { - qDebug() << "- Jamulus-TCP: message parsed OK, ID =" << iRecID; - - // this is a protocol message, check the type of the message - if ( CProtocol::IsConnectionLessMessageID ( iRecID ) ) - { - //### TODO: BEGIN ###// - // a copy of the vector is used -> avoid malloc in real-time routine - emit ProtocolCLMessageReceived ( iRecID, vecbyMesBodyData, pTcpConnection->tcpAddress, pTcpConnection ); - //### TODO: END ###// - } - else - { - //### TODO: BEGIN ###// - // a copy of the vector is used -> avoid malloc in real-time routine - // emit ProtocolMessageReceived ( iRecCounter, iRecID, vecbyMesBodyData, pTcpConnection->tcpAddress, pTcpConnection ); - //### TODO: END ###// - } - } - - qDebug() << "- end of readyRead(), bytesAvailable() =" << pTcpConnection->pTcpSocket->bytesAvailable(); - } ); -} - -#if 0 -void CTcpServer::Send ( QTcpSocket* pSocket ) { - // pSocket->write ( ); + new CTcpConnection ( pSocket, peerAddress, pServer ); // will auto-delete on disconnect } -#endif diff --git a/src/tcpserver.h b/src/tcpserver.h index ea00e50c8d..8e1da5acc2 100644 --- a/src/tcpserver.h +++ b/src/tcpserver.h @@ -31,15 +31,17 @@ #include #include +#include "tcpconnection.h" + #include "global.h" #include "util.h" // The header files channel.h and server.h require to include this header file // so we get a cyclic dependency. To solve this issue, a prototype of the // channel class and server class is defined here. -class CServer; // forward declaration of CServer -class CChannel; // forward declaration of CChannel -class CTcpConnection; // forward declaration of CTcpConnection +class CServer; // forward declaration of CServer +// class CChannel; // forward declaration of CChannel +// class CTcpConnection; // forward declaration of CTcpConnection /* Classes ********************************************************************/ class CTcpServer : public QObject @@ -59,20 +61,9 @@ class CTcpServer : public QObject const bool bEnableIPv6; QTcpServer* pTcpServer; -signals: - void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, CTcpConnection* pTcpConnection ); + // signals: + // void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, CTcpConnection* pTcpConnection ); protected slots: void OnNewConnection(); }; - -class CTcpConnection -{ -public: - CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress ) : pTcpSocket ( pTcpSocket ), tcpAddress ( tcpAddress ) {} - ~CTcpConnection() {} - - QTcpSocket* pTcpSocket; - CHostAddress tcpAddress; - CHostAddress udpAddress; -}; From e369e977d0a5e6ceec73d303ea85bf8a35fb837f Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Sun, 22 Mar 2026 16:46:15 +0000 Subject: [PATCH 13/17] Make CTcpConnection members private --- src/server.cpp | 2 +- src/tcpconnection.cpp | 10 ++++++++++ src/tcpconnection.h | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/server.cpp b/src/server.cpp index f1f4f87417..5151db43b6 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -488,7 +488,7 @@ void CServer::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecM if ( pTcpConnection ) { // send to the connected socket directly - pTcpConnection->pTcpSocket->write ( (const char*) &( (CVector) vecMessage )[0], vecMessage.Size() ); + pTcpConnection->write ( (const char*) &( (CVector) vecMessage )[0], vecMessage.Size() ); } else { diff --git a/src/tcpconnection.cpp b/src/tcpconnection.cpp index 8a960e6c4b..c342c51cc8 100644 --- a/src/tcpconnection.cpp +++ b/src/tcpconnection.cpp @@ -143,3 +143,13 @@ void CTcpConnection::OnReadyRead() qDebug() << "- end of readyRead(), bytesAvailable() =" << pTcpSocket->bytesAvailable(); } + +qint64 CTcpConnection::write ( const char* data, qint64 maxSize ) +{ + if ( !pTcpSocket ) + { + return -1; + } + + return pTcpSocket->write ( data, maxSize ); +} diff --git a/src/tcpconnection.h b/src/tcpconnection.h index 46527c15cb..834900c3d5 100644 --- a/src/tcpconnection.h +++ b/src/tcpconnection.h @@ -49,11 +49,13 @@ class CTcpConnection : public QObject CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress, CServer* pServer = nullptr ); ~CTcpConnection() {} + qint64 write ( const char* data, qint64 maxSize ); + +private: QTcpSocket* pTcpSocket; CHostAddress tcpAddress; CHostAddress udpAddress; -private: CServer* pServer; int iPos; int iPayloadRemain; From fb6150ce4dc083d9e94d6887f38cd3008ea34df4 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Mon, 23 Mar 2026 12:16:31 +0000 Subject: [PATCH 14/17] Add client-side TCP code --- src/client.cpp | 18 ++++++++++++++++++ src/tcpconnection.cpp | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/src/client.cpp b/src/client.cpp index 4e3c7dd450..2e0391e827 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -264,6 +264,24 @@ void CClient::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecM if ( bUseTcpClient ) { // create a TCP client connection and send message + QTcpSocket* pSocket = new QTcpSocket ( this ); + + connect ( pSocket, &QTcpSocket::errorOccurred, this, [this, pSocket] ( QAbstractSocket::SocketError err ) { + Q_UNUSED ( err ); + + qWarning() << "- TCP connection error:" << pSocket->errorString(); + // may want to specifically handle ConnectionRefusedError? + pSocket->deleteLater(); + } ); + + connect ( pSocket, &QTcpSocket::connected, this, [this, pSocket, InetAddr, vecMessage]() { + // connection succeeded, give it to a CTcpConnection + CTcpConnection* pTcpConnection = new CTcpConnection ( pSocket, InetAddr, nullptr ); // client connection, will self-delete on disconnect + + pTcpConnection->write ( (const char*) &( (CVector) vecMessage )[0], vecMessage.Size() ); + + // the CTcpConnection object will pass the reply back up to CProtocol + } ); } else { diff --git a/src/tcpconnection.cpp b/src/tcpconnection.cpp index c342c51cc8..f20f787388 100644 --- a/src/tcpconnection.cpp +++ b/src/tcpconnection.cpp @@ -122,6 +122,12 @@ void CTcpConnection::OnReadyRead() // a copy of the vector is used -> avoid malloc in real-time routine emit ProtocolCLMessageReceived ( iRecID, vecbyMesBodyData, tcpAddress, this ); //### TODO: END ###// + + // disconnect if we are a client + if ( !pServer ) + { + pTcpSocket->disconnectFromHost(); + } } else { From 031ce5cef9409af3c5a369dfecfa67396c6008bd Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Mon, 23 Mar 2026 18:11:20 +0000 Subject: [PATCH 15/17] Request server list via TCP if required --- src/client.cpp | 7 +++++-- src/connectdlg.cpp | 13 ++++++++++++- src/tcpconnection.cpp | 17 ++++++++++++----- src/tcpconnection.h | 16 +++++++++------- src/tcpserver.cpp | 7 ++----- src/tcpserver.h | 13 ++++--------- 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 2e0391e827..54a907b8e8 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -276,12 +276,15 @@ void CClient::OnSendCLProtMessage ( CHostAddress InetAddr, CVector vecM connect ( pSocket, &QTcpSocket::connected, this, [this, pSocket, InetAddr, vecMessage]() { // connection succeeded, give it to a CTcpConnection - CTcpConnection* pTcpConnection = new CTcpConnection ( pSocket, InetAddr, nullptr ); // client connection, will self-delete on disconnect + CTcpConnection* pTcpConnection = + new CTcpConnection ( pSocket, InetAddr, nullptr, &Channel ); // client connection, will self-delete on disconnect pTcpConnection->write ( (const char*) &( (CVector) vecMessage )[0], vecMessage.Size() ); - // the CTcpConnection object will pass the reply back up to CProtocol + // the CTcpConnection object will pass the reply back up to CClient::Channel } ); + + pSocket->connectToHost ( InetAddr.InetAddr, InetAddr.iPort ); } else { diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp index 354e3982d2..9296336713 100644 --- a/src/connectdlg.cpp +++ b/src/connectdlg.cpp @@ -544,7 +544,18 @@ void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector& vecChanInfo ) { diff --git a/src/tcpconnection.cpp b/src/tcpconnection.cpp index f20f787388..04118a238d 100644 --- a/src/tcpconnection.cpp +++ b/src/tcpconnection.cpp @@ -28,10 +28,11 @@ #include "server.h" #include "channel.h" -CTcpConnection::CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress, CServer* pServer ) : +CTcpConnection::CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress, CServer* pServer, CChannel* pChannel ) : pTcpSocket ( pTcpSocket ), tcpAddress ( tcpAddress ), - pServer ( pServer ) + pServer ( pServer ), + pChannel ( pChannel ) { vecbyRecBuf.Init ( MAX_SIZE_BYTES_NETW_BUF ); iPos = 0; @@ -39,17 +40,23 @@ CTcpConnection::CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcp connect ( pTcpSocket, &QTcpSocket::disconnected, this, &CTcpConnection::OnDisconnected ); connect ( pTcpSocket, &QTcpSocket::readyRead, this, &CTcpConnection::OnReadyRead ); + if ( pServer ) { connect ( this, &CTcpConnection::ProtocolCLMessageReceived, pServer, &CServer::OnProtocolCLMessageReceived ); } + + if ( pChannel ) + { + connect ( this, &CTcpConnection::ProtocolCLMessageReceived, pChannel, &CChannel::OnProtocolCLMessageReceived ); + } } void CTcpConnection::OnDisconnected() { - qDebug() << "- Jamulus-TCP: disconnected from:" << tcpAddress.InetAddr.toString(); + qDebug() << "- Jamulus-TCP: disconnected from:" << tcpAddress.toString(); pTcpSocket->deleteLater(); - delete this; + deleteLater(); // delete this object in the next event loop } void CTcpConnection::OnReadyRead() @@ -124,7 +131,7 @@ void CTcpConnection::OnReadyRead() //### TODO: END ###// // disconnect if we are a client - if ( !pServer ) + if ( pChannel ) { pTcpSocket->disconnectFromHost(); } diff --git a/src/tcpconnection.h b/src/tcpconnection.h index 834900c3d5..0930b4c419 100644 --- a/src/tcpconnection.h +++ b/src/tcpconnection.h @@ -35,10 +35,10 @@ #include "util.h" // The header files channel.h and server.h require to include this header file -// so we get a cyclic dependency. To solve this issue, a prototype of the -// channel class and server class is defined here. -class CServer; // forward declaration of CServer -// class CChannel; // forward declaration of CChannel +// so we get a cyclic dependency. To solve this issue, prototypes of the +// channel class and server class are defined here. +class CServer; // forward declaration of CServer +class CChannel; // forward declaration of CChannel /* Classes ********************************************************************/ class CTcpConnection : public QObject @@ -46,7 +46,7 @@ class CTcpConnection : public QObject Q_OBJECT public: - CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress, CServer* pServer = nullptr ); + CTcpConnection ( QTcpSocket* pTcpSocket, const CHostAddress& tcpAddress, CServer* pServer, CChannel* pChannel ); ~CTcpConnection() {} qint64 write ( const char* data, qint64 maxSize ); @@ -56,7 +56,9 @@ class CTcpConnection : public QObject CHostAddress tcpAddress; CHostAddress udpAddress; - CServer* pServer; + CServer* pServer; + CChannel* pChannel; + int iPos; int iPayloadRemain; CVector vecbyRecBuf; @@ -64,7 +66,7 @@ class CTcpConnection : public QObject signals: void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, CTcpConnection* pTcpConnection ); -protected slots: +private slots: void OnDisconnected(); void OnReadyRead(); }; diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp index d659914680..be5251dc1c 100644 --- a/src/tcpserver.cpp +++ b/src/tcpserver.cpp @@ -23,11 +23,8 @@ \******************************************************************************/ #include "tcpserver.h" -//#include "tcpconnection.h" -#include "protocol.h" #include "server.h" -//#include "channel.h" CTcpServer::CTcpServer ( CServer* pNServP, const QString& strServerBindIP, int iPort, bool bEnableIPv6 ) : pServer ( pNServP ), @@ -98,7 +95,7 @@ void CTcpServer::OnNewConnection() } } - qDebug() << "- Jamulus-TCP: received connection from:" << peerAddress.InetAddr.toString(); + qDebug() << "- Jamulus-TCP: received connection from:" << peerAddress.toString(); - new CTcpConnection ( pSocket, peerAddress, pServer ); // will auto-delete on disconnect + new CTcpConnection ( pSocket, peerAddress, pServer, nullptr ); // will auto-delete on disconnect } diff --git a/src/tcpserver.h b/src/tcpserver.h index 8e1da5acc2..92329d691d 100644 --- a/src/tcpserver.h +++ b/src/tcpserver.h @@ -36,12 +36,10 @@ #include "global.h" #include "util.h" -// The header files channel.h and server.h require to include this header file +// The header file server.h requires to include this header file // so we get a cyclic dependency. To solve this issue, a prototype of the -// channel class and server class is defined here. +// server class is defined here. class CServer; // forward declaration of CServer -// class CChannel; // forward declaration of CChannel -// class CTcpConnection; // forward declaration of CTcpConnection /* Classes ********************************************************************/ class CTcpServer : public QObject @@ -50,7 +48,7 @@ class CTcpServer : public QObject public: CTcpServer ( CServer* pNServP, const QString& strServerBindIP, int iPort, bool bEnableIPv6 ); - virtual ~CTcpServer(); + ~CTcpServer(); bool Start(); @@ -61,9 +59,6 @@ class CTcpServer : public QObject const bool bEnableIPv6; QTcpServer* pTcpServer; - // signals: - // void ProtocolCLMessageReceived ( int iRecID, CVector vecbyMesBodyData, CHostAddress HostAdr, CTcpConnection* pTcpConnection ); - -protected slots: +private slots: void OnNewConnection(); }; From 3a12b7c608ad838c051c263dba037309a4c98f88 Mon Sep 17 00:00:00 2001 From: Tony Mountifield Date: Wed, 25 Mar 2026 20:35:24 +0000 Subject: [PATCH 16/17] Add message context parameter for CLM_TCP_SUPPORTED --- src/client.h | 2 +- src/clientdlg.h | 2 +- src/connectdlg.cpp | 25 ++++++++++++++++++------- src/connectdlg.h | 2 +- src/protocol.cpp | 35 +++++++++++++++++++++++++++++------ src/protocol.h | 6 +++--- src/server.cpp | 2 +- src/server.h | 2 +- src/serverlist.cpp | 2 +- 9 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/client.h b/src/client.h index eac46c5518..6c7d0af9c2 100644 --- a/src/client.h +++ b/src/client.h @@ -477,7 +477,7 @@ protected slots: void CLRedServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo ); - void CLTcpSupported ( CHostAddress InetAddr ); + void CLTcpSupported ( CHostAddress InetAddr, int iID ); void CLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo ); diff --git a/src/clientdlg.h b/src/clientdlg.h index b36e297593..64ddb86106 100644 --- a/src/clientdlg.h +++ b/src/clientdlg.h @@ -223,7 +223,7 @@ public slots: ConnectDlg.SetServerList ( InetAddr, vecServerInfo, true ); } - void OnCLTcpSupported ( CHostAddress InetAddr ) { ConnectDlg.SetTcpSupported ( InetAddr ); } + void OnCLTcpSupported ( CHostAddress InetAddr, int iID ) { ConnectDlg.SetTcpSupported ( InetAddr, iID ); } void OnCLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo ) { diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp index 9296336713..1727dcf65a 100644 --- a/src/connectdlg.cpp +++ b/src/connectdlg.cpp @@ -544,16 +544,27 @@ void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVectorerrorString();