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 <francis.giraldeau@gmail.com>

* Fix include file case

Signed-off-by: Francis Giraldeau <francis.giraldeau@nrc-cnrc.gc.ca>
This commit is contained in:
Francis Giraldeau 2018-07-26 19:10:14 -04:00 committed by Itay Grudev
parent a36a327ddf
commit f975da90cc
4 changed files with 42 additions and 25 deletions

View File

@ -1,4 +1,4 @@
#include <SingleApplication.h> #include <singleapplication.h>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {

View File

@ -50,7 +50,7 @@
#include <QApplication> #include <QApplication>
#include <SingleApplication.h> #include <singleapplication.h>
#include "calculator.h" #include "calculator.h"

View File

@ -1,4 +1,4 @@
#include <SingleApplication.h> #include <singleapplication.h>
#include "messagereceiver.h" #include "messagereceiver.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])

View File

@ -216,6 +216,13 @@ void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType conne
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length())); quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
writeStream << checksum; 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->write( initMsg );
socket->flush(); socket->flush();
socket->waitForBytesWritten( msecs ); socket->waitForBytesWritten( msecs );
@ -274,33 +281,43 @@ void SingleApplicationPrivate::slotConnectionEstablished()
quint32 instanceId = 0; quint32 instanceId = 0;
ConnectionType connectionType = InvalidConnection; ConnectionType connectionType = InvalidConnection;
if( nextConnSocket->waitForReadyRead( 100 ) ) { if( nextConnSocket->waitForReadyRead( 100 ) ) {
// read all data from message in same order/format as written // read the fields in same order and format as written
QByteArray msgBytes = nextConnSocket->read(nextConnSocket->bytesAvailable() - static_cast<qint64>(sizeof(quint16))); QDataStream headerStream(nextConnSocket);
QByteArray checksumBytes = nextConnSocket->read(sizeof(quint16)); headerStream.setVersion(QDataStream::Qt_5_6);
// Read the header to know the message length
quint64 msgLen = 0;
headerStream >> msgLen;
if (msgLen >= sizeof(quint16)) {
// Read the message body
QByteArray msgBytes = nextConnSocket->read(msgLen);
QDataStream readStream(msgBytes); QDataStream readStream(msgBytes);
readStream.setVersion(QDataStream::Qt_5_6); readStream.setVersion(QDataStream::Qt_5_6);
// server name // server name
QByteArray latin1Name; QByteArray latin1Name;
readStream >> latin1Name; readStream >> latin1Name;
// connectioon type
// connection type
quint8 connType = InvalidConnection; quint8 connType = InvalidConnection;
readStream >> connType; readStream >> connType;
connectionType = static_cast<ConnectionType>(connType); connectionType = static_cast<ConnectionType>(connType);
// instance id // instance id
readStream >> instanceId; readStream >> instanceId;
// checksum // checksum
quint16 msgChecksum = 0; quint16 msgChecksum = 0;
QDataStream checksumStream(checksumBytes); readStream >> msgChecksum;
checksumStream.setVersion(QDataStream::Qt_5_6);
checksumStream >> msgChecksum;
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length())); const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) { if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) {
connectionType = InvalidConnection; connectionType = InvalidConnection;
} }
} }
}
if( connectionType == InvalidConnection ) { if( connectionType == InvalidConnection ) {
nextConnSocket->close(); nextConnSocket->close();