[qet] qet/qet: [5708] Update singleApplication.

[ Thread Index | Date Index | More lists.tuxfamily.org/qet Archives ]


Revision: 5708
Author:   scorpio810
Date:     2019-01-19 16:25:48 +0100 (Sat, 19 Jan 2019)
Log Message:
-----------
Update singleApplication.
See : https://github.com/itay-grudev/SingleApplication

Modified Paths:
--------------
    trunk/SingleApplication/singleapplication.cpp
    trunk/SingleApplication/singleapplication_p.cpp
    trunk/SingleApplication/singleapplication_p.h

Modified: trunk/SingleApplication/singleapplication.cpp
===================================================================
--- trunk/SingleApplication/singleapplication.cpp	2019-01-15 17:56:42 UTC (rev 5707)
+++ trunk/SingleApplication/singleapplication.cpp	2019-01-19 15:25:48 UTC (rev 5708)
@@ -91,7 +91,7 @@
 
         d->memory->unlock();
 
-        // Random sleep here limits the probability of a colision between two racing apps
+        // Random sleep here limits the probability of a collision between two racing apps
         qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
         QThread::sleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ) );
     }

Modified: trunk/SingleApplication/singleapplication_p.cpp
===================================================================
--- trunk/SingleApplication/singleapplication_p.cpp	2019-01-15 17:56:42 UTC (rev 5707)
+++ trunk/SingleApplication/singleapplication_p.cpp	2019-01-19 15:25:48 UTC (rev 5708)
@@ -101,7 +101,6 @@
     // User level block requires a user specific data in the hash
     if( options & SingleApplication::Mode::User ) {
 #ifdef Q_OS_WIN
-       // Q_UNUSED(timeout);
         wchar_t username [ UNLEN + 1 ];
         // Specifies size of the buffer on input
         DWORD usernameLength = UNLEN + 1;
@@ -110,7 +109,8 @@
         } else {
             appData.addData( QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).join("").toUtf8() );
         }
-#else
+#endif
+#ifdef Q_OS_UNIX
         QProcess process;
         process.start( "whoami" );
         if( process.waitForFinished( 100 ) &&
@@ -207,7 +207,11 @@
         // Notify the parent that a new instance had been started;
         QByteArray initMsg;
         QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
-        writeStream.setVersion(QDataStream::Qt_5_5);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+        writeStream.setVersion(QDataStream::Qt_5_6);
+#endif
+
         writeStream << blockServerName.toLatin1();
         writeStream << static_cast<quint8>(connectionType);
         writeStream << instanceNumber;
@@ -217,7 +221,10 @@
         // The header indicates the message length that follows
         QByteArray header;
         QDataStream headerStream(&header, QIODevice::WriteOnly);
-        headerStream.setVersion(QDataStream::Qt_5_5);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+        headerStream.setVersion(QDataStream::Qt_5_6);
+#endif
         headerStream << static_cast <quint64>( initMsg.length() );
 
         socket->write( header );
@@ -252,85 +259,133 @@
  */
 void SingleApplicationPrivate::slotConnectionEstablished()
 {
-    Q_Q(SingleApplication);
-
     QLocalSocket *nextConnSocket = server->nextPendingConnection();
+    connectionMap.insert(nextConnSocket, ConnectionInfo());
 
-    quint32 instanceId = 0;
-    ConnectionType connectionType = InvalidConnection;
-    if( nextConnSocket->waitForReadyRead( 100 ) ) {
-        // read the fields in same order and format as written
-        QDataStream headerStream(nextConnSocket);
-        headerStream.setVersion( QDataStream::Qt_5_5 );
+    QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
+        [nextConnSocket, this]() {
+            auto &info = connectionMap[nextConnSocket];
+            Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
+        }
+    );
 
-        // Read the header to know the message length
-        quint64 msgLen = 0;
-        headerStream >> msgLen;
+    QObject::connect(nextConnSocket, &QLocalSocket::disconnected,
+        [nextConnSocket, this](){
+            connectionMap.remove(nextConnSocket);
+            nextConnSocket->deleteLater();
+        }
+    );
 
-        if( msgLen >= sizeof( quint16 ) ) {
-           // Read the message body
-           QByteArray msgBytes = nextConnSocket->read(msgLen);
-           QDataStream readStream(msgBytes);
-           readStream.setVersion( QDataStream::Qt_5_5 );
+    QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
+        [nextConnSocket, this]() {
+            auto &info = connectionMap[nextConnSocket];
+            switch(info.stage) {
+            case StageHeader:
+                readInitMessageHeader(nextConnSocket);
+                break;
+            case StageBody:
+                readInitMessageBody(nextConnSocket);
+                break;
+            case StageConnected:
+                Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
+                break;
+            default:
+                break;
+            };
+        }
+    );
+}
 
-           // server name
-           QByteArray latin1Name;
-           readStream >> latin1Name;
+void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
+{
+    if (!connectionMap.contains( sock )) {
+        return;
+    }
 
-           // connection type
-           quint8 connType = InvalidConnection;
-           readStream >> connType;
-           connectionType = static_cast <ConnectionType>( connType );
+    if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ) {
+        return;
+    }
 
-           // instance id
-           readStream >> instanceId;
+    QDataStream headerStream( sock );
 
-           // checksum
-           quint16 msgChecksum = 0;
-           readStream >> msgChecksum;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+    headerStream.setVersion( QDataStream::Qt_5_6 );
+#endif
 
-           const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
+    // Read the header to know the message length
+    quint64 msgLen = 0;
+    headerStream >> msgLen;
+    ConnectionInfo &info = connectionMap[sock];
+    info.stage = StageBody;
+    info.msgLen = msgLen;
 
-           if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) {
-             connectionType = InvalidConnection;
-           }
-        }
+    if ( sock->bytesAvailable() >= (qint64) msgLen ) {
+        readInitMessageBody( sock );
     }
+}
 
-    if( connectionType == InvalidConnection ) {
-        nextConnSocket->close();
-        delete nextConnSocket;
+void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
+{
+    Q_Q(SingleApplication);
+
+    if (!connectionMap.contains( sock )) {
         return;
     }
 
-    QObject::connect(
-        nextConnSocket,
-        &QLocalSocket::aboutToClose,
-        this,
-        [nextConnSocket, instanceId, this]() {
-            Q_EMIT this->slotClientConnectionClosed( nextConnSocket, instanceId );
-        }
-    );
+    ConnectionInfo &info = connectionMap[sock];
+    if( sock->bytesAvailable() < ( qint64 )info.msgLen ) {
+        return;
+    }
 
-    QObject::connect(
-        nextConnSocket,
-        &QLocalSocket::readyRead,
-        this,
-        [nextConnSocket, instanceId, this]() {
-            Q_EMIT this->slotDataAvailable( nextConnSocket, instanceId );
-        }
-    );
+    // Read the message body
+    QByteArray msgBytes = sock->read(info.msgLen);
+    QDataStream readStream(msgBytes);
 
-    if( connectionType == NewInstance || (
-            connectionType == SecondaryInstance &&
-            options & SingleApplication::Mode::SecondaryNotification
-        )
-    ) {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+    readStream.setVersion( QDataStream::Qt_5_6 );
+#endif
+
+    // server name
+    QByteArray latin1Name;
+    readStream >> latin1Name;
+
+    // connection type
+    ConnectionType connectionType = InvalidConnection;
+    quint8 connTypeVal = InvalidConnection;
+    readStream >> connTypeVal;
+    connectionType = static_cast <ConnectionType>( connTypeVal );
+
+    // instance id
+    quint32 instanceId = 0;
+    readStream >> instanceId;
+
+    // checksum
+    quint16 msgChecksum = 0;
+    readStream >> msgChecksum;
+
+    const quint16 actualChecksum = qChecksum( msgBytes.constData(), static_cast<quint32>( msgBytes.length() - sizeof( quint16 ) ) );
+
+    bool isValid = readStream.status() == QDataStream::Ok &&
+                   QLatin1String(latin1Name) == blockServerName &&
+                   msgChecksum == actualChecksum;
+
+    if( !isValid ) {
+        sock->close();
+        return;
+    }
+
+    info.instanceId = instanceId;
+    info.stage = StageConnected;
+
+    if( connectionType == NewInstance ||
+        ( connectionType == SecondaryInstance &&
+          options & SingleApplication::Mode::SecondaryNotification ) )
+    {
         Q_EMIT q->instanceStarted();
     }
 
-    if( nextConnSocket->bytesAvailable() > 0 ) {
-        Q_EMIT this->slotDataAvailable( nextConnSocket, instanceId );
+    if (sock->bytesAvailable() > 0) {
+        Q_EMIT this->slotDataAvailable( sock, instanceId );
     }
 }
 
@@ -344,5 +399,4 @@
 {
     if( closedSocket->bytesAvailable() > 0 )
         Q_EMIT slotDataAvailable( closedSocket, instanceId  );
-    closedSocket->deleteLater();
 }

Modified: trunk/SingleApplication/singleapplication_p.h
===================================================================
--- trunk/SingleApplication/singleapplication_p.h	2019-01-15 17:56:42 UTC (rev 5707)
+++ trunk/SingleApplication/singleapplication_p.h	2019-01-19 15:25:48 UTC (rev 5708)
@@ -44,6 +44,14 @@
     quint16 checksum;
 };
 
+struct ConnectionInfo {
+    explicit ConnectionInfo() :
+        msgLen(0), instanceId(0), stage(0) {}
+    qint64 msgLen;
+    quint32 instanceId;
+    quint8 stage;
+};
+
 class SingleApplicationPrivate : public QObject {
 Q_OBJECT
 public:
@@ -53,6 +61,11 @@
         SecondaryInstance = 2,
         Reconnect = 3
     };
+    enum ConnectionStage : quint8 {
+        StageHeader = 0,
+        StageBody = 1,
+        StageConnected = 2,
+    };
     Q_DECLARE_PUBLIC(SingleApplication)
 
     SingleApplicationPrivate( SingleApplication *q_ptr );
@@ -65,6 +78,8 @@
     void connectToPrimary(int msecs, ConnectionType connectionType );
     quint16 blockChecksum();
     qint64 primaryPid();
+    void readInitMessageHeader(QLocalSocket *socket);
+    void readInitMessageBody(QLocalSocket *socket);
 
     SingleApplication *q_ptr;
     QSharedMemory *memory;
@@ -73,6 +88,7 @@
     quint32 instanceNumber;
     QString blockServerName;
     SingleApplication::Options options;
+    QMap<QLocalSocket*, ConnectionInfo> connectionMap;
 
 public Q_SLOTS:
     void slotConnectionEstablished();


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/