Krita Source Code Documentation
Loading...
Searching...
No Matches
qtlocalpeer.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
2// SPDX-License-Identifier: BSD-3-Clause
3
4
5#include "qtlocalpeer.h"
6#include <QCoreApplication>
7#include <QDataStream>
8#include <QRegularExpression>
9#include <QTime>
10
11#if defined(Q_OS_WIN)
12#include <QLibrary>
13#include <qt_windows.h>
14typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
15static PProcessIdToSessionId pProcessIdToSessionId = 0;
16#endif
17#if defined(Q_OS_UNIX)
18#include <sys/types.h>
19#include <time.h>
20#include <unistd.h>
21#endif
22
23namespace QtLP_Private {
24#include "qtlockedfile.cpp"
25#if defined(Q_OS_WIN)
26#include "qtlockedfile_win.cpp"
27#else
28#include "qtlockedfile_unix.cpp"
29#endif
30}
31
32const char* QtLocalPeer::ack = "ack";
33
34QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
35 : QObject(parent), id(appId)
36{
37 QString prefix = id;
38 if (id.isEmpty()) {
39 id = QCoreApplication::applicationFilePath();
40#if defined(Q_OS_WIN)
41 id = id.toLower();
42#endif
43 prefix = id.section(QLatin1Char('/'), -1);
44 }
45 prefix.remove(QRegularExpression("[^a-zA-Z]"));
46 prefix.truncate(6);
47
48 QByteArray idc = id.toUtf8();
49 quint16 idNum = qChecksum(idc.constData(), idc.size());
50 socketName = QLatin1String("qtsingleapp-") + prefix
51 + QLatin1Char('-') + QString::number(idNum, 16);
52
53#if defined(Q_OS_WIN)
54 if (!pProcessIdToSessionId) {
55 QLibrary lib("kernel32");
56 pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
57 }
58 if (pProcessIdToSessionId) {
59 DWORD sessionId = 0;
60 pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
61 socketName += QLatin1Char('-') + QString::number(sessionId, 16);
62 }
63#else
64 socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
65#endif
66
67 server = new QLocalServer(this);
68 QString lockName = QDir(QDir::tempPath()).absolutePath()
69 + QLatin1Char('/') + socketName
70 + QLatin1String("-lockfile");
71 lockFile.setFileName(lockName);
72 lockFile.open(QIODevice::ReadWrite);
73}
74
75
76
78{
79 if (lockFile.isLocked())
80 return false;
81
83 return true;
84
85 bool res = server->listen(socketName);
86#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
87 // ### Workaround
88 if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
89 QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
90 res = server->listen(socketName);
91 }
92#endif
93 if (!res)
94 qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
95 QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
96 return false;
97}
98
99
100bool QtLocalPeer::sendMessage(const QString &message, int timeout)
101{
102 if (!isClient())
103 return false;
104
105 QLocalSocket socket;
106 bool connOk = false;
107 for(int i = 0; i < 2; i++) {
108 // Try twice, in case the other instance is just starting up
109 socket.connectToServer(socketName);
110 connOk = socket.waitForConnected(timeout/2);
111 if (connOk || i)
112 break;
113 int ms = 250;
114#if defined(Q_OS_WIN)
115 Sleep(DWORD(ms));
116#else
117 struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
118 nanosleep(&ts, NULL);
119#endif
120 }
121 if (!connOk)
122 return false;
123
124 QByteArray uMsg(message.toUtf8());
125 QDataStream ds(&socket);
126 ds.writeBytes(uMsg.constData(), uMsg.size());
127 bool res = socket.waitForBytesWritten(timeout);
128 if (res) {
129 res &= socket.waitForReadyRead(timeout); // wait for ack
130 if (res)
131 res &= (socket.read(qstrlen(ack)) == ack);
132 }
133 return res;
134}
135
136
138{
139 QLocalSocket* socket = server->nextPendingConnection();
140 if (!socket)
141 return;
142
143 while (true) {
144 if (socket->state() == QLocalSocket::UnconnectedState) {
145 qWarning("QtLocalPeer: Peer disconnected");
146 delete socket;
147 return;
148 }
149 if (socket->bytesAvailable() >= qint64(sizeof(quint32)))
150 break;
151 socket->waitForReadyRead();
152 }
153
154 QDataStream ds(socket);
155 QByteArray uMsg;
156 quint32 remaining;
157 ds >> remaining;
158 uMsg.resize(remaining);
159 int got = 0;
160 char* uMsgBuf = uMsg.data();
161 do {
162 got = ds.readRawData(uMsgBuf, remaining);
163 remaining -= got;
164 uMsgBuf += got;
165 } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
166 if (got < 0) {
167 qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
168 delete socket;
169 return;
170 }
171 QString message(QString::fromUtf8(uMsg));
172 socket->write(ack, qstrlen(ack));
173 socket->waitForBytesWritten(1000);
174 socket->waitForDisconnected(1000); // make sure client reads ack
175 delete socket;
176 emit messageReceived(message); //### (might take a long time to return)
177}
bool open(OpenMode mode)
bool lock(LockMode mode, bool block=true)
QString socketName
Definition qtlocalpeer.h:32
void messageReceived(const QString &message)
bool isClient()
QtLocalPeer(QObject *parent=0, const QString &appId=QString())
static const char * ack
Definition qtlocalpeer.h:37
QString id
Definition qtlocalpeer.h:31
bool sendMessage(const QString &message, int timeout)
QtLP_Private::QtLockedFile lockFile
Definition qtlocalpeer.h:34
QLocalServer * server
Definition qtlocalpeer.h:33
void receiveConnection()