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>
47 #include <QtCore/QLibrary>
48 #include <QtCore/qt_windows.h>
49 typedef BOOL(WINAPI
*PProcessIdToSessionId
)(DWORD
,DWORD
*);
50 static PProcessIdToSessionId pProcessIdToSessionId
= 0;
52 #if defined(Q_OS_UNIX)
56 namespace QtLP_Private
{
57 #include "qtlockedfile.cpp"
59 #include "qtlockedfile_win.cpp"
61 #include "qtlockedfile_unix.cpp"
65 const char* QtLocalPeer::ack
= "ack";
67 QtLocalPeer::QtLocalPeer(QObject
* parent
, const QString
&appId
)
68 : QObject(parent
), id(appId
)
72 id
= QCoreApplication::applicationFilePath();
76 prefix
= id
.section(QLatin1Char('/'), -1);
78 prefix
.remove(QRegExp("[^a-zA-Z]"));
81 QByteArray idc
= id
.toUtf8();
82 quint16 idNum
= qChecksum(idc
.constData(), idc
.size());
83 socketName
= QLatin1String("qtsingleapp-") + prefix
84 + QLatin1Char('-') + QString::number(idNum
, 16);
87 if (!pProcessIdToSessionId
) {
88 QLibrary
lib("kernel32");
89 pProcessIdToSessionId
= (PProcessIdToSessionId
)lib
.resolve("ProcessIdToSessionId");
91 if (pProcessIdToSessionId
) {
93 pProcessIdToSessionId(GetCurrentProcessId(), &sessionId
);
94 socketName
+= QLatin1Char('-') + QString::number(sessionId
, 16);
97 socketName
+= QLatin1Char('-') + QString::number(::getuid(), 16);
100 server
= new QLocalServer(this);
101 QString lockName
= QDir(QDir::tempPath()).absolutePath()
102 + QLatin1Char('/') + socketName
103 + QLatin1String("-lockfile");
104 lockFile
.setFileName(lockName
);
105 lockFile
.open(QIODevice::ReadWrite
);
110 bool QtLocalPeer::isClient()
112 if (lockFile
.isLocked())
115 if (!lockFile
.lock(QtLP_Private::QtLockedFile::WriteLock
, false))
118 bool res
= server
->listen(socketName
);
119 #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
121 if (!res
&& server
->serverError() == QAbstractSocket::AddressInUseError
) {
122 QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName
);
123 res
= server
->listen(socketName
);
127 qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server
->errorString()));
128 QObject::connect(server
, SIGNAL(newConnection()), SLOT(receiveConnection()));
133 bool QtLocalPeer::sendMessage(const QString
&message
, int timeout
)
140 for(int i
= 0; i
< 2; i
++) {
141 // Try twice, in case the other instance is just starting up
142 socket
.connectToServer(socketName
);
143 connOk
= socket
.waitForConnected(timeout
/2);
147 #if defined(Q_OS_WIN)
150 struct timespec ts
= { ms
/ 1000, (ms
% 1000) * 1000 * 1000 };
151 nanosleep(&ts
, NULL
);
157 QByteArray
uMsg(message
.toUtf8());
158 QDataStream
ds(&socket
);
159 ds
.writeBytes(uMsg
.constData(), uMsg
.size());
160 bool res
= socket
.waitForBytesWritten(timeout
);
162 res
&= socket
.waitForReadyRead(timeout
); // wait for ack
164 res
&= (socket
.read(qstrlen(ack
)) == ack
);
170 void QtLocalPeer::receiveConnection()
172 QLocalSocket
* socket
= server
->nextPendingConnection();
176 while (socket
->bytesAvailable() < (int)sizeof(quint32
))
177 socket
->waitForReadyRead();
178 QDataStream
ds(socket
);
182 uMsg
.resize(remaining
);
184 char* uMsgBuf
= uMsg
.data();
186 got
= ds
.readRawData(uMsgBuf
, remaining
);
189 } while (remaining
&& got
>= 0 && socket
->waitForReadyRead(2000));
191 qWarning("QtLocalPeer: Message reception failed %s", socket
->errorString().toLatin1().constData());
195 QString
message(QString::fromUtf8(uMsg
));
196 socket
->write(ack
, qstrlen(ack
));
197 socket
->waitForBytesWritten(1000);
199 emit
messageReceived(message
); //### (might take a long time to return)