source: smplayer/trunk/src/qtsingleapplication/qtlocalpeer.cpp@ 165

Last change on this file since 165 was 165, checked in by Silvan Scherrer, 11 years ago

SMPlayer: update trunk to latest 0.8.7

File size: 6.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the Qt Solutions component.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** You may use this file under the terms of the BSD license as follows:
10**
11** "Redistribution and use in source and binary forms, with or without
12** modification, are permitted provided that the following conditions are
13** met:
14** * Redistributions of source code must retain the above copyright
15** notice, this list of conditions and the following disclaimer.
16** * Redistributions in binary form must reproduce the above copyright
17** notice, this list of conditions and the following disclaimer in
18** the documentation and/or other materials provided with the
19** distribution.
20** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21** of its contributors may be used to endorse or promote products derived
22** from this software without specific prior written permission.
23**
24**
25** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41
42#include "qtlocalpeer.h"
43#include <QCoreApplication>
44#include <QTime>
45
46#if defined(Q_OS_WIN)
47#include <QLibrary>
48#include <qt_windows.h>
49typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
50static PProcessIdToSessionId pProcessIdToSessionId = 0;
51#endif
52#if defined(Q_OS_UNIX) || defined(Q_OS_OS2)
53#include <sys/types.h>
54#include <time.h>
55#include <unistd.h>
56#endif
57
58namespace QtLP_Private {
59#include "qtlockedfile.cpp"
60#if defined(Q_OS_WIN)
61#include "qtlockedfile_win.cpp"
62#else
63#include "qtlockedfile_unix.cpp"
64#endif
65}
66
67const char* QtLocalPeer::ack = "ack";
68
69QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
70 : QObject(parent), id(appId)
71{
72 QString prefix = id;
73 if (id.isEmpty()) {
74 id = QCoreApplication::applicationFilePath();
75#if defined(Q_OS_WIN)
76 id = id.toLower();
77#endif
78 prefix = id.section(QLatin1Char('/'), -1);
79 }
80 prefix.remove(QRegExp("[^a-zA-Z]"));
81 prefix.truncate(6);
82
83 QByteArray idc = id.toUtf8();
84 quint16 idNum = qChecksum(idc.constData(), idc.size());
85 socketName = QLatin1String("qtsingleapp-") + prefix
86 + QLatin1Char('-') + QString::number(idNum, 16);
87
88#if defined(Q_OS_WIN)
89 if (!pProcessIdToSessionId) {
90 QLibrary lib("kernel32");
91 pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
92 }
93 if (pProcessIdToSessionId) {
94 DWORD sessionId = 0;
95 pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
96 socketName += QLatin1Char('-') + QString::number(sessionId, 16);
97 }
98#else
99 socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
100#endif
101
102 server = new QLocalServer(this);
103 QString lockName = QDir(QDir::tempPath()).absolutePath()
104 + QLatin1Char('/') + socketName
105 + QLatin1String("-lockfile");
106 lockFile.setFileName(lockName);
107 lockFile.open(QIODevice::ReadWrite);
108}
109
110
111
112bool QtLocalPeer::isClient()
113{
114 if (lockFile.isLocked())
115 return false;
116
117 if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
118 return true;
119
120 bool res = server->listen(socketName);
121#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
122 // ### Workaround
123 if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
124 QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
125 res = server->listen(socketName);
126 }
127#endif
128 if (!res)
129 qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
130 QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
131 return false;
132}
133
134
135bool QtLocalPeer::sendMessage(const QString &message, int timeout)
136{
137 if (!isClient())
138 return false;
139
140 QLocalSocket socket;
141 bool connOk = false;
142 for(int i = 0; i < 2; i++) {
143 // Try twice, in case the other instance is just starting up
144 socket.connectToServer(socketName);
145 connOk = socket.waitForConnected(timeout/2);
146 if (connOk || i)
147 break;
148 int ms = 250;
149#if defined(Q_OS_WIN)
150 Sleep(DWORD(ms));
151#else
152 struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
153 nanosleep(&ts, NULL);
154#endif
155 }
156 if (!connOk)
157 return false;
158
159 QByteArray uMsg(message.toUtf8());
160 QDataStream ds(&socket);
161 ds.writeBytes(uMsg.constData(), uMsg.size());
162 bool res = socket.waitForBytesWritten(timeout);
163 if (res) {
164 res &= socket.waitForReadyRead(timeout); // wait for ack
165 if (res)
166 res &= (socket.read(qstrlen(ack)) == ack);
167 }
168 return res;
169}
170
171
172void QtLocalPeer::receiveConnection()
173{
174 QLocalSocket* socket = server->nextPendingConnection();
175 if (!socket)
176 return;
177
178 while (socket->bytesAvailable() < (int)sizeof(quint32))
179 socket->waitForReadyRead();
180 QDataStream ds(socket);
181 QByteArray uMsg;
182 quint32 remaining;
183 ds >> remaining;
184 uMsg.resize(remaining);
185 int got = 0;
186 char* uMsgBuf = uMsg.data();
187 do {
188 got = ds.readRawData(uMsgBuf, remaining);
189 remaining -= got;
190 uMsgBuf += got;
191 } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
192 if (got < 0) {
193 qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
194 delete socket;
195 return;
196 }
197 QString message(QString::fromUtf8(uMsg));
198 socket->write(ack, qstrlen(ack));
199 socket->waitForBytesWritten(1000);
200 socket->waitForDisconnected(1000); // make sure client reads ack
201 delete socket;
202 emit messageReceived(message); //### (might take a long time to return)
203}
Note: See TracBrowser for help on using the repository browser.