diff --git a/singleapplication.cpp b/singleapplication.cpp index 8711cb1..c74d6db 100644 --- a/singleapplication.cpp +++ b/singleapplication.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -46,11 +47,6 @@ #include "singleapplication_p.h" -static const char NewInstance = 'N'; -static const char SecondaryInstance = 'S'; -static const char Reconnect = 'R'; -static const char InvalidConnection = '\0'; - SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr ) : q_ptr( q_ptr ) { server = nullptr; socket = nullptr; @@ -64,7 +60,7 @@ SingleApplicationPrivate::~SingleApplicationPrivate() } memory->lock(); - InstancesInfo* inst = (InstancesInfo*)memory->data(); + InstancesInfo* inst = static_cast(memory->data()); if( server != nullptr ) { server->close(); delete server; @@ -162,7 +158,7 @@ void SingleApplicationPrivate::startPrimary( bool resetMemory ) // Reset the number of connections memory->lock(); - InstancesInfo* inst = (InstancesInfo*)memory->data(); + InstancesInfo* inst = static_cast(memory->data()); if( resetMemory ) { inst->secondary = 0; @@ -185,7 +181,7 @@ void SingleApplicationPrivate::startSecondary() #endif } -void SingleApplicationPrivate::connectToPrimary( int msecs, char connectionType ) +void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType ) { // Connect to the Local Server of the Primary Instance if not already // connected. @@ -211,11 +207,14 @@ void SingleApplicationPrivate::connectToPrimary( int msecs, char connectionType // Initialisation message according to the SingleApplication protocol if( socket->state() == QLocalSocket::ConnectedState ) { // Notify the parent that a new instance had been started; - QByteArray initMsg = blockServerName.toLatin1(); - - initMsg.append( connectionType ); - initMsg.append( (const char *)&instanceNumber, sizeof(quint32) ); - initMsg.append( QByteArray::number( qChecksum( initMsg.constData(), initMsg.length() ), 256) ); + QByteArray initMsg; + QDataStream writeStream(&initMsg, QIODevice::WriteOnly); + writeStream.setVersion(QDataStream::Qt_5_6); + writeStream << blockServerName.toLatin1(); + writeStream << static_cast(connectionType); + writeStream << instanceNumber; + quint16 checksum = qChecksum(initMsg.constData(), static_cast(initMsg.length())); + writeStream << checksum; socket->write( initMsg ); socket->flush(); @@ -228,7 +227,7 @@ qint64 SingleApplicationPrivate::primaryPid() qint64 pid; memory->lock(); - InstancesInfo* inst = (InstancesInfo*)memory->data(); + InstancesInfo* inst = static_cast(memory->data()); pid = inst->primaryPid; memory->unlock(); @@ -272,39 +271,34 @@ void SingleApplicationPrivate::slotConnectionEstablished() QLocalSocket *nextConnSocket = server->nextPendingConnection(); - // Verify that the new connection follows the SingleApplication protocol - char connectionType = InvalidConnection; - quint32 instanceId; - QByteArray initMsg, tmp; + quint32 instanceId = 0; + ConnectionType connectionType = InvalidConnection; if( nextConnSocket->waitForReadyRead( 100 ) ) { - tmp = nextConnSocket->read( blockServerName.length() ); - // Verify that the socket data start with blockServerName - if( tmp == blockServerName.toLatin1() ) { - initMsg = tmp; - connectionType = nextConnSocket->read( 1 )[0]; + // 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); - switch( connectionType ) { - case NewInstance: - case SecondaryInstance: - case Reconnect: - { - initMsg += connectionType; - tmp = nextConnSocket->read( sizeof(quint32) ); - const char * data = tmp.constData(); - instanceId = (quint32)*data; - initMsg += tmp; - // Verify the checksum of the initMsg - QByteArray checksum = QByteArray::number( - qChecksum( initMsg.constData(), initMsg.length() ), - 256 - ); - tmp = nextConnSocket->read( checksum.length() ); - if( checksum == tmp ) - break; // Otherwise set to invalid connection (next line) - } - default: - connectionType = InvalidConnection; - } + // 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; + + const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast(msgBytes.length())); + + if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) { + connectionType = InvalidConnection; } } @@ -395,7 +389,7 @@ SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSeconda // Attempt to attach to the memory segment if( d->memory->attach() ) { d->memory->lock(); - InstancesInfo* inst = (InstancesInfo*)d->memory->data(); + InstancesInfo* inst = static_cast(d->memory->data()); if( ! inst->primary ) { d->startPrimary( false ); @@ -409,7 +403,7 @@ SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSeconda d->instanceNumber = inst->secondary; d->startSecondary(); if( d->options & Mode::SecondaryNotification ) { - d->connectToPrimary( timeout, SecondaryInstance ); + d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance ); } d->memory->unlock(); return; @@ -419,7 +413,7 @@ SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSeconda } } - d->connectToPrimary( timeout, NewInstance ); + d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance ); delete d; ::exit( EXIT_SUCCESS ); } @@ -465,7 +459,7 @@ bool SingleApplication::sendMessage( QByteArray message, int timeout ) if( isPrimary() ) return false; // Make sure the socket is connected - d->connectToPrimary( timeout, Reconnect ); + d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect ); d->socket->write( message ); bool dataWritten = d->socket->flush(); diff --git a/singleapplication_p.h b/singleapplication_p.h index 856b33d..a990a53 100644 --- a/singleapplication_p.h +++ b/singleapplication_p.h @@ -46,6 +46,12 @@ struct InstancesInfo { class SingleApplicationPrivate : public QObject { Q_OBJECT public: + enum ConnectionType : quint8 { + InvalidConnection = 0, + NewInstance = 1, + SecondaryInstance = 2, + Reconnect = 3 + }; Q_DECLARE_PUBLIC(SingleApplication) SingleApplicationPrivate( SingleApplication *q_ptr ); @@ -54,7 +60,7 @@ public: void genBlockServerName( int msecs ); void startPrimary( bool resetMemory ); void startSecondary(); - void connectToPrimary( int msecs, char connectionType ); + void connectToPrimary(int msecs, ConnectionType connectionType ); qint64 primaryPid(); #ifdef Q_OS_UNIX