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