1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qremoteserviceregister.h"
35#include "qremoteserviceregisterentry_p.h"
36#include "ipc/instancemanager_p.h"
37#include "qremoteserviceregister_p.h"
38#include "qserviceclientcredentials_p.h"
39
40#include <QtCore/QDataStream>
41#include <QtCore/QEvent>
42
43QT_BEGIN_NAMESPACE
44
45/*!
46 \class QRemoteServiceRegister::Entry
47 \ingroup servicefw
48 \inmodule QtServiceFramework
49 \brief The Entry class represents a remote service entry to be published on QRemoteServiceRegister.
50
51 This class is created using QRemoteServiceRegister::createEntry to supply remote service
52 details matching a valid QServiceInterfaceDescriptor.
53
54 A registration entry can then be published for discovery by remote clients.
55
56*/
57
58/*!
59 Constructs a null registration entry.
60*/
61QRemoteServiceRegister::Entry::Entry()
62{
63 d = new QRemoteServiceRegisterEntryPrivate;
64}
65
66/*!
67 Constructs the registration entry that is a copy of \a other.
68*/
69QRemoteServiceRegister::Entry::Entry(const Entry& other)
70 : d(other.d)
71{
72}
73
74/*!
75 Destroys the registration entry.
76*/
77QRemoteServiceRegister::Entry::~Entry()
78{
79}
80
81/*!
82 Checks if the registration entry is currently a valid remote service entry
83
84 Returns true if the serviceName(), interfaceName() and version() point to
85 a valid QServiceInterfaceDescriptor, otherwise false.
86*/
87bool QRemoteServiceRegister::Entry::isValid() const
88{
89 if (!d->iface.isEmpty() && !d->service.isEmpty()
90 && !d->ifaceVersion.isEmpty() && d->cptr!=0 && d->meta!=0)
91 return true;
92 return false;
93}
94
95/*!
96 Returns true if this font is equal to \a other; otherwise false.
97*/
98bool QRemoteServiceRegister::Entry::operator==(const Entry& other) const
99{
100 return d->service == other.d->service &&
101 d->iface == other.d->iface &&
102 d->ifaceVersion == other.d->ifaceVersion;
103}
104
105/*!
106 Returns true if this font is different from \a other; otherwise false.
107*/
108bool QRemoteServiceRegister::Entry::operator!=(const Entry& other) const
109{
110 return !(other == *this);
111}
112
113/*!
114 Assigns \a other to this registration entry and returns a reference to it.
115*/
116QRemoteServiceRegister::Entry &QRemoteServiceRegister::Entry::operator=(const Entry& other)
117{
118 d = other.d;
119 return *this;
120}
121
122/*!
123 Returns the interface name of the registration entry.
124
125 This should correspond to the interface name from the service XML description.
126
127 \sa serviceName(), version()
128*/
129QString QRemoteServiceRegister::Entry::interfaceName() const
130{
131 return d->iface;
132}
133
134/*!
135 Returns the service name of the registration entry.
136
137 This should correspond to the service name from the service XML description.
138
139 \sa interfaceName(), version()
140*/
141QString QRemoteServiceRegister::Entry::serviceName() const
142{
143 return d->service;
144}
145
146/*!
147 Returns the version of the registration entry in format x.y.
148
149 This should correspond to the interface version from the service XML description.
150
151 \sa interfaceName(), serviceName()
152*/
153QString QRemoteServiceRegister::Entry::version() const
154{
155 return d->ifaceVersion;
156}
157
158const QMetaObject * QRemoteServiceRegister::Entry::metaObject() const
159{
160 return d->meta;
161}
162
163/*!
164 Sets the QRemoteServiceRegister::InstanceType of the registration entry.
165
166 If this is not explicitly called, the default instance \a type for the registration entry
167 is QRemoteServiceRegister::PrivateInstance.
168*/
169void QRemoteServiceRegister::Entry::setInstantiationType(QRemoteServiceRegister::InstanceType type)
170{
171 d->instanceType = type;
172}
173
174/*!
175 Returns the QRemoteServiceRegister::InstanceType of the registration entry.
176*/
177QRemoteServiceRegister::InstanceType QRemoteServiceRegister::Entry::instantiationType() const
178{
179 return d->instanceType;
180}
181
182/*!
183 \class QRemoteServiceRegister
184 \inmodule QtServiceFramework
185 \ingroup servicefw
186 \brief The QRemoteServiceRegister class manages instances of remote service objects.
187
188 This class registers and publishes IPC based service objects. It owns the service's
189 objects and uses the platform specific IPC mechanism to publish the service.
190
191 In order for the remote services to be discoverable by QServiceManager each
192 QRemoteServiceRegister::Entry must be registered with the same information in
193 the XML description, otherwise no corresponding QServiceInterfaceDescriptor can be
194 found.
195
196 The following XML descriptor is used for subsequent examples.
197
198 \code
199 <SFW version="1.1">
200 <service>
201 <name>MyService</name>
202 <ipcaddress>my_executable</ipcaddress>
203 <description>My service example</description>
204 <interface>
205 <name>com.nokia.qt.example.myService</name>
206 <version>1.0</version>
207 <description>My private service</description>
208 <capabilities></capabilities>
209 </interface>
210 </service>
211 </SFW>
212 \endcode
213
214 The snippet belows demonstrates how an application can register the class \a MyClass
215 as a remote service, which is published and accessible to clients who wish to load
216 service object instances.
217
218 \code
219 int main(int argc, char** argv)
220 {
221 QCoreApplication app(argc, argv);
222
223 QRemoteServiceRegister *serviceRegister = new QRemoteServiceRegister();
224
225 QRemoteServiceRegister::Entry myService;
226 myService = serviceRegister->createEntry<MyClass>(
227 "MyService", "com.nokia.qt.example.myservice", "1.0");
228
229 serviceRegister->publishEntries("my_service");
230
231 return app.exec();
232 delete serviceRegister;
233 }
234 \endcode
235
236 By default all entries are created as \l QRemoteServiceRegister::PrivateInstance
237 types. This can be changed by calling QRemoteServiceRegister::Entry::setInstantiationType()
238 on the entry. Once the service register has been published the associated service entries
239 can no longer be changed.
240
241 \sa QRemoteServiceRegister::Entry
242*/
243
244/*!
245 \enum QRemoteServiceRegister::InstanceType
246 Defines the two types of instances for a registration entry
247 \value GlobalInstance New requests for a service gets the same service instance
248 \value PrivateInstance New requests for a service gets a new service instance
249*/
250
251/*!
252 \fn void QRemoteServiceRegister::instanceClosed(const QRemoteServiceRegister::Entry& entry)
253
254 This signal is emitted whenever a created instance has been closed. This indicates
255 that a connected client has either shutdown or released the loaded service object.
256
257 \a entry is supplied to identify which registered service
258 entry the closed instance belonged to.
259
260 \sa allInstancesClosed()
261*/
262
263/*!
264 \fn void QRemoteServiceRegister::allInstancesClosed()
265
266 This signal is emitted whenever all service instances have been closed. This indicates
267 that the last connected client has either shutdown or released the loaded service object.
268
269 \sa instanceClosed()
270*/
271
272/*!
273 \typedef QRemoteServiceRegister::CreateServiceFunc
274 \internal
275 Denotes a function pointer returning a service instance
276*/
277
278/*!
279 \typedef QRemoteServiceRegister::SecurityFilter
280 \internal
281 Denotes a function pointer used for the security filter feature
282*/
283
284/*!
285 Creates a service register instance with the given \a parent.
286*/
287QRemoteServiceRegister::QRemoteServiceRegister(QObject* parent)
288 : QObject(parent)
289 , d(0)
290{
291 connect(sender: InstanceManager::instance(), SIGNAL(allInstancesClosed()),
292 receiver: this, SIGNAL(allInstancesClosed()));
293 connect(sender: InstanceManager::instance(), SIGNAL(instanceClosed(QRemoteServiceRegister::Entry)),
294 receiver: this, SIGNAL(instanceClosed(QRemoteServiceRegister::Entry)));
295}
296
297/*!
298 Destroys the service register instance
299*/
300QRemoteServiceRegister::~QRemoteServiceRegister()
301{
302}
303
304/*!
305 Publishes every service QRemoteServiceRegister::Entry that has been created using
306 \l createEntry(). The \a ident is the service specific IPC address under which
307 the service can be reached.
308
309 This address must match the address provided in the services XML descriptor, otherwise
310 the service will not be discoverable. In some cases this may also cause the IPC
311 rendezvous feature to fail.
312
313 \sa createEntry()
314*/
315void QRemoteServiceRegister::publishEntries(const QString& ident)
316{
317 if (!d) init();
318 d->publishServices(ident);
319}
320
321/*!
322 \property QRemoteServiceRegister::quitOnLastInstanceClosed
323
324 \brief Terminate the service when all clients have closed all objects. Default value is true.
325*/
326bool QRemoteServiceRegister::quitOnLastInstanceClosed() const
327{
328 if (!d) const_cast<QRemoteServiceRegister*>(this)->init();
329 return d->quitOnLastInstanceClosed();
330}
331
332void QRemoteServiceRegister::setQuitOnLastInstanceClosed(bool quit)
333{
334 if (!d) init();
335 d->setQuitOnLastInstanceClosed(quit);
336}
337
338/*!
339 \since 5.0
340
341 Set the user id for the socket or pipe. For backends that use sockets or
342 pipes and provide filesystem based access control.
343
344 */
345
346void QRemoteServiceRegister::setBaseUserIdentifier(qintptr uid)
347{
348 if (!d) init();
349 d->setBaseUserIdentifier(uid);
350}
351
352/*!
353 \since 5.0
354
355 Get the user id set on the socket or pipe.
356*/
357
358qintptr QRemoteServiceRegister::getBaseUserIdentifier() const
359{
360 if (!d) const_cast<QRemoteServiceRegister*>(this)->init();
361 return d->getBaseUserIdentifier();
362}
363
364/*!
365 \since 5.0
366
367 Set the group id for the socket or pipe. For backends that use sockets or
368 pipes and provide filesystem based access control.
369 */
370
371void QRemoteServiceRegister::setBaseGroupIdentifier(qintptr gid)
372{
373 if (!d) init();
374 d->setBaseGroupIdentifier(gid);
375}
376
377/*!
378 \since 5.0
379
380 Get the group id set on the socket or pipe.
381*/
382
383qintptr QRemoteServiceRegister::getBaseGroupIdentifier() const
384{
385 if (!d) const_cast<QRemoteServiceRegister*>(this)->init();
386 return d->getBaseGroupIdentifier();
387}
388
389/*!
390 \since 5.0
391
392 Set the socket access control. This sets the file
393 system permissions on that socket.
394
395 */
396
397void QRemoteServiceRegister::setSecurityAccessOptions(SecurityAccessOptions options)
398{
399 if (!d) init();
400 d->setSecurityOptions(options);
401}
402
403/*!
404 Allows a security filter to be set which can access
405 QRemoteServiceRegister::QRemoteServiceRegisterCredentials.
406
407 The \a filter is a function pointer where the function code implements possible
408 permission checks and returns true or false. If a connecting client fails the security
409 filter it will be denied access and unable to obtain a valid service instance.
410
411 The following snippet is an example of how to use the security filter feature.
412
413 \code
414 bool myFunction(const void *p)
415 {
416 const QRemoteServiceRegisterCredentials *cred =
417 (const struct QRemoteServiceRegisterCredentials *)p;
418
419 // allow the superuser
420 if (cred->uid == 0)
421 return true;
422
423 return false;
424 }
425
426 int main(int argc, char** argv)
427 {
428 ...
429
430 QRemoteServiceRegister* serviceRegister = new QRemoteServiceRegister();
431 service->setSecurityFilter(myFunction);
432
433 ...
434 }
435 \endcode
436
437*/
438QRemoteServiceRegister::SecurityFilter QRemoteServiceRegister::setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter)
439{
440 if (!d) init();
441 return d->setSecurityFilter(filter);
442}
443
444/*!
445 \fn QRemoteServiceRegister::createEntry(const QString& serviceName, const QString& interfaceName, const QString& version)
446
447 Creates an entry on our remote instance manager. The \a serviceName, \a interfaceName and
448 \a version must match the service XML descriptor in order for the remote service to be
449 discoverable.
450
451 \sa publishEntries()
452*/
453QRemoteServiceRegister::Entry QRemoteServiceRegister::createEntry(const QString& serviceName, const QString& interfaceName, const QString& version, QRemoteServiceRegister::CreateServiceFunc cptr, const QMetaObject* meta)
454{
455 if (serviceName.isEmpty()
456 || interfaceName.isEmpty()
457 || version.isEmpty() ) {
458 qWarning() << "QRemoteServiceRegister::registerService: service name, interface name and version must be specified";
459 return Entry();
460 }
461
462 Entry e;
463 e.d->service = serviceName;
464 e.d->iface = interfaceName;
465 e.d->ifaceVersion = version;
466 e.d->cptr = cptr;
467 e.d->meta = meta;
468
469 Q_ASSERT(InstanceManager::instance());
470 InstanceManager::instance()->addType(entry: e);
471
472 return e;
473}
474
475bool QRemoteServiceRegister::event(QEvent *e)
476{
477 if (!d && e->type() == QEvent::DynamicPropertyChange) {
478 QDynamicPropertyChangeEvent *event = static_cast<QDynamicPropertyChangeEvent*>(e);
479 if (event->propertyName() == QByteArray("serviceType")) {
480 QService::Type serviceType = static_cast<QService::Type>(property(name: "serviceType").toInt());
481 d = QRemoteServiceRegisterPrivate::constructPrivateObject(serviceType, parent: this);
482 }
483 }
484
485 return QObject::event(event: e);
486}
487
488void QRemoteServiceRegister::init()
489{
490 d = QRemoteServiceRegisterPrivate::constructPrivateObject(parent: this);
491}
492
493#ifndef QT_NO_DATASTREAM
494Q_SERVICEFW_EXPORT QDataStream& operator>>(QDataStream& s, QRemoteServiceRegister::Entry& entry) {
495 //for now we only serialize version, iface and service name
496 //needs to sync with qHash and operator==
497 s >> entry.d->service >> entry.d->iface >> entry.d->ifaceVersion;
498 return s;
499}
500
501Q_SERVICEFW_EXPORT QDataStream& operator<<(QDataStream& s, const QRemoteServiceRegister::Entry& entry) {
502 //for now we only serialize version, iface and service name
503 //needs to sync with qHash and operator==
504 s << entry.d->service << entry.d->iface << entry.d->ifaceVersion;
505 return s;
506}
507#endif
508
509#ifndef QT_NO_DEBUG_STREAM
510QDebug operator<<(QDebug dbg, const QRemoteServiceRegister::Entry& entry) {
511 dbg.nospace() << "QRemoteServiceRegister::Entry("
512 << entry.serviceName() << ", "
513 << entry.interfaceName() << ", "
514 << entry.version() << ")";
515 return dbg.space();
516}
517#endif
518
519#include "moc_qremoteserviceregister.cpp"
520
521QT_END_NAMESPACE
522

source code of qtsystems/src/serviceframework/qremoteserviceregister.cpp