[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();