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

source code of qtremoteobjects/src/remoteobjects/qconnectionfactories.cpp