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[])
{

View File

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

View File

@ -1,4 +1,4 @@
#include <SingleApplication.h>
#include <singleapplication.h>
#include "messagereceiver.h"
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()));
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,33 +281,43 @@ 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<qint64>(sizeof(quint16)));
QByteArray checksumBytes = nextConnSocket->read(sizeof(quint16));
// read the fields in same order and format as written
QDataStream headerStream(nextConnSocket);
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);
readStream.setVersion(QDataStream::Qt_5_6);
// server name
QByteArray latin1Name;
readStream >> latin1Name;
// connectioon type
// connection type
quint8 connType = InvalidConnection;
readStream >> connType;
connectionType = static_cast<ConnectionType>(connType);
// instance id
readStream >> instanceId;
// checksum
quint16 msgChecksum = 0;
QDataStream checksumStream(checksumBytes);
checksumStream.setVersion(QDataStream::Qt_5_6);
checksumStream >> msgChecksum;
readStream >> 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) {
connectionType = InvalidConnection;
}
}
}
if( connectionType == InvalidConnection ) {
nextConnSocket->close();