1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 ** This file is part of a Qt Solutions component.
10 ** You may use this file under the terms of the BSD license as follows:
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
15 ** * Redistributions of source code must retain the above copyright
16 ** notice, this list of conditions and the following disclaimer.
17 ** * Redistributions in binary form must reproduce the above copyright
18 ** notice, this list of conditions and the following disclaimer in
19 ** the documentation and/or other materials provided with the
21 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22 ** the names of its contributors may be used to endorse or promote
23 ** products derived from this software without specific prior written
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
38 ****************************************************************************/
41 #include "qtlocalpeer.h"
42 #include <QtCore/QCoreApplication>
43 #include <QtCore/QTime>
46 #include <QtCore/QLibrary>
47 #include <QtCore/qt_windows.h>
48 typedef BOOL(WINAPI
*PProcessIdToSessionId
)(DWORD
,DWORD
*);
49 static PProcessIdToSessionId pProcessIdToSessionId
= 0;
51 #if defined(Q_OS_UNIX)
55 namespace QtLP_Private
{
56 #include "qtlockedfile.cpp"
58 #include "qtlockedfile_win.cpp"
60 #include "qtlockedfile_unix.cpp"
64 const char* QtLocalPeer::ack
= "ack";
66 QtLocalPeer::QtLocalPeer(QObject
* parent
, const QString
&appId
)
67 : QObject(parent
), id(appId
)
71 id
= QCoreApplication::applicationFilePath();
75 prefix
= id
.section(QLatin1Char('/'), -1);
77 prefix
.remove(QRegExp("[^a-zA-Z]"));
80 QByteArray idc
= id
.toUtf8();
81 quint16 idNum
= qChecksum(idc
.constData(), idc
.size());
82 socketName
= QLatin1String("qtsingleapp-") + prefix
83 + QLatin1Char('-') + QString::number(idNum
, 16);
86 if (!pProcessIdToSessionId
) {
87 QLibrary
lib("kernel32");
88 pProcessIdToSessionId
= (PProcessIdToSessionId
)lib
.resolve("ProcessIdToSessionId");
90 if (pProcessIdToSessionId
) {
92 pProcessIdToSessionId(GetCurrentProcessId(), &sessionId
);
93 socketName
+= QLatin1Char('-') + QString::number(sessionId
, 16);
96 socketName
+= QLatin1Char('-') + QString::number(::getuid(), 16);
99 server
= new QLocalServer(this);
100 QString lockName
= QDir(QDir::tempPath()).absolutePath()
101 + QLatin1Char('/') + socketName
102 + QLatin1String("-lockfile");
103 lockFile
.setFileName(lockName
);
104 lockFile
.open(QIODevice::ReadWrite
);
109 bool QtLocalPeer::isClient()
111 if (lockFile
.isLocked())
114 if (!lockFile
.lock(QtLP_Private::QtLockedFile::WriteLock
, false))
117 bool res
= server
->listen(socketName
);
118 #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
120 if (!res
&& server
->serverError() == QAbstractSocket::AddressInUseError
) {
121 QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName
);
122 res
= server
->listen(socketName
);
126 qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server
->errorString()));
127 QObject::connect(server
, SIGNAL(newConnection()), SLOT(receiveConnection()));
132 bool QtLocalPeer::sendMessage(const QString
&message
, int timeout
)
139 for(int i
= 0; i
< 2; i
++) {
140 // Try twice, in case the other instance is just starting up
141 socket
.connectToServer(socketName
);
142 connOk
= socket
.waitForConnected(timeout
/2);
146 #if defined(Q_OS_WIN)
149 struct timespec ts
= { ms
/ 1000, (ms
% 1000) * 1000 * 1000 };
150 nanosleep(&ts
, NULL
);
156 QByteArray
uMsg(message
.toUtf8());
157 QDataStream
ds(&socket
);
158 ds
.writeBytes(uMsg
.constData(), uMsg
.size());
159 bool res
= socket
.waitForBytesWritten(timeout
);
161 res
&= socket
.waitForReadyRead(timeout
); // wait for ack
163 res
&= (socket
.read(qstrlen(ack
)) == ack
);
169 void QtLocalPeer::receiveConnection()
171 QLocalSocket
* socket
= server
->nextPendingConnection();
175 while (socket
->bytesAvailable() < (int)sizeof(quint32
))
176 socket
->waitForReadyRead();
177 QDataStream
ds(socket
);
181 uMsg
.resize(remaining
);
183 char* uMsgBuf
= uMsg
.data();
185 got
= ds
.readRawData(uMsgBuf
, remaining
);
188 } while (remaining
&& got
>= 0 && socket
->waitForReadyRead(2000));
190 qWarning("QtLocalPeer: Message reception failed %s", socket
->errorString().toLatin1().constData());
194 QString
message(QString::fromUtf8(uMsg
));
195 socket
->write(ack
, qstrlen(ack
));
196 socket
->waitForBytesWritten(1000);
198 emit
messageReceived(message
); //### (might take a long time to return)