PageRenderTime 58ms CodeModel.GetById 27ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 47
 48#include "qtlocalpeer.h"
 49#include <QtCore/QCoreApplication>
 50#include <QtCore/QTime>
 51
 52#if defined(Q_OS_WIN)
 53#include <QtCore/QLibrary>
 54#include <QtCore/qt_windows.h>
 55typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
 56static PProcessIdToSessionId pProcessIdToSessionId = 0;
 57#endif
 58#if defined(Q_OS_UNIX)
 59#include <time.h>
 60#endif
 61
 62namespace QtLP_Private {
 63#include "qtlockedfile.cpp"
 64#if defined(Q_OS_WIN)
 65#include "qtlockedfile_win.cpp"
 66#else
 67#include "qtlockedfile_unix.cpp"
 68#endif
 69}
 70
 71const char* QtLocalPeer::ack = "ack";
 72
 73QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
 74    : QObject(parent), id(appId)
 75{
 76    QString prefix = id;
 77    if (id.isEmpty()) {
 78        id = QCoreApplication::applicationFilePath();
 79#if defined(Q_OS_WIN)
 80        id = id.toLower();
 81#endif
 82        prefix = id.section(QLatin1Char('/'), -1);
 83    }
 84    prefix.remove(QRegExp("[^a-zA-Z]"));
 85    prefix.truncate(6);
 86
 87    QByteArray idc = id.toUtf8();
 88    quint16 idNum = qChecksum(idc.constData(), idc.size());
 89    socketName = QLatin1String("qtsingleapp-") + prefix
 90                 + QLatin1Char('-') + QString::number(idNum, 16);
 91
 92#if defined(Q_OS_WIN)
 93    if (!pProcessIdToSessionId) {
 94        QLibrary lib("kernel32");
 95        pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
 96    }
 97    if (pProcessIdToSessionId) {
 98        DWORD sessionId = 0;
 99        pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
100        socketName += QLatin1Char('-') + QString::number(sessionId, 16);
101    }
102#else
103    socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
104#endif
105
106    server = new QLocalServer(this);
107    QString lockName = QDir(QDir::tempPath()).absolutePath()
108                       + QLatin1Char('/') + socketName
109                       + QLatin1String("-lockfile");
110    lockFile.setFileName(lockName);
111    lockFile.open(QIODevice::ReadWrite);
112}
113
114
115
116bool QtLocalPeer::isClient()
117{
118    if (lockFile.isLocked())
119        return false;
120
121    if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
122        return true;
123
124    bool res = server->listen(socketName);
125#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
126    // ### Workaround
127    if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
128        QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
129        res = server->listen(socketName);
130    }
131#endif
132    if (!res)
133        qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
134    QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
135    return false;
136}
137
138
139bool QtLocalPeer::sendMessage(const QString &message, int timeout)
140{
141    if (!isClient())
142        return false;
143
144    QLocalSocket socket;
145    bool connOk = false;
146    for(int i = 0; i < 2; i++) {
147        // Try twice, in case the other instance is just starting up
148        socket.connectToServer(socketName);
149        connOk = socket.waitForConnected(timeout/2);
150        if (connOk || i)
151            break;
152        int ms = 250;
153#if defined(Q_OS_WIN)
154        Sleep(DWORD(ms));
155#else
156        struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
157        nanosleep(&ts, NULL);
158#endif
159    }
160    if (!connOk)
161        return false;
162
163    QByteArray uMsg(message.toUtf8());
164    QDataStream ds(&socket);
165    ds.writeBytes(uMsg.constData(), uMsg.size());
166    bool res = socket.waitForBytesWritten(timeout);
167    res &= socket.waitForReadyRead(timeout);   // wait for ack
168    res &= (socket.read(qstrlen(ack)) == ack);
169    return res;
170}
171
172
173void QtLocalPeer::receiveConnection()
174{
175    QLocalSocket* socket = server->nextPendingConnection();
176    if (!socket)
177        return;
178
179    while (socket->bytesAvailable() < (int)sizeof(quint32))
180        socket->waitForReadyRead();
181    QDataStream ds(socket);
182    QByteArray uMsg;
183    quint32 remaining;
184    ds >> remaining;
185    uMsg.resize(remaining);
186    int got = 0;
187    char* uMsgBuf = uMsg.data();
188    do {
189        got = ds.readRawData(uMsgBuf, remaining);
190        remaining -= got;
191        uMsgBuf += got;
192    } while (remaining && got >= 0 && socket->waitForReadyRead(2000));
193    if (got < 0) {
194        qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString();
195        delete socket;
196        return;
197    }
198    QString message(QString::fromUtf8(uMsg));
199    socket->write(ack, qstrlen(ack));
200    socket->waitForBytesWritten(1000);
201    delete socket;
202    emit messageReceived(message); //### (might take a long time to return)
203}