~mardy/signon-ui/ignore-ssl-errors

« back to all changes in this revision

Viewing changes to src/remote-request-interface.cpp

  • Committer: Alberto Mardegan
  • Date: 2013-05-10 14:41:34 UTC
  • mfrom: (85.1.11 trunk)
  • Revision ID: alberto.mardegan@canonical.com-20130510144134-vnyb2ohem41r5ere
Update from trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of signon-ui
 
3
 *
 
4
 * Copyright (C) 2013 Canonical Ltd.
 
5
 *
 
6
 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
 
7
 *
 
8
 * This program is free software: you can redistribute it and/or modify it
 
9
 * under the terms of the GNU General Public License version 3, as published
 
10
 * by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
14
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
15
 * PURPOSE.  See the GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License along
 
18
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
#include "remote-request-interface.h"
 
22
 
 
23
#include "debug.h"
 
24
 
 
25
#include <QByteArray>
 
26
#include <QDataStream>
 
27
#include <QFile>
 
28
#include <QSocketNotifier>
 
29
 
 
30
using namespace SignOnUi;
 
31
 
 
32
namespace SignOnUi {
 
33
 
 
34
static const QByteArray welcomeMessage = "SsoUi";
 
35
 
 
36
class IpcHandler: public QObject
 
37
{
 
38
    Q_OBJECT
 
39
 
 
40
public:
 
41
    enum Code {
 
42
        Start = 1,
 
43
        Cancel,
 
44
        SetResult,
 
45
        SetCanceled,
 
46
    };
 
47
 
 
48
    IpcHandler();
 
49
    ~IpcHandler();
 
50
 
 
51
    void setChannels(QIODevice *readChannel, QIODevice *writeChannel);
 
52
    void write(const QByteArray &data);
 
53
 
 
54
Q_SIGNALS:
 
55
    void dataReady(const QByteArray &data);
 
56
 
 
57
private Q_SLOTS:
 
58
    void onReadyRead();
 
59
 
 
60
private:
 
61
    bool waitWelcomeMessage();
 
62
 
 
63
private:
 
64
    QIODevice *m_readChannel;
 
65
    QIODevice *m_writeChannel;
 
66
    int m_expectedLength;
 
67
    bool m_gotWelcomeMessage;
 
68
    QByteArray m_readBuffer;
 
69
};
 
70
 
 
71
} // namespace
 
72
 
 
73
IpcHandler::IpcHandler():
 
74
    QObject(),
 
75
    m_readChannel(0),
 
76
    m_writeChannel(0),
 
77
    m_expectedLength(0),
 
78
    m_gotWelcomeMessage(false)
 
79
{
 
80
}
 
81
 
 
82
IpcHandler::~IpcHandler()
 
83
{
 
84
}
 
85
 
 
86
void IpcHandler::setChannels(QIODevice *readChannel, QIODevice *writeChannel)
 
87
{
 
88
    m_readChannel = readChannel;
 
89
    m_writeChannel = writeChannel;
 
90
    QObject::connect(m_readChannel, SIGNAL(readyRead()),
 
91
                     this, SLOT(onReadyRead()));
 
92
    /* QFile need special handling */
 
93
    QFile *file = qobject_cast<QFile*>(m_readChannel);
 
94
    if (file != 0) {
 
95
        QSocketNotifier *notifier = new QSocketNotifier(file->handle(),
 
96
                                                        QSocketNotifier::Read,
 
97
                                                        this);
 
98
        QObject::connect(notifier, SIGNAL(activated(int)),
 
99
                         this, SLOT(onReadyRead()));
 
100
    }
 
101
    onReadyRead();
 
102
 
 
103
    if (m_writeChannel != 0) {
 
104
        m_writeChannel->write(welcomeMessage);
 
105
    }
 
106
}
 
107
 
 
108
void IpcHandler::write(const QByteArray &data)
 
109
{
 
110
    int length = data.count();
 
111
    m_writeChannel->write((char *)&length, sizeof(length));
 
112
    m_writeChannel->write(data);
 
113
}
 
114
 
 
115
void IpcHandler::onReadyRead()
 
116
{
 
117
    while (true) {
 
118
        if (m_expectedLength == 0) {
 
119
            /* We are beginning a new read */
 
120
 
 
121
            /* skip all noise */
 
122
            if (!waitWelcomeMessage()) break;
 
123
 
 
124
            int length;
 
125
            int bytesRead = m_readChannel->read((char *)&length,
 
126
                                                sizeof(length));
 
127
            if (bytesRead < int(sizeof(length))) break;
 
128
            m_expectedLength = length;
 
129
            m_readBuffer.clear();
 
130
        }
 
131
 
 
132
        int neededBytes = m_expectedLength - m_readBuffer.length();
 
133
        QByteArray buffer = m_readChannel->read(neededBytes);
 
134
        m_readBuffer += buffer;
 
135
        if (buffer.length() < neededBytes) break;
 
136
        if (m_readBuffer.length() == m_expectedLength) {
 
137
            Q_EMIT dataReady(m_readBuffer);
 
138
            m_expectedLength = 0;
 
139
        }
 
140
    }
 
141
}
 
142
 
 
143
bool IpcHandler::waitWelcomeMessage()
 
144
{
 
145
    if (m_gotWelcomeMessage) return true;
 
146
 
 
147
    /* All Qt applications on the Nexus 4 write some just to stdout when
 
148
     * starting. So, skip all input until a well-defined welcome message is
 
149
     * found */
 
150
 
 
151
    QByteArray buffer;
 
152
    int startCheckIndex = 0;
 
153
    do {
 
154
        buffer = m_readChannel->peek(40);
 
155
        int found = buffer.indexOf(welcomeMessage, startCheckIndex);
 
156
        int skip = (found >= 0) ? found : buffer.length() - welcomeMessage.length();
 
157
        if (found >= 0) {
 
158
            buffer = m_readChannel->read(skip + welcomeMessage.length());
 
159
            m_gotWelcomeMessage = true;
 
160
            return true;
 
161
        }
 
162
        if (skip > 0) {
 
163
            buffer = m_readChannel->read(skip);
 
164
        } else {
 
165
            buffer.clear();
 
166
        }
 
167
    } while (!buffer.isEmpty());
 
168
 
 
169
    return false;
 
170
}
 
171
 
 
172
namespace SignOnUi {
 
173
class RemoteRequestClientPrivate: public QObject
 
174
{
 
175
    Q_OBJECT
 
176
    Q_DECLARE_PUBLIC(RemoteRequestClient)
 
177
 
 
178
public:
 
179
    RemoteRequestClientPrivate(RemoteRequestClient *client);
 
180
    ~RemoteRequestClientPrivate() {};
 
181
 
 
182
private Q_SLOTS:
 
183
    void onDataReady(const QByteArray &data);
 
184
 
 
185
private:
 
186
    IpcHandler m_handler;
 
187
    mutable RemoteRequestClient *q_ptr;
 
188
};
 
189
} // namespace
 
190
 
 
191
RemoteRequestClientPrivate::RemoteRequestClientPrivate(RemoteRequestClient *client):
 
192
    QObject(client),
 
193
    q_ptr(client)
 
194
{
 
195
    QObject::connect(&m_handler, SIGNAL(dataReady(const QByteArray&)),
 
196
                     this, SLOT(onDataReady(const QByteArray&)));
 
197
}
 
198
 
 
199
void RemoteRequestClientPrivate::onDataReady(const QByteArray &data)
 
200
{
 
201
    Q_Q(RemoteRequestClient);
 
202
 
 
203
    QDataStream dataStream(data);
 
204
 
 
205
    // All messages start with the operation code
 
206
    int code;
 
207
    dataStream >> code;
 
208
    if (code == IpcHandler::SetResult) {
 
209
        QVariantMap result;
 
210
        dataStream >> result;
 
211
        Q_EMIT q->result(result);
 
212
    } else if (code == IpcHandler::SetCanceled) {
 
213
        Q_EMIT q->canceled();
 
214
    } else {
 
215
        qWarning() << "Unsupported opcode" << code;
 
216
    }
 
217
}
 
218
 
 
219
RemoteRequestClient::RemoteRequestClient(QObject *parent):
 
220
    QObject(parent),
 
221
    d_ptr(new RemoteRequestClientPrivate(this))
 
222
{
 
223
}
 
224
 
 
225
RemoteRequestClient::~RemoteRequestClient()
 
226
{
 
227
}
 
228
 
 
229
void RemoteRequestClient::setChannels(QIODevice *readChannel, QIODevice *writeChannel)
 
230
{
 
231
    Q_D(RemoteRequestClient);
 
232
    d->m_handler.setChannels(readChannel, writeChannel);
 
233
}
 
234
 
 
235
void RemoteRequestClient::start(const QVariantMap &parameters)
 
236
{
 
237
    Q_D(RemoteRequestClient);
 
238
 
 
239
    QByteArray data;
 
240
    QDataStream dataStream(&data, QIODevice::WriteOnly);
 
241
    dataStream << int(IpcHandler::Start);
 
242
    dataStream << parameters;
 
243
    d->m_handler.write(data);
 
244
}
 
245
 
 
246
void RemoteRequestClient::cancel()
 
247
{
 
248
    Q_D(RemoteRequestClient);
 
249
 
 
250
    QByteArray data;
 
251
    QDataStream dataStream(&data, QIODevice::WriteOnly);
 
252
    dataStream << int(IpcHandler::Cancel);
 
253
    d->m_handler.write(data);
 
254
}
 
255
 
 
256
namespace SignOnUi {
 
257
class RemoteRequestServerPrivate: public QObject
 
258
{
 
259
    Q_OBJECT
 
260
    Q_DECLARE_PUBLIC(RemoteRequestServer)
 
261
 
 
262
public:
 
263
    RemoteRequestServerPrivate(RemoteRequestServer *server);
 
264
    ~RemoteRequestServerPrivate() {};
 
265
 
 
266
private Q_SLOTS:
 
267
    void onDataReady(const QByteArray &data);
 
268
 
 
269
private:
 
270
    IpcHandler m_handler;
 
271
    mutable RemoteRequestServer *q_ptr;
 
272
};
 
273
} // namespace
 
274
 
 
275
RemoteRequestServerPrivate::RemoteRequestServerPrivate(RemoteRequestServer *server):
 
276
    QObject(server),
 
277
    q_ptr(server)
 
278
{
 
279
    QObject::connect(&m_handler, SIGNAL(dataReady(const QByteArray&)),
 
280
                     this, SLOT(onDataReady(const QByteArray&)));
 
281
}
 
282
 
 
283
void RemoteRequestServerPrivate::onDataReady(const QByteArray &data)
 
284
{
 
285
    Q_Q(RemoteRequestServer);
 
286
 
 
287
    QDataStream dataStream(data);
 
288
 
 
289
    // All messages start with the operation code
 
290
    int code;
 
291
    dataStream >> code;
 
292
    if (code == IpcHandler::Start) {
 
293
        QVariantMap parameters;
 
294
        dataStream >> parameters;
 
295
        Q_EMIT q->started(parameters);
 
296
    } else if (code == IpcHandler::Cancel) {
 
297
        Q_EMIT q->canceled();
 
298
    } else {
 
299
        qWarning() << "Unsupported opcode" << code;
 
300
    }
 
301
}
 
302
 
 
303
RemoteRequestServer::RemoteRequestServer(QObject *parent):
 
304
    QObject(parent),
 
305
    d_ptr(new RemoteRequestServerPrivate(this))
 
306
{
 
307
}
 
308
 
 
309
RemoteRequestServer::~RemoteRequestServer()
 
310
{
 
311
}
 
312
 
 
313
void RemoteRequestServer::setChannels(QIODevice *readChannel, QIODevice *writeChannel)
 
314
{
 
315
    Q_D(RemoteRequestServer);
 
316
    d->m_handler.setChannels(readChannel, writeChannel);
 
317
}
 
318
 
 
319
void RemoteRequestServer::setResult(const QVariantMap &result)
 
320
{
 
321
    Q_D(RemoteRequestServer);
 
322
 
 
323
    QByteArray data;
 
324
    QDataStream dataStream(&data, QIODevice::WriteOnly);
 
325
    dataStream << int(IpcHandler::SetResult);
 
326
    dataStream << result;
 
327
    d->m_handler.write(data);
 
328
}
 
329
 
 
330
void RemoteRequestServer::setCanceled()
 
331
{
 
332
    Q_D(RemoteRequestServer);
 
333
 
 
334
    QByteArray data;
 
335
    QDataStream dataStream(&data, QIODevice::WriteOnly);
 
336
    dataStream << int(IpcHandler::SetCanceled);
 
337
    d->m_handler.write(data);
 
338
}
 
339
 
 
340
#include "remote-request-interface.moc"