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 | |
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 | */ |
99 | IoDeviceBase::IoDeviceBase(QObject *parent) |
100 | : QObject(parent), m_isClosing(false), m_curReadSize(0) |
101 | { |
102 | m_dataStream.setVersion(dataStreamVersion); |
103 | } |
104 | |
105 | IoDeviceBase::~IoDeviceBase() |
106 | { |
107 | } |
108 | |
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(in&: m_dataStream, type, name); |
127 | } |
128 | |
129 | void IoDeviceBase::write(const QByteArray &data) |
130 | { |
131 | if (connection()->isOpen() && !m_isClosing) |
132 | connection()->write(data); |
133 | } |
134 | |
135 | void IoDeviceBase::write(const QByteArray &data, qint64 size) |
136 | { |
137 | if (connection()->isOpen() && !m_isClosing) |
138 | connection()->write(data: data.data(), len: size); |
139 | } |
140 | |
141 | void IoDeviceBase::close() |
142 | { |
143 | m_isClosing = true; |
144 | doClose(); |
145 | } |
146 | |
147 | qint64 IoDeviceBase::bytesAvailable() const |
148 | { |
149 | return connection()->bytesAvailable(); |
150 | } |
151 | |
152 | void IoDeviceBase::initializeDataStream() |
153 | { |
154 | m_dataStream.setDevice(connection()); |
155 | m_dataStream.resetStatus(); |
156 | } |
157 | |
158 | void IoDeviceBase::addSource(const QString &name) |
159 | { |
160 | m_remoteObjects.insert(value: name); |
161 | } |
162 | |
163 | void IoDeviceBase::removeSource(const QString &name) |
164 | { |
165 | m_remoteObjects.remove(value: name); |
166 | } |
167 | |
168 | QSet<QString> IoDeviceBase::remoteObjects() const |
169 | { |
170 | return m_remoteObjects; |
171 | } |
172 | |
173 | ClientIoDevice::ClientIoDevice(QObject *parent) : IoDeviceBase(parent) |
174 | { |
175 | } |
176 | |
177 | ClientIoDevice::~ClientIoDevice() |
178 | { |
179 | if (!m_isClosing) |
180 | close(); |
181 | } |
182 | |
183 | void ClientIoDevice::disconnectFromServer() |
184 | { |
185 | doDisconnectFromServer(); |
186 | emit shouldReconnect(this); |
187 | } |
188 | |
189 | QUrl ClientIoDevice::url() const |
190 | { |
191 | return m_url; |
192 | } |
193 | |
194 | 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 | */ |
204 | ServerIoDevice::ServerIoDevice(QObject *parent) : IoDeviceBase(parent) |
205 | { |
206 | } |
207 | |
208 | QString ServerIoDevice::deviceType() const |
209 | { |
210 | return QStringLiteral("ServerIoDevice" ); |
211 | } |
212 | |
213 | QConnectionAbstractServer::QConnectionAbstractServer(QObject *parent) |
214 | : QObject(parent) |
215 | { |
216 | } |
217 | |
218 | QConnectionAbstractServer::~QConnectionAbstractServer() |
219 | { |
220 | } |
221 | |
222 | ServerIoDevice *QConnectionAbstractServer::nextPendingConnection() |
223 | { |
224 | ServerIoDevice *iodevice = configureNewConnection(); |
225 | iodevice->initializeDataStream(); |
226 | return iodevice; |
227 | } |
228 | |
229 | ExternalIoDevice::ExternalIoDevice(QIODevice *device, QObject *parent) |
230 | : IoDeviceBase(parent) |
231 | , m_device(device) |
232 | { |
233 | initializeDataStream(); |
234 | connect(sender: m_device.data(), signal: &QIODevice::aboutToClose, context: this, slot: [this]() { this->m_isClosing = true; }); |
235 | connect(sender: m_device.data(), signal: &QIODevice::readyRead, receiver: this, slot: &ExternalIoDevice::readyRead); |
236 | auto meta = device->metaObject(); |
237 | if (-1 != meta->indexOfSignal(SIGNAL(disconnected()))) |
238 | connect(sender: m_device.data(), SIGNAL(disconnected()), receiver: this, SIGNAL(disconnected())); |
239 | } |
240 | |
241 | QIODevice *ExternalIoDevice::connection() const |
242 | { |
243 | return m_device; |
244 | } |
245 | |
246 | bool ExternalIoDevice::isOpen() const |
247 | { |
248 | if (!m_device) |
249 | return false; |
250 | return m_device->isOpen() && IoDeviceBase::isOpen(); |
251 | } |
252 | |
253 | void ExternalIoDevice::doClose() |
254 | { |
255 | if (isOpen()) |
256 | m_device->close(); |
257 | } |
258 | |
259 | 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 | */ |
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 | |
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 | */ |
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 | |
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 | |