root / trunk / client / gui_qt / QtSolutions / qtlocalpeer.cpp @ 1919
History | View | Annotate | Download (6.7 KB)
| 1 | 
                  /**************************************************************************** 
                 | 
              
|---|---|
| 2 | 
                  **  | 
              
| 3 | 
                  ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).  | 
              
| 4 | 
                  ** All rights reserved.  | 
              
| 5 | 
                  ** Contact: Nokia Corporation ([email protected])  | 
              
| 6 | 
                  **  | 
              
| 7 | 
                  ** This file is part of a Qt Solutions component.  | 
              
| 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: https://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.1, 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: https://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 Nokia at [email protected].  | 
              
| 44 | 
                  **  | 
              
| 45 | 
                  ****************************************************************************/  | 
              
| 46 | 
                   | 
              
| 47 | 
                   | 
              
| 48 | 
                  #include "qtlocalpeer.h"  | 
              
| 49 | 
                  #include  | 
              
| 50 | 
                  #include  | 
              
| 51 | 
                  #include  | 
              
| 52 | 
                   | 
              
| 53 | 
                  #if defined(Q_OS_WIN)
                 | 
              
| 54 | 
                  #include  | 
              
| 55 | 
                  #include  | 
              
| 56 | 
                  typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
                 | 
              
| 57 | 
                  static PProcessIdToSessionId pProcessIdToSessionId = 0;  | 
              
| 58 | 
                  #endif
                 | 
              
| 59 | 
                  #if defined(Q_OS_UNIX)
                 | 
              
| 60 | 
                  #include  | 
              
| 61 | 
                  #include  | 
              
| 62 | 
                  #include  | 
              
| 63 | 
                  #endif
                 | 
              
| 64 | 
                   | 
              
| 65 | 
                  const char* QtLocalPeer::ack = "ack";  | 
              
| 66 | 
                   | 
              
| 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 | 
                   | 
              
| 81 | 
                  QByteArray idc = id.toUtf8();  | 
              
| 82 | 
                  quint16 idNum = qChecksum(idc.constData(), idc.size());  | 
              
| 83 | 
                      socketName = QLatin1String("qtsingleapp-") + prefix
                 | 
              
| 84 | 
                  + QLatin1Char('-') + QString::number(idNum, 16);  | 
              
| 85 | 
                   | 
              
| 86 | 
                  #if defined(Q_OS_WIN)
                 | 
              
| 87 | 
                      if (!pProcessIdToSessionId) {
                 | 
              
| 88 | 
                          QLibrary lib("kernel32");
                 | 
              
| 89 | 
                          pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
                 | 
              
| 90 | 
                  }  | 
              
| 91 | 
                      if (pProcessIdToSessionId) {
                 | 
              
| 92 | 
                          DWORD sessionId = 0;
                 | 
              
| 93 | 
                  pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);  | 
              
| 94 | 
                  socketName += QLatin1Char('-') + QString::number(sessionId, 16);  | 
              
| 95 | 
                  }  | 
              
| 96 | 
                  #else
                 | 
              
| 97 | 
                  socketName += QLatin1Char('-') + QString::number(::getuid(), 16);  | 
              
| 98 | 
                  #endif
                 | 
              
| 99 | 
                   | 
              
| 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);  | 
              
| 106 | 
                  }  | 
              
| 107 | 
                   | 
              
| 108 | 
                   | 
              
| 109 | 
                   | 
              
| 110 | 
                  bool QtLocalPeer::isClient()
                 | 
              
| 111 | 
                  {
                 | 
              
| 112 | 
                      if (lockFile.isLocked())
                 | 
              
| 113 | 
                  return false;  | 
              
| 114 | 
                   | 
              
| 115 | 
                  if (!lockFile.lock(QtLockedFile::WriteLock, false))  | 
              
| 116 | 
                  return true;  | 
              
| 117 | 
                   | 
              
| 118 | 
                      bool res = server->listen(socketName);
                 | 
              
| 119 | 
                  #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))  | 
              
| 120 | 
                      // ### Workaround
                 | 
              
| 121 | 
                      if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
                 | 
              
| 122 | 
                          QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
                 | 
              
| 123 | 
                  res = server->listen(socketName);  | 
              
| 124 | 
                  }  | 
              
| 125 | 
                  #endif
                 | 
              
| 126 | 
                      if (!res)
                 | 
              
| 127 | 
                          qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
                 | 
              
| 128 | 
                  QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));  | 
              
| 129 | 
                  return false;  | 
              
| 130 | 
                  }  | 
              
| 131 | 
                   | 
              
| 132 | 
                   | 
              
| 133 | 
                  bool QtLocalPeer::sendMessage(const QString &message, int timeout)  | 
              
| 134 | 
                  {
                 | 
              
| 135 | 
                      return sendMessage(message.toUtf8(), timeout);
                 | 
              
| 136 | 
                  }  | 
              
| 137 | 
                   | 
              
| 138 | 
                  bool QtLocalPeer::sendMessage(const char* message, int timeout)  | 
              
| 139 | 
                  {
                 | 
              
| 140 | 
                      return sendMessage(QByteArray(message), timeout);
                 | 
              
| 141 | 
                  }  | 
              
| 142 | 
                   | 
              
| 143 | 
                  bool QtLocalPeer::sendMessage(const QByteArray &message, int timeout)  | 
              
| 144 | 
                  {
                 | 
              
| 145 | 
                      if (!isClient())
                 | 
              
| 146 | 
                  return false;  | 
              
| 147 | 
                   | 
              
| 148 | 
                  QLocalSocket socket;  | 
              
| 149 | 
                  bool connOk = false;  | 
              
| 150 | 
                  for(int i = 0; i < 2; i++) {  | 
              
| 151 | 
                          // Try twice, in case the other instance is just starting up
                 | 
              
| 152 | 
                  socket.connectToServer(socketName);  | 
              
| 153 | 
                          connOk = socket.waitForConnected(timeout/2);
                 | 
              
| 154 | 
                          if (connOk || i)
                 | 
              
| 155 | 
                              break;
                 | 
              
| 156 | 
                  int ms = 250;  | 
              
| 157 | 
                  #if defined(Q_OS_WIN)
                 | 
              
| 158 | 
                  Sleep(DWORD(ms));  | 
              
| 159 | 
                  #else
                 | 
              
| 160 | 
                  struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };  | 
              
| 161 | 
                          nanosleep(&ts, NULL);
                 | 
              
| 162 | 
                  #endif
                 | 
              
| 163 | 
                  }  | 
              
| 164 | 
                      if (!connOk)
                 | 
              
| 165 | 
                  return false;  | 
              
| 166 | 
                   | 
              
| 167 | 
                  QDataStream ds(&socket);  | 
              
| 168 | 
                  ds.writeBytes(message.constData(), message.size());  | 
              
| 169 | 
                      bool res = socket.waitForBytesWritten(timeout);
                 | 
              
| 170 | 
                      res &= socket.waitForReadyRead(timeout);   // wait for ack
                 | 
              
| 171 | 
                  res &= (socket.read(qstrlen(ack)) == ack);  | 
              
| 172 | 
                      return res;
                 | 
              
| 173 | 
                  }  | 
              
| 174 | 
                   | 
              
| 175 | 
                   | 
              
| 176 | 
                  void QtLocalPeer::receiveConnection()
                 | 
              
| 177 | 
                  {
                 | 
              
| 178 | 
                  QLocalSocket* socket = server->nextPendingConnection();  | 
              
| 179 | 
                      if (!socket)
                 | 
              
| 180 | 
                          return;
                 | 
              
| 181 | 
                   | 
              
| 182 | 
                  while (socket->bytesAvailable() < (int)sizeof(quint32))  | 
              
| 183 | 
                  socket->waitForReadyRead();  | 
              
| 184 | 
                  QDataStream ds(socket);  | 
              
| 185 | 
                  QByteArray uMsg;  | 
              
| 186 | 
                  quint32 remaining;  | 
              
| 187 | 
                  ds >> remaining;  | 
              
| 188 | 
                  uMsg.resize(remaining);  | 
              
| 189 | 
                  int got = 0;  | 
              
| 190 | 
                      char* uMsgBuf = uMsg.data();
                 | 
              
| 191 | 
                      do {
                 | 
              
| 192 | 
                  got = ds.readRawData(uMsgBuf, remaining);  | 
              
| 193 | 
                  remaining -= got;  | 
              
| 194 | 
                  uMsgBuf += got;  | 
              
| 195 | 
                  } while (remaining && got >= 0 && socket->waitForReadyRead(2000));  | 
              
| 196 | 
                  if (got < 0) {  | 
              
| 197 | 
                          qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString();
                 | 
              
| 198 | 
                  delete socket;  | 
              
| 199 | 
                          return;
                 | 
              
| 200 | 
                  }  | 
              
| 201 | 
                  socket->write(ack, qstrlen(ack));  | 
              
| 202 | 
                      socket->waitForBytesWritten(1000);
                 | 
              
| 203 | 
                  delete socket;  | 
              
| 204 | 
                      emit messageReceived(uMsg); //### (might take a long time to return)
                 | 
              
| 205 | 
                  emit messageReceived(QString::fromUtf8(uMsg));  | 
              
| 206 | 
                  }  | 
              
NNTPGrab

