Statistics
| Revision:

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
}