From f975da90ccbb70b4dda4142be629e0b54841a71f Mon Sep 17 00:00:00 2001 From: Francis Giraldeau Date: Thu, 26 Jul 2018 19:10:14 -0400 Subject: [PATCH] Fix sendmessage (#46) * Fix send message example If a secondary instance sends a message immediately after connecting, the message follows the init message. This causes the slotConnectionEstablished to read and consume the tail of the message and interpret it as the checksum. The checksum fails and the connection becomes invalid. To avoid this race, we prefix the init message with its length. This way, we consume only the data relevant to the init message. This patch fixes the sending_arguments example. Signed-off-by: Francis Giraldeau * Fix include file case Signed-off-by: Francis Giraldeau --- examples/basic/main.cpp | 2 +- examples/calculator/main.cpp | 2 +- examples/sending_arguments/main.cpp | 2 +- singleapplication.cpp | 61 ++++++++++++++++++----------- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp index 4787d1c..1841902 100755 --- a/examples/basic/main.cpp +++ b/examples/basic/main.cpp @@ -1,4 +1,4 @@ -#include +#include int main(int argc, char *argv[]) { diff --git a/examples/calculator/main.cpp b/examples/calculator/main.cpp index 32d8811..d45438f 100644 --- a/examples/calculator/main.cpp +++ b/examples/calculator/main.cpp @@ -50,7 +50,7 @@ #include -#include +#include #include "calculator.h" diff --git a/examples/sending_arguments/main.cpp b/examples/sending_arguments/main.cpp index 8368036..d90b250 100755 --- a/examples/sending_arguments/main.cpp +++ b/examples/sending_arguments/main.cpp @@ -1,4 +1,4 @@ -#include +#include #include "messagereceiver.h" int main(int argc, char *argv[]) diff --git a/singleapplication.cpp b/singleapplication.cpp index c74d6db..a333a62 100644 --- a/singleapplication.cpp +++ b/singleapplication.cpp @@ -216,6 +216,13 @@ void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType conne quint16 checksum = qChecksum(initMsg.constData(), static_cast(initMsg.length())); writeStream << checksum; + // The header indicates the message length that follows + QByteArray header; + QDataStream headerStream(&header, QIODevice::WriteOnly); + headerStream.setVersion(QDataStream::Qt_5_6); + headerStream << (quint64) initMsg.length(); + + socket->write( header ); socket->write( initMsg ); socket->flush(); socket->waitForBytesWritten( msecs ); @@ -274,31 +281,41 @@ void SingleApplicationPrivate::slotConnectionEstablished() quint32 instanceId = 0; ConnectionType connectionType = InvalidConnection; if( nextConnSocket->waitForReadyRead( 100 ) ) { - // read all data from message in same order/format as written - QByteArray msgBytes = nextConnSocket->read(nextConnSocket->bytesAvailable() - static_cast(sizeof(quint16))); - QByteArray checksumBytes = nextConnSocket->read(sizeof(quint16)); - QDataStream readStream(msgBytes); - readStream.setVersion(QDataStream::Qt_5_6); + // read the fields in same order and format as written + QDataStream headerStream(nextConnSocket); + headerStream.setVersion(QDataStream::Qt_5_6); - // server name - QByteArray latin1Name; - readStream >> latin1Name; - // connectioon type - quint8 connType = InvalidConnection; - readStream >> connType; - connectionType = static_cast(connType); - // instance id - readStream >> instanceId; - // checksum - quint16 msgChecksum = 0; - QDataStream checksumStream(checksumBytes); - checksumStream.setVersion(QDataStream::Qt_5_6); - checksumStream >> msgChecksum; + // Read the header to know the message length + quint64 msgLen = 0; + headerStream >> msgLen; - const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast(msgBytes.length())); + if (msgLen >= sizeof(quint16)) { + // Read the message body + QByteArray msgBytes = nextConnSocket->read(msgLen); + QDataStream readStream(msgBytes); + readStream.setVersion(QDataStream::Qt_5_6); - if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) { - connectionType = InvalidConnection; + // server name + QByteArray latin1Name; + readStream >> latin1Name; + + // connection type + quint8 connType = InvalidConnection; + readStream >> connType; + connectionType = static_cast(connType); + + // instance id + readStream >> instanceId; + + // checksum + quint16 msgChecksum = 0; + readStream >> msgChecksum; + + const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast(msgBytes.length() - sizeof(quint16))); + + if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) { + connectionType = InvalidConnection; + } } }