signon 8.54

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

remotepluginprocess.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of signon
3 *
4 * Copyright (C) 2009-2010 Nokia Corporation.
5 *
6 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * version 2.1 as published by the Free Software Foundation.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 */
22 #include <QProcess>
23 #include <QUrl>
24 #include <QTimer>
25 #include <QBuffer>
26 #include <QDataStream>
27 #include <unistd.h>
28
29 #include "debug.h"
30 #ifdef HAVE_LIBPROXY
31 #include "my-network-proxy-factory.h"
32 #endif
33 #include "remotepluginprocess.h"
34
35 // signon-plugins-common
36 #include "SignOn/blobiohandler.h"
37 #include "SignOn/ipc.h"
38
39 using namespace SignOn;
40
41 namespace RemotePluginProcessNS {
42
43 static CancelEventThread *cancelThread = NULL;
44
45 /* ---------------------- RemotePluginProcess ---------------------- */
46
47 RemotePluginProcess::RemotePluginProcess(QObject *parent):
48 QObject(parent)
49 {
50 m_plugin = NULL;
51 m_readnotifier = NULL;
52 m_errnotifier = NULL;
53
54 qRegisterMetaType<SignOn::SessionData>("SignOn::SessionData");
55 qRegisterMetaType<QString>("QString");
56 }
57
58 RemotePluginProcess::~RemotePluginProcess()
59 {
60 delete m_plugin;
61 delete m_readnotifier;
62 delete m_errnotifier;
63
64 if (cancelThread) {
65 cancelThread->quit();
66 cancelThread->wait();
67 delete cancelThread;
68 }
69 }
70
71 RemotePluginProcess *
72 RemotePluginProcess::createRemotePluginProcess(QString &type, QObject *parent)
73 {
74 RemotePluginProcess *rpp = new RemotePluginProcess(parent);
75
76 //this is needed before plugin is initialized
77 rpp->setupProxySettings();
78
79 if (!rpp->loadPlugin(type) ||
80 !rpp->setupDataStreams() ||
81 rpp->m_plugin->type() != type) {
82 delete rpp;
83 return NULL;
84 }
85 return rpp;
86 }
87
88 bool RemotePluginProcess::loadPlugin(QString &type)
89 {
90 TRACE() << " loading auth library for " << type;
91
92 QLibrary lib(getPluginName(type));
93
94 if (!lib.load()) {
95 qCritical() << QString("Failed to load %1 (reason: %2)")
96 .arg(getPluginName(type)).arg(lib.errorString());
97 return false;
98 }
99
100 TRACE() << "library loaded";
101
102 typedef AuthPluginInterface* (*SsoAuthPluginInstanceF)();
103 SsoAuthPluginInstanceF instance =
104 (SsoAuthPluginInstanceF)lib.resolve("auth_plugin_instance");
105 if (!instance) {
106 qCritical() << QString("Failed to resolve init function in %1 "
107 "(reason: %2)")
108 .arg(getPluginName(type)).arg(lib.errorString());
109 return false;
110 }
111
112 TRACE() << "constructor resolved";
113
114 m_plugin = qobject_cast<AuthPluginInterface *>(instance());
115
116 if (!m_plugin) {
117 qCritical() << QString("Failed to cast object for %1 type")
118 .arg(type);
119 return false;
120 }
121
122 connect(m_plugin, SIGNAL(result(const SignOn::SessionData&)),
123 this, SLOT(result(const SignOn::SessionData&)));
124
125 connect(m_plugin, SIGNAL(store(const SignOn::SessionData&)),
126 this, SLOT(store(const SignOn::SessionData&)));
127
128 connect(m_plugin, SIGNAL(error(const SignOn::Error &)),
129 this, SLOT(error(const SignOn::Error &)));
130
131 connect(m_plugin, SIGNAL(userActionRequired(const SignOn::UiSessionData&)),
132 this, SLOT(userActionRequired(const SignOn::UiSessionData&)));
133
134 connect(m_plugin, SIGNAL(refreshed(const SignOn::UiSessionData&)),
135 this, SLOT(refreshed(const SignOn::UiSessionData&)));
136
137 connect(m_plugin,
138 SIGNAL(statusChanged(const AuthPluginState, const QString&)),
139 this, SLOT(statusChanged(const AuthPluginState, const QString&)));
140
141 m_plugin->setParent(this);
142
143 TRACE() << "plugin is fully initialized";
144 return true;
145 }
146
147 bool RemotePluginProcess::setupDataStreams()
148 {
149 TRACE();
150
151 m_inFile.open(STDIN_FILENO, QIODevice::ReadOnly);
152 m_outFile.open(STDOUT_FILENO, QIODevice::WriteOnly);
153
154 m_readnotifier = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read);
155 m_errnotifier = new QSocketNotifier(STDIN_FILENO,
156 QSocketNotifier::Exception);
157
158 connect(m_readnotifier, SIGNAL(activated(int)), this, SLOT(startTask()));
159 connect(m_errnotifier, SIGNAL(activated(int)),
160 this, SIGNAL(processStopped()));
161
162 if (!cancelThread)
163 cancelThread = new CancelEventThread(m_plugin);
164
165 TRACE() << "cancel thread created";
166
167 m_blobIOHandler = new BlobIOHandler(&m_inFile, &m_outFile, this);
168
169 connect(m_blobIOHandler,
170 SIGNAL(dataReceived(const QVariantMap &)),
171 this,
172 SLOT(sessionDataReceived(const QVariantMap &)));
173
174 connect(m_blobIOHandler,
175 SIGNAL(error()),
176 this,
177 SLOT(blobIOError()));
178
179 m_blobIOHandler->setReadChannelSocketNotifier(m_readnotifier);
180
181 return true;
182 }
183
184 bool RemotePluginProcess::setupProxySettings()
185 {
186 TRACE();
187
188 #ifdef HAVE_LIBPROXY
189 /* Use a libproxy-based proxy factory; this code will no longer be
190 * needed when https://bugreports.qt-project.org/browse/QTBUG-26295
191 * is fixed. */
192 MyNetworkProxyFactory *proxyFactory = new MyNetworkProxyFactory();
193 QNetworkProxyFactory::setApplicationProxyFactory(proxyFactory);
194 #endif
195
196 return true;
197 }
198
199 void RemotePluginProcess::blobIOError()
200 {
201 error(
202 Error(Error::InternalServer,
203 QLatin1String("Failed to I/O session data to/from the signon daemon.")));
204 connect(m_readnotifier, SIGNAL(activated(int)), this, SLOT(startTask()));
205 }
206
207 void RemotePluginProcess::result(const SignOn::SessionData &data)
208 {
209 disableCancelThread();
210 QDataStream out(&m_outFile);
211 QVariantMap resultDataMap;
212
213 foreach(QString key, data.propertyNames())
214 resultDataMap[key] = data.getProperty(key);
215
216 out << (quint32)PLUGIN_RESPONSE_RESULT;
217
218 m_blobIOHandler->sendData(resultDataMap);
219
220 m_outFile.flush();
221 }
222
223 void RemotePluginProcess::store(const SignOn::SessionData &data)
224 {
225 QDataStream out(&m_outFile);
226 QVariantMap storeDataMap;
227
228 foreach(QString key, data.propertyNames())
229 storeDataMap[key] = data.getProperty(key);
230
231 out << (quint32)PLUGIN_RESPONSE_STORE;
232
233 m_blobIOHandler->sendData(storeDataMap);
234
235 m_outFile.flush();
236 }
237
238 void RemotePluginProcess::error(const SignOn::Error &err)
239 {
240 disableCancelThread();
241
242 QDataStream out(&m_outFile);
243
244 out << (quint32)PLUGIN_RESPONSE_ERROR;
245 out << (quint32)err.type();
246 out << err.message();
247 m_outFile.flush();
248
249 TRACE() << "error is sent" << err.type() << " " << err.message();
250 }
251
252 void RemotePluginProcess::userActionRequired(const SignOn::UiSessionData &data)
253 {
254 TRACE();
255 disableCancelThread();
256
257 QDataStream out(&m_outFile);
258 QVariantMap resultDataMap;
259
260 foreach(QString key, data.propertyNames())
261 resultDataMap[key] = data.getProperty(key);
262
263 out << (quint32)PLUGIN_RESPONSE_UI;
264 m_blobIOHandler->sendData(resultDataMap);
265 m_outFile.flush();
266 }
267
268 void RemotePluginProcess::refreshed(const SignOn::UiSessionData &data)
269 {
270 TRACE();
271 disableCancelThread();
272
273 QDataStream out(&m_outFile);
274 QVariantMap resultDataMap;
275
276 foreach(QString key, data.propertyNames())
277 resultDataMap[key] = data.getProperty(key);
278
279 m_readnotifier->setEnabled(true);
280
281 out << (quint32)PLUGIN_RESPONSE_REFRESHED;
282
283 m_blobIOHandler->sendData(resultDataMap);
284
285 m_outFile.flush();
286 }
287
288 void RemotePluginProcess::statusChanged(const AuthPluginState state,
289 const QString &message)
290 {
291 TRACE();
292 QDataStream out(&m_outFile);
293
294 out << (quint32)PLUGIN_RESPONSE_SIGNAL;
295 out << (quint32)state;
296 out << message;
297
298 m_outFile.flush();
299 }
300
301 QString RemotePluginProcess::getPluginName(const QString &type)
302 {
303 QString dirName = qgetenv("SSO_PLUGINS_DIR");
304 if (dirName.isEmpty())
305 dirName = QDir::cleanPath(SIGNOND_PLUGINS_DIR);
306 QString fileName = dirName +
307 QDir::separator() +
308 QString(SIGNON_PLUGIN_PREFIX) +
309 type +
310 QString(SIGNON_PLUGIN_SUFFIX);
311
312 return fileName;
313 }
314
315 void RemotePluginProcess::type()
316 {
317 QDataStream out(&m_outFile);
318 out << m_plugin->type();
319 }
320
321 void RemotePluginProcess::mechanisms()
322 {
323 QDataStream out(&m_outFile);
324 QStringList mechanisms = m_plugin->mechanisms();
325 QVariant mechsVar = mechanisms;
326 out << mechsVar;
327 }
328
329 void RemotePluginProcess::process()
330 {
331 QDataStream in(&m_inFile);
332
333
334 in >> m_currentMechanism;
335
336 int processBlobSize = -1;
337 in >> processBlobSize;
338
339 disconnect(m_readnotifier, SIGNAL(activated(int)), this, SLOT(startTask()));
340
341 m_currentOperation = PLUGIN_OP_PROCESS;
342 m_blobIOHandler->receiveData(processBlobSize);
343 }
344
345 void RemotePluginProcess::userActionFinished()
346 {
347 QDataStream in(&m_inFile);
348 int processBlobSize = -1;
349 in >> processBlobSize;
350
351 disconnect(m_readnotifier, SIGNAL(activated(int)), this, SLOT(startTask()));
352
353 m_currentOperation = PLUGIN_OP_PROCESS_UI;
354 m_blobIOHandler->receiveData(processBlobSize);
355 }
356
357 void RemotePluginProcess::refresh()
358 {
359 QDataStream in(&m_inFile);
360 int processBlobSize = -1;
361 in >> processBlobSize;
362
363 disconnect(m_readnotifier, SIGNAL(activated(int)), this, SLOT(startTask()));
364
365 m_currentOperation = PLUGIN_OP_REFRESH;
366 m_blobIOHandler->receiveData(processBlobSize);
367 }
368
369 void RemotePluginProcess::sessionDataReceived(const QVariantMap &sessionDataMap)
370 {
371 enableCancelThread();
372 TRACE() << "The cancel thread is started";
373
374 if (m_currentOperation == PLUGIN_OP_PROCESS) {
375 SessionData inData(sessionDataMap);
376 m_plugin->process(inData, m_currentMechanism);
377 m_currentMechanism.clear();
378
379 } else if(m_currentOperation == PLUGIN_OP_PROCESS_UI) {
380 UiSessionData inData(sessionDataMap);
381 m_plugin->userActionFinished(inData);
382
383 } else if(m_currentOperation == PLUGIN_OP_REFRESH) {
384 UiSessionData inData(sessionDataMap);
385 m_plugin->refresh(inData);
386
387 } else {
388 TRACE() << "Wrong operation code.";
389 error(Error(Error::InternalServer,
390 QLatin1String("Plugin process - invalid operation code.")));
391 }
392
393 m_currentOperation = PLUGIN_OP_STOP;
394 connect(m_readnotifier, SIGNAL(activated(int)), this, SLOT(startTask()));
395 }
396
397 void RemotePluginProcess::enableCancelThread()
398 {
399 QEventLoop loop;
400 connect(cancelThread,
401 SIGNAL(started()),
402 &loop,
403 SLOT(quit()));
404
405 m_readnotifier->setEnabled(false);
406 QTimer::singleShot(0.5*1000, &loop, SLOT(quit()));
407 cancelThread->start();
408 loop.exec();
409 QThread::yieldCurrentThread();
410 }
411
412 void RemotePluginProcess::disableCancelThread()
413 {
414 if (!cancelThread->isRunning())
415 return;
416
423 cancelThread->quit();
424
425 TRACE() << "Before the isFinished loop ";
426
427 int i = 0;
428 while (!cancelThread->isFinished()) {
429 cancelThread->quit();
430 TRACE() << "Internal iteration " << i++;
431 usleep(0.005 * 1000000);
432 }
433
434 if (!cancelThread->wait(500)) {
435 BLAME() << "Cannot disable cancel thread";
436 int i;
437 for (i = 0; i < 5; i++) {
438 usleep(0.01 * 1000000);
439 if (cancelThread->wait(500))
440 break;
441 }
442
443 if (i == 5) {
444 BLAME() << "Cannot do anything with cancel thread";
445 cancelThread->terminate();
446 cancelThread->wait();
447 }
448 }
449
450 m_readnotifier->setEnabled(true);
451 }
452
453 void RemotePluginProcess::startTask()
454 {
455 quint32 opcode = PLUGIN_OP_STOP;
456 bool is_stopped = false;
457
458 QDataStream in(&m_inFile);
459 in >> opcode;
460
461 switch (opcode) {
462 case PLUGIN_OP_CANCEL:
463 {
464 m_plugin->cancel(); break;
465 //still do not have clear understanding
466 //of the cancelation-stop mechanism
467 //is_stopped = true;
468 }
469 break;
470 case PLUGIN_OP_TYPE:
471 type();
472 break;
473 case PLUGIN_OP_MECHANISMS:
474 mechanisms();
475 break;
476 case PLUGIN_OP_PROCESS:
477 process();
478 break;
479 case PLUGIN_OP_PROCESS_UI:
480 userActionFinished();
481 break;
482 case PLUGIN_OP_REFRESH:
483 refresh();
484 break;
485 case PLUGIN_OP_STOP:
486 is_stopped = true;
487 break;
488 default:
489 {
490 qCritical() << " unknown operation code: " << opcode;
491 is_stopped = true;
492 }
493 break;
494 };
495
496 TRACE() << "operation is completed";
497
498 if (!is_stopped) {
499 if (!m_outFile.flush())
500 is_stopped = true;
501 }
502
503 if (is_stopped)
504 {
505 m_plugin->abort();
506 emit processStopped();
507 }
508 }
509
510 CancelEventThread::CancelEventThread(AuthPluginInterface *plugin)
511 {
512 m_plugin = plugin;
513 m_cancelNotifier = 0;
514 }
515
516 CancelEventThread::~CancelEventThread()
517 {
518 delete m_cancelNotifier;
519 }
520
521 void CancelEventThread::run()
522 {
523 if (!m_cancelNotifier) {
524 m_cancelNotifier = new QSocketNotifier(STDIN_FILENO,
525 QSocketNotifier::Read);
526 connect(m_cancelNotifier, SIGNAL(activated(int)),
527 this, SLOT(cancel()), Qt::DirectConnection);
528 }
529
530 m_cancelNotifier->setEnabled(true);
531 exec();
532 m_cancelNotifier->setEnabled(false);
533 }
534
535 void CancelEventThread::cancel()
536 {
537 char buf[4];
538 memset(buf, 0, 4);
539 int n = 0;
540
541 if (!(n = read(STDIN_FILENO, buf, 4))) {
542 qCritical() << "Cannot read from cancel socket";
543 return;
544 }
545
546 /*
547 * Read the actual value of
548 * */
549 QByteArray ba(buf, 4);
550 quint32 opcode;
551 QDataStream ds(ba);
552 ds >> opcode;
553
554 if (opcode != PLUGIN_OP_CANCEL)
555 qCritical() << "wrong operation code: breakage of remotepluginprocess "
556 "threads synchronization: " << opcode;
557
558 m_plugin->cancel();
559 }
560
561 } //namespace RemotePluginProcessNS
562
RemotePluginProcessNS::RemotePluginProcess::setupProxySettings
bool setupProxySettings()
Definition: remotepluginprocess.cpp:184
SIGNON_PLUGIN_SUFFIX
#define SIGNON_PLUGIN_SUFFIX
Definition: remotepluginprocess.h:58
RemotePluginProcessNS::RemotePluginProcess::processStopped
void processStopped()
RemotePluginProcessNS::RemotePluginProcess::~RemotePluginProcess
~RemotePluginProcess()
Definition: remotepluginprocess.cpp:58
BLAME
#define BLAME()
Definition: debug.h:32
RemotePluginProcessNS::RemotePluginProcess::sessionDataReceived
void sessionDataReceived(const QVariantMap &sessionDataMap)
Definition: remotepluginprocess.cpp:369
debug.h
RemotePluginProcessNS::RemotePluginProcess::createRemotePluginProcess
static RemotePluginProcess * createRemotePluginProcess(QString &type, QObject *parent)
Definition: remotepluginprocess.cpp:72
RemotePluginProcessNS::RemotePluginProcess::loadPlugin
bool loadPlugin(QString &type)
Definition: remotepluginprocess.cpp:88
RemotePluginProcessNS::CancelEventThread
Thread to enable cancel functionality.
Definition: remotepluginprocess.h:73
MyNetworkProxyFactory
Definition: my-network-proxy-factory.h:28
RemotePluginProcessNS::RemotePluginProcess
Class to execute plugin process.
Definition: remotepluginprocess.h:95
SIGNON_PLUGIN_PREFIX
#define SIGNON_PLUGIN_PREFIX
Definition: remotepluginprocess.h:54
my-network-proxy-factory.h
RemotePluginProcessNS::CancelEventThread::cancel
void cancel()
Definition: remotepluginprocess.cpp:535
RemotePluginProcessNS::RemotePluginProcess::RemotePluginProcess
RemotePluginProcess(QObject *parent)
Definition: remotepluginprocess.cpp:47
RemotePluginProcessNS::CancelEventThread::~CancelEventThread
~CancelEventThread()
Definition: remotepluginprocess.cpp:516
TRACE
#define TRACE()
Definition: debug.h:28
remotepluginprocess.h
RemotePluginProcessNS::RemotePluginProcess::setupDataStreams
bool setupDataStreams()
Definition: remotepluginprocess.cpp:147
RemotePluginProcessNS::CancelEventThread::run
void run()
Definition: remotepluginprocess.cpp:521
SIGNOND_PLUGINS_DIR
#define SIGNOND_PLUGINS_DIR
Definition: remotepluginprocess.h:50
RemotePluginProcessNS::CancelEventThread::CancelEventThread
CancelEventThread(AuthPluginInterface *plugin)
Definition: remotepluginprocess.cpp:510
RemotePluginProcessNS::RemotePluginProcess::startTask
void startTask()
Definition: remotepluginprocess.cpp:453