2
* This file is part of signon-ui
4
* Copyright (C) 2013 Canonical Ltd.
6
* Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
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.
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.
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/>.
21
#include "remote-request-interface.h"
26
#include <QDataStream>
28
#include <QSocketNotifier>
30
using namespace SignOnUi;
34
static const QByteArray welcomeMessage = "SsoUi";
36
class IpcHandler: public QObject
51
void setChannels(QIODevice *readChannel, QIODevice *writeChannel);
52
void write(const QByteArray &data);
55
void dataReady(const QByteArray &data);
61
bool waitWelcomeMessage();
64
QIODevice *m_readChannel;
65
QIODevice *m_writeChannel;
67
bool m_gotWelcomeMessage;
68
QByteArray m_readBuffer;
73
IpcHandler::IpcHandler():
78
m_gotWelcomeMessage(false)
82
IpcHandler::~IpcHandler()
86
void IpcHandler::setChannels(QIODevice *readChannel, QIODevice *writeChannel)
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);
95
QSocketNotifier *notifier = new QSocketNotifier(file->handle(),
96
QSocketNotifier::Read,
98
QObject::connect(notifier, SIGNAL(activated(int)),
99
this, SLOT(onReadyRead()));
103
if (m_writeChannel != 0) {
104
m_writeChannel->write(welcomeMessage);
108
void IpcHandler::write(const QByteArray &data)
110
int length = data.count();
111
m_writeChannel->write((char *)&length, sizeof(length));
112
m_writeChannel->write(data);
115
void IpcHandler::onReadyRead()
118
if (m_expectedLength == 0) {
119
/* We are beginning a new read */
122
if (!waitWelcomeMessage()) break;
125
int bytesRead = m_readChannel->read((char *)&length,
127
if (bytesRead < int(sizeof(length))) break;
128
m_expectedLength = length;
129
m_readBuffer.clear();
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;
143
bool IpcHandler::waitWelcomeMessage()
145
if (m_gotWelcomeMessage) return true;
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
152
int startCheckIndex = 0;
154
buffer = m_readChannel->peek(40);
155
int found = buffer.indexOf(welcomeMessage, startCheckIndex);
156
int skip = (found >= 0) ? found : buffer.length() - welcomeMessage.length();
158
buffer = m_readChannel->read(skip + welcomeMessage.length());
159
m_gotWelcomeMessage = true;
163
buffer = m_readChannel->read(skip);
167
} while (!buffer.isEmpty());
173
class RemoteRequestClientPrivate: public QObject
176
Q_DECLARE_PUBLIC(RemoteRequestClient)
179
RemoteRequestClientPrivate(RemoteRequestClient *client);
180
~RemoteRequestClientPrivate() {};
183
void onDataReady(const QByteArray &data);
186
IpcHandler m_handler;
187
mutable RemoteRequestClient *q_ptr;
191
RemoteRequestClientPrivate::RemoteRequestClientPrivate(RemoteRequestClient *client):
195
QObject::connect(&m_handler, SIGNAL(dataReady(const QByteArray&)),
196
this, SLOT(onDataReady(const QByteArray&)));
199
void RemoteRequestClientPrivate::onDataReady(const QByteArray &data)
201
Q_Q(RemoteRequestClient);
203
QDataStream dataStream(data);
205
// All messages start with the operation code
208
if (code == IpcHandler::SetResult) {
210
dataStream >> result;
211
Q_EMIT q->result(result);
212
} else if (code == IpcHandler::SetCanceled) {
213
Q_EMIT q->canceled();
215
qWarning() << "Unsupported opcode" << code;
219
RemoteRequestClient::RemoteRequestClient(QObject *parent):
221
d_ptr(new RemoteRequestClientPrivate(this))
225
RemoteRequestClient::~RemoteRequestClient()
229
void RemoteRequestClient::setChannels(QIODevice *readChannel, QIODevice *writeChannel)
231
Q_D(RemoteRequestClient);
232
d->m_handler.setChannels(readChannel, writeChannel);
235
void RemoteRequestClient::start(const QVariantMap ¶meters)
237
Q_D(RemoteRequestClient);
240
QDataStream dataStream(&data, QIODevice::WriteOnly);
241
dataStream << int(IpcHandler::Start);
242
dataStream << parameters;
243
d->m_handler.write(data);
246
void RemoteRequestClient::cancel()
248
Q_D(RemoteRequestClient);
251
QDataStream dataStream(&data, QIODevice::WriteOnly);
252
dataStream << int(IpcHandler::Cancel);
253
d->m_handler.write(data);
257
class RemoteRequestServerPrivate: public QObject
260
Q_DECLARE_PUBLIC(RemoteRequestServer)
263
RemoteRequestServerPrivate(RemoteRequestServer *server);
264
~RemoteRequestServerPrivate() {};
267
void onDataReady(const QByteArray &data);
270
IpcHandler m_handler;
271
mutable RemoteRequestServer *q_ptr;
275
RemoteRequestServerPrivate::RemoteRequestServerPrivate(RemoteRequestServer *server):
279
QObject::connect(&m_handler, SIGNAL(dataReady(const QByteArray&)),
280
this, SLOT(onDataReady(const QByteArray&)));
283
void RemoteRequestServerPrivate::onDataReady(const QByteArray &data)
285
Q_Q(RemoteRequestServer);
287
QDataStream dataStream(data);
289
// All messages start with the operation 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();
299
qWarning() << "Unsupported opcode" << code;
303
RemoteRequestServer::RemoteRequestServer(QObject *parent):
305
d_ptr(new RemoteRequestServerPrivate(this))
309
RemoteRequestServer::~RemoteRequestServer()
313
void RemoteRequestServer::setChannels(QIODevice *readChannel, QIODevice *writeChannel)
315
Q_D(RemoteRequestServer);
316
d->m_handler.setChannels(readChannel, writeChannel);
319
void RemoteRequestServer::setResult(const QVariantMap &result)
321
Q_D(RemoteRequestServer);
324
QDataStream dataStream(&data, QIODevice::WriteOnly);
325
dataStream << int(IpcHandler::SetResult);
326
dataStream << result;
327
d->m_handler.write(data);
330
void RemoteRequestServer::setCanceled()
332
Q_D(RemoteRequestServer);
335
QDataStream dataStream(&data, QIODevice::WriteOnly);
336
dataStream << int(IpcHandler::SetCanceled);
337
d->m_handler.write(data);
340
#include "remote-request-interface.moc"