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 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | using namespace QtRemoteObjects; |
18 | |
19 | class QtROFactoryLoader |
20 | { |
21 | public: |
22 | QtROClientFactory clientFactory; |
23 | QtROServerFactory serverFactory; |
24 | }; |
25 | |
26 | Q_GLOBAL_STATIC(QtROFactoryLoader, loader) |
27 | |
28 | inline 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 | */ |
63 | QtROIoDeviceBase::QtROIoDeviceBase(QObject *parent) : QObject(*new QtROIoDeviceBasePrivate, parent) { } |
64 | |
65 | QtROIoDeviceBase::QtROIoDeviceBase(QtROIoDeviceBasePrivate &dptr, QObject *parent) : QObject(dptr, parent) { } |
66 | |
67 | QtROIoDeviceBase::~QtROIoDeviceBase() |
68 | { |
69 | } |
70 | |
71 | bool 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 | |
93 | void QtROIoDeviceBase::write(const QByteArray &data) |
94 | { |
95 | Q_D(QtROIoDeviceBase); |
96 | if (connection()->isOpen() && !d->m_isClosing) |
97 | connection()->write(data); |
98 | } |
99 | |
100 | void 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 | |
107 | bool QtROIoDeviceBase::isOpen() const |
108 | { |
109 | return !isClosing(); |
110 | } |
111 | |
112 | void QtROIoDeviceBase::close() |
113 | { |
114 | Q_D(QtROIoDeviceBase); |
115 | d->m_isClosing = true; |
116 | doClose(); |
117 | } |
118 | |
119 | qint64 QtROIoDeviceBase::bytesAvailable() const |
120 | { |
121 | return connection()->bytesAvailable(); |
122 | } |
123 | |
124 | void QtROIoDeviceBase::initializeDataStream() |
125 | { |
126 | Q_D(QtROIoDeviceBase); |
127 | d->m_dataStream.setDevice(connection()); |
128 | d->m_dataStream.resetStatus(); |
129 | } |
130 | |
131 | bool QtROIoDeviceBase::isClosing() const |
132 | { |
133 | Q_D(const QtROIoDeviceBase); |
134 | return d->m_isClosing; |
135 | } |
136 | |
137 | void QtROIoDeviceBase::addSource(const QString &name) |
138 | { |
139 | Q_D(QtROIoDeviceBase); |
140 | d->m_remoteObjects.insert(value: name); |
141 | } |
142 | |
143 | void QtROIoDeviceBase::removeSource(const QString &name) |
144 | { |
145 | Q_D(QtROIoDeviceBase); |
146 | d->m_remoteObjects.remove(value: name); |
147 | } |
148 | |
149 | QSet<QString> QtROIoDeviceBase::remoteObjects() const |
150 | { |
151 | Q_D(const QtROIoDeviceBase); |
152 | return d->m_remoteObjects; |
153 | } |
154 | |
155 | QtROClientIoDevice::QtROClientIoDevice(QObject *parent) : QtROIoDeviceBase(*new QtROClientIoDevicePrivate, parent) |
156 | { |
157 | } |
158 | |
159 | QtROClientIoDevice::~QtROClientIoDevice() |
160 | { |
161 | if (!isClosing()) |
162 | close(); |
163 | } |
164 | |
165 | void QtROClientIoDevice::disconnectFromServer() |
166 | { |
167 | doDisconnectFromServer(); |
168 | emit shouldReconnect(this); |
169 | } |
170 | |
171 | QUrl QtROClientIoDevice::url() const |
172 | { |
173 | Q_D(const QtROClientIoDevice); |
174 | return d->m_url; |
175 | } |
176 | |
177 | QString QtROClientIoDevice::deviceType() const |
178 | { |
179 | return QStringLiteral("QtROClientIoDevice" ); |
180 | } |
181 | |
182 | void 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 | */ |
193 | QtROServerIoDevice::QtROServerIoDevice(QObject *parent) : QtROIoDeviceBase(parent) |
194 | { |
195 | } |
196 | |
197 | QString QtROServerIoDevice::deviceType() const |
198 | { |
199 | return QStringLiteral("QtROServerIoDevice" ); |
200 | } |
201 | |
202 | QConnectionAbstractServer::QConnectionAbstractServer(QObject *parent) |
203 | : QObject(parent) |
204 | { |
205 | } |
206 | |
207 | QConnectionAbstractServer::~QConnectionAbstractServer() |
208 | { |
209 | } |
210 | |
211 | QtROServerIoDevice *QConnectionAbstractServer::nextPendingConnection() |
212 | { |
213 | QtROServerIoDevice *iodevice = configureNewConnection(); |
214 | iodevice->initializeDataStream(); |
215 | return iodevice; |
216 | } |
217 | |
218 | QtROExternalIoDevice::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 | |
230 | QIODevice *QtROExternalIoDevice::connection() const |
231 | { |
232 | Q_D(const QtROExternalIoDevice); |
233 | return d->m_device; |
234 | } |
235 | |
236 | bool 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 | |
244 | void QtROExternalIoDevice::doClose() |
245 | { |
246 | Q_D(QtROExternalIoDevice); |
247 | if (isOpen()) |
248 | d->m_device->close(); |
249 | } |
250 | |
251 | QString 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 | */ |
261 | QtROServerFactory::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 | |
273 | QtROServerFactory *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 | */ |
283 | QtROClientFactory::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 | |
295 | QtROClientFactory *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 | |
354 | QtROIoDeviceBasePrivate::QtROIoDeviceBasePrivate() : QObjectPrivate() |
355 | { |
356 | m_dataStream.setVersion(dataStreamVersion); |
357 | m_dataStream.setByteOrder(QDataStream::LittleEndian); |
358 | } |
359 | |
360 | QT_END_NAMESPACE |
361 | |