1 /****************************************************************************
2 **
3 ** Copyright (C) 2017-2015 Ford Motor Company
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtRemoteObjects module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qconnectionfactories_p.h"
41 #include "qconnectionfactories_p.h"
42
43 // BEGIN: Backends
44 #if defined(Q_OS_QNX)
45 #include "qconnection_qnx_backend_p.h"
46 #endif
47 #include "qconnection_local_backend_p.h"
48 #include "qconnection_tcpip_backend_p.h"
49 // END: Backends
50
51 QT_BEGIN_NAMESPACE
52
53 using namespace QtRemoteObjects;
54
55 class QtROFactoryLoader
56 {
57 public:
58 QtROClientFactory clientFactory;
59 QtROServerFactory serverFactory;
60 };
61
Q_GLOBAL_STATIC(QtROFactoryLoader,loader)62 Q_GLOBAL_STATIC(QtROFactoryLoader, loader)
63
64 inline bool fromDataStream(QDataStream &in, QRemoteObjectPacketTypeEnum &type, QString &name)
65 {
66 quint16 _type;
67 in >> _type;
68 type = Invalid;
69 switch (_type) {
70 case Handshake: type = Handshake; break;
71 case InitPacket: type = InitPacket; break;
72 case InitDynamicPacket: type = InitDynamicPacket; break;
73 case AddObject: type = AddObject; break;
74 case RemoveObject: type = RemoveObject; break;
75 case InvokePacket: type = InvokePacket; break;
76 case InvokeReplyPacket: type = InvokeReplyPacket; break;
77 case PropertyChangePacket: type = PropertyChangePacket; break;
78 case ObjectList: type = ObjectList; break;
79 case Ping: type = Ping; break;
80 case Pong: type = Pong; break;
81 default:
82 qCWarning(QT_REMOTEOBJECT_IO) << "Invalid packet received" << _type;
83 }
84 if (type == Invalid)
85 return false;
86 if (type == ObjectList)
87 return true;
88 in >> name;
89 qCDebug(QT_REMOTEOBJECT_IO) << "Packet received of type" << type << "for object" << name;
90 return true;
91 }
92
93 /*!
94 All communication between nodes happens through some form of QIODevice with
95 an associated QDataStream to handle marshalling of Qt types. IoDeviceBase
96 is an abstract base class that provides a consistent interface to QtRO, yet
97 can be extended to support different types of QIODevice.
98 */
IoDeviceBase(QObject * parent)99 IoDeviceBase::IoDeviceBase(QObject *parent)
100 : QObject(parent), m_isClosing(false), m_curReadSize(0)
101 {
102 m_dataStream.setVersion(dataStreamVersion);
103 }
104
~IoDeviceBase()105 IoDeviceBase::~IoDeviceBase()
106 {
107 }
108
read(QRemoteObjectPacketTypeEnum & type,QString & name)109 bool IoDeviceBase::read(QRemoteObjectPacketTypeEnum &type, QString &name)
110 {
111 qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()" << m_curReadSize << bytesAvailable();
112
113 if (m_curReadSize == 0) {
114 if (bytesAvailable() < static_cast<int>(sizeof(quint32)))
115 return false;
116
117 m_dataStream >> m_curReadSize;
118 }
119
120 qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()-looking for map" << m_curReadSize << bytesAvailable();
121
122 if (bytesAvailable() < m_curReadSize)
123 return false;
124
125 m_curReadSize = 0;
126 return fromDataStream(m_dataStream, type, name);
127 }
128
write(const QByteArray & data)129 void IoDeviceBase::write(const QByteArray &data)
130 {
131 if (connection()->isOpen() && !m_isClosing)
132 connection()->write(data);
133 }
134
write(const QByteArray & data,qint64 size)135 void IoDeviceBase::write(const QByteArray &data, qint64 size)
136 {
137 if (connection()->isOpen() && !m_isClosing)
138 connection()->write(data.data(), size);
139 }
140
close()141 void IoDeviceBase::close()
142 {
143 m_isClosing = true;
144 doClose();
145 }
146
bytesAvailable() const147 qint64 IoDeviceBase::bytesAvailable() const
148 {
149 return connection()->bytesAvailable();
150 }
151
initializeDataStream()152 void IoDeviceBase::initializeDataStream()
153 {
154 m_dataStream.setDevice(connection());
155 m_dataStream.resetStatus();
156 }
157
addSource(const QString & name)158 void IoDeviceBase::addSource(const QString &name)
159 {
160 m_remoteObjects.insert(name);
161 }
162
removeSource(const QString & name)163 void IoDeviceBase::removeSource(const QString &name)
164 {
165 m_remoteObjects.remove(name);
166 }
167
remoteObjects() const168 QSet<QString> IoDeviceBase::remoteObjects() const
169 {
170 return m_remoteObjects;
171 }
172
ClientIoDevice(QObject * parent)173 ClientIoDevice::ClientIoDevice(QObject *parent) : IoDeviceBase(parent)
174 {
175 }
176
~ClientIoDevice()177 ClientIoDevice::~ClientIoDevice()
178 {
179 if (!m_isClosing)
180 close();
181 }
182
disconnectFromServer()183 void ClientIoDevice::disconnectFromServer()
184 {
185 doDisconnectFromServer();
186 emit shouldReconnect(this);
187 }
188
url() const189 QUrl ClientIoDevice::url() const
190 {
191 return m_url;
192 }
193
deviceType() const194 QString ClientIoDevice::deviceType() const
195 {
196 return QStringLiteral("ClientIoDevice");
197 }
198
199 /*!
200 The Qt servers create QIODevice derived classes from handleConnection. The
201 problem is that they behave differently, so this class adds some
202 consistency.
203 */
ServerIoDevice(QObject * parent)204 ServerIoDevice::ServerIoDevice(QObject *parent) : IoDeviceBase(parent)
205 {
206 }
207
deviceType() const208 QString ServerIoDevice::deviceType() const
209 {
210 return QStringLiteral("ServerIoDevice");
211 }
212
QConnectionAbstractServer(QObject * parent)213 QConnectionAbstractServer::QConnectionAbstractServer(QObject *parent)
214 : QObject(parent)
215 {
216 }
217
~QConnectionAbstractServer()218 QConnectionAbstractServer::~QConnectionAbstractServer()
219 {
220 }
221
nextPendingConnection()222 ServerIoDevice *QConnectionAbstractServer::nextPendingConnection()
223 {
224 ServerIoDevice *iodevice = configureNewConnection();
225 iodevice->initializeDataStream();
226 return iodevice;
227 }
228
ExternalIoDevice(QIODevice * device,QObject * parent)229 ExternalIoDevice::ExternalIoDevice(QIODevice *device, QObject *parent)
230 : IoDeviceBase(parent)
231 , m_device(device)
232 {
233 initializeDataStream();
234 connect(m_device.data(), &QIODevice::aboutToClose, this, [this]() { this->m_isClosing = true; });
235 connect(m_device.data(), &QIODevice::readyRead, this, &ExternalIoDevice::readyRead);
236 auto meta = device->metaObject();
237 if (-1 == meta->indexOfSignal(SIGNAL(disconnected())))
238 connect(m_device.data(), SIGNAL(disconnected()), this, SIGNAL(disconnected()));
239 }
240
connection() const241 QIODevice *ExternalIoDevice::connection() const
242 {
243 return m_device;
244 }
245
isOpen() const246 bool ExternalIoDevice::isOpen() const
247 {
248 if (!m_device)
249 return false;
250 return m_device->isOpen() && IoDeviceBase::isOpen();
251 }
252
doClose()253 void ExternalIoDevice::doClose()
254 {
255 if (isOpen())
256 m_device->close();
257 }
258
deviceType() const259 QString ExternalIoDevice::deviceType() const
260 {
261 return QStringLiteral("ExternalIoDevice");
262 }
263
264 /*!
265 \class QtROServerFactory
266 \inmodule QtRemoteObjects
267 \brief A class that holds information about server backends available on the Qt Remote Objects network.
268 */
QtROServerFactory()269 QtROServerFactory::QtROServerFactory()
270 {
271 #if defined(Q_OS_QNX)
272 registerType<QnxServerImpl>(QStringLiteral("qnx"));
273 #endif
274 registerType<LocalServerImpl>(QStringLiteral("local"));
275 registerType<TcpServerImpl>(QStringLiteral("tcp"));
276 }
277
instance()278 QtROServerFactory *QtROServerFactory::instance()
279 {
280 return &loader->serverFactory;
281 }
282
283 /*!
284 \class QtROClientFactory
285 \inmodule QtRemoteObjects
286 \brief A class that holds information about client backends available on the Qt Remote Objects network.
287 */
QtROClientFactory()288 QtROClientFactory::QtROClientFactory()
289 {
290 #if defined(Q_OS_QNX)
291 registerType<QnxClientIo>(QStringLiteral("qnx"));
292 #endif
293 registerType<LocalClientIo>(QStringLiteral("local"));
294 registerType<TcpClientIo>(QStringLiteral("tcp"));
295 }
296
instance()297 QtROClientFactory *QtROClientFactory::instance()
298 {
299 return &loader->clientFactory;
300 }
301
302 /*!
303 \fn void qRegisterRemoteObjectsClient(const QString &id)
304 \relates QtROClientFactory
305
306 Registers the Remote Objects client \a id for the type \c{T}.
307
308 If you need a custom transport protocol for Qt Remote Objects, you need to
309 register the client & server implementation here.
310
311 \note This function requires that \c{T} is a fully defined type at the point
312 where the function is called.
313
314 This example registers the class \c{CustomClientIo} as \c{"myprotocol"}:
315
316 \code
317 qRegisterRemoteObjectsClient<CustomClientIo>(QStringLiteral("myprotocol"));
318 \endcode
319
320 With this in place, you can now instantiate nodes using this new custom protocol:
321
322 \code
323 QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry")));
324 \endcode
325
326 \sa {qRegisterRemoteObjectsServer}
327 */
328
329 /*!
330 \fn void qRegisterRemoteObjectsServer(const QString &id)
331 \relates QtROServerFactory
332
333 Registers the Remote Objects server \a id for the type \c{T}.
334
335 If you need a custom transport protocol for Qt Remote Objects, you need to
336 register the client & server implementation here.
337
338 \note This function requires that \c{T} is a fully defined type at the point
339 where the function is called.
340
341 This example registers the class \c{CustomServerImpl} as \c{"myprotocol"}:
342
343 \code
344 qRegisterRemoteObjectsServer<CustomServerImpl>(QStringLiteral("myprotocol"));
345 \endcode
346
347 With this in place, you can now instantiate nodes using this new custom protocol:
348
349 \code
350 QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry")));
351 \endcode
352
353 \sa {qRegisterRemoteObjectsServer}
354 */
355
356 QT_END_NAMESPACE
357