/vp_plugins/qt_single_apps/qtlocalpeer.cpp

http://cupsfilter.googlecode.com/ · C++ · 203 lines · 135 code · 21 blank · 47 comment · 22 complexity · a717ead088c57616d71023ac2241d4d5 MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** This file is part of a Qt Solutions component.
  4. **
  5. ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
  6. **
  7. ** Contact: Qt Software Information (qt-info@nokia.com)
  8. **
  9. ** Commercial Usage
  10. ** Licensees holding valid Qt Commercial licenses may use this file in
  11. ** accordance with the Qt Solutions Commercial License Agreement provided
  12. ** with the Software or, alternatively, in accordance with the terms
  13. ** contained in a written agreement between you and Nokia.
  14. **
  15. ** GNU Lesser General Public License Usage
  16. ** Alternatively, this file may be used under the terms of the GNU Lesser
  17. ** General Public License version 2.1 as published by the Free Software
  18. ** Foundation and appearing in the file LICENSE.LGPL included in the
  19. ** packaging of this file. Please review the following information to
  20. ** ensure the GNU Lesser General Public License version 2.1 requirements
  21. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  22. **
  23. ** In addition, as a special exception, Nokia gives you certain
  24. ** additional rights. These rights are described in the Nokia Qt LGPL
  25. ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
  26. ** package.
  27. **
  28. ** GNU General Public License Usage
  29. ** Alternatively, this file may be used under the terms of the GNU
  30. ** General Public License version 3.0 as published by the Free Software
  31. ** Foundation and appearing in the file LICENSE.GPL included in the
  32. ** packaging of this file. Please review the following information to
  33. ** ensure the GNU General Public License version 3.0 requirements will be
  34. ** met: http://www.gnu.org/copyleft/gpl.html.
  35. **
  36. ** Please note Third Party Software included with Qt Solutions may impose
  37. ** additional restrictions and it is the user's responsibility to ensure
  38. ** that they have met the licensing requirements of the GPL, LGPL, or Qt
  39. ** Solutions Commercial license and the relevant license of the Third
  40. ** Party Software they are using.
  41. **
  42. ** If you are unsure which license is appropriate for your use, please
  43. ** contact the sales department at qt-sales@nokia.com.
  44. **
  45. ****************************************************************************/
  46. #include "qtlocalpeer.h"
  47. #include <QtCore/QCoreApplication>
  48. #include <QtCore/QTime>
  49. #if defined(Q_OS_WIN)
  50. #include <QtCore/QLibrary>
  51. #include <QtCore/qt_windows.h>
  52. typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
  53. static PProcessIdToSessionId pProcessIdToSessionId = 0;
  54. #endif
  55. #if defined(Q_OS_UNIX)
  56. #include <time.h>
  57. #endif
  58. namespace 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. const char* QtLocalPeer::ack = "ack";
  67. QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
  68. : QObject(parent), id(appId)
  69. {
  70. QString prefix = id;
  71. if (id.isEmpty()) {
  72. id = QCoreApplication::applicationFilePath();
  73. #if defined(Q_OS_WIN)
  74. id = id.toLower();
  75. #endif
  76. prefix = id.section(QLatin1Char('/'), -1);
  77. }
  78. prefix.remove(QRegExp("[^a-zA-Z]"));
  79. prefix.truncate(6);
  80. QByteArray idc = id.toUtf8();
  81. quint16 idNum = qChecksum(idc.constData(), idc.size());
  82. socketName = QLatin1String("qtsingleapp-") + prefix
  83. + QLatin1Char('-') + QString::number(idNum, 16);
  84. #if defined(Q_OS_WIN)
  85. if (!pProcessIdToSessionId) {
  86. QLibrary lib("kernel32");
  87. pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
  88. }
  89. if (pProcessIdToSessionId) {
  90. DWORD sessionId = 0;
  91. pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
  92. socketName += QLatin1Char('-') + QString::number(sessionId, 16);
  93. }
  94. #else
  95. socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
  96. #endif
  97. server = new QLocalServer(this);
  98. QString lockName = QDir(QDir::tempPath()).absolutePath()
  99. + QLatin1Char('/') + socketName
  100. + QLatin1String("-lockfile");
  101. lockFile.setFileName(lockName);
  102. lockFile.open(QIODevice::ReadWrite);
  103. }
  104. bool QtLocalPeer::isClient()
  105. {
  106. if (lockFile.isLocked())
  107. return false;
  108. if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
  109. return true;
  110. bool res = server->listen(socketName);
  111. #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
  112. // ### Workaround
  113. if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
  114. QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
  115. res = server->listen(socketName);
  116. }
  117. #endif
  118. if (!res)
  119. qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
  120. QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
  121. return false;
  122. }
  123. bool QtLocalPeer::sendMessage(const QString &message, int timeout)
  124. {
  125. if (!isClient())
  126. return false;
  127. QLocalSocket socket;
  128. bool connOk = false;
  129. for(int i = 0; i < 2; i++) {
  130. // Try twice, in case the other instance is just starting up
  131. socket.connectToServer(socketName);
  132. connOk = socket.waitForConnected(timeout/2);
  133. if (connOk || i)
  134. break;
  135. int ms = 250;
  136. #if defined(Q_OS_WIN)
  137. Sleep(DWORD(ms));
  138. #else
  139. struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
  140. nanosleep(&ts, NULL);
  141. #endif
  142. }
  143. if (!connOk)
  144. return false;
  145. QByteArray uMsg(message.toUtf8());
  146. QDataStream ds(&socket);
  147. ds.writeBytes(uMsg.constData(), uMsg.size());
  148. bool res = socket.waitForBytesWritten(timeout);
  149. res &= socket.waitForReadyRead(timeout); // wait for ack
  150. res &= (socket.read(qstrlen(ack)) == ack);
  151. return res;
  152. }
  153. void QtLocalPeer::receiveConnection()
  154. {
  155. QLocalSocket* socket = server->nextPendingConnection();
  156. if (!socket)
  157. return;
  158. while (socket->bytesAvailable() < (int)sizeof(quint32))
  159. socket->waitForReadyRead();
  160. QDataStream ds(socket);
  161. QByteArray uMsg;
  162. quint32 remaining;
  163. ds >> remaining;
  164. uMsg.resize(remaining);
  165. int got = 0;
  166. char* uMsgBuf = uMsg.data();
  167. do {
  168. got = ds.readRawData(uMsgBuf, remaining);
  169. remaining -= got;
  170. uMsgBuf += got;
  171. } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
  172. if (got < 0) {
  173. qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString();
  174. delete socket;
  175. return;
  176. }
  177. QString message(QString::fromUtf8(uMsg));
  178. socket->write(ack, qstrlen(ack));
  179. socket->waitForBytesWritten(1000);
  180. delete socket;
  181. emit messageReceived(message); //### (might take a long time to return)
  182. }