/**************************************************************************** ** ** Copyright (C) 2017-2015 Ford Motor Company ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtRemoteObjects module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qconnectionfactories_p.h" #include "qconnectionfactories_p.h" // BEGIN: Backends #if defined(Q_OS_QNX) #include "qconnection_qnx_backend_p.h" #endif #include "qconnection_local_backend_p.h" #include "qconnection_tcpip_backend_p.h" // END: Backends QT_BEGIN_NAMESPACE using namespace QtRemoteObjects; class QtROFactoryLoader { public: QtROClientFactory clientFactory; QtROServerFactory serverFactory; }; Q_GLOBAL_STATIC(QtROFactoryLoader, loader) inline bool fromDataStream(QDataStream &in, QRemoteObjectPacketTypeEnum &type, QString &name) { quint16 _type; in >> _type; type = Invalid; switch (_type) { case Handshake: type = Handshake; break; case InitPacket: type = InitPacket; break; case InitDynamicPacket: type = InitDynamicPacket; break; case AddObject: type = AddObject; break; case RemoveObject: type = RemoveObject; break; case InvokePacket: type = InvokePacket; break; case InvokeReplyPacket: type = InvokeReplyPacket; break; case PropertyChangePacket: type = PropertyChangePacket; break; case ObjectList: type = ObjectList; break; case Ping: type = Ping; break; case Pong: type = Pong; break; default: qCWarning(QT_REMOTEOBJECT_IO) << "Invalid packet received" << _type; } if (type == Invalid) return false; if (type == ObjectList) return true; in >> name; qCDebug(QT_REMOTEOBJECT_IO) << "Packet received of type" << type << "for object" << name; return true; } /*! All communication between nodes happens through some form of QIODevice with an associated QDataStream to handle marshalling of Qt types. IoDeviceBase is an abstract base class that provides a consistent interface to QtRO, yet can be extended to support different types of QIODevice. */ IoDeviceBase::IoDeviceBase(QObject *parent) : QObject(parent), m_isClosing(false), m_curReadSize(0) { m_dataStream.setVersion(dataStreamVersion); } IoDeviceBase::~IoDeviceBase() { } bool IoDeviceBase::read(QRemoteObjectPacketTypeEnum &type, QString &name) { qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()" << m_curReadSize << bytesAvailable(); if (m_curReadSize == 0) { if (bytesAvailable() < static_cast(sizeof(quint32))) return false; m_dataStream >> m_curReadSize; } qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()-looking for map" << m_curReadSize << bytesAvailable(); if (bytesAvailable() < m_curReadSize) return false; m_curReadSize = 0; return fromDataStream(m_dataStream, type, name); } void IoDeviceBase::write(const QByteArray &data) { if (connection()->isOpen() && !m_isClosing) connection()->write(data); } void IoDeviceBase::write(const QByteArray &data, qint64 size) { if (connection()->isOpen() && !m_isClosing) connection()->write(data.data(), size); } void IoDeviceBase::close() { m_isClosing = true; doClose(); } qint64 IoDeviceBase::bytesAvailable() const { return connection()->bytesAvailable(); } void IoDeviceBase::initializeDataStream() { m_dataStream.setDevice(connection()); m_dataStream.resetStatus(); } void IoDeviceBase::addSource(const QString &name) { m_remoteObjects.insert(name); } void IoDeviceBase::removeSource(const QString &name) { m_remoteObjects.remove(name); } QSet IoDeviceBase::remoteObjects() const { return m_remoteObjects; } ClientIoDevice::ClientIoDevice(QObject *parent) : IoDeviceBase(parent) { } ClientIoDevice::~ClientIoDevice() { if (!m_isClosing) close(); } void ClientIoDevice::disconnectFromServer() { doDisconnectFromServer(); emit shouldReconnect(this); } QUrl ClientIoDevice::url() const { return m_url; } QString ClientIoDevice::deviceType() const { return QStringLiteral("ClientIoDevice"); } /*! The Qt servers create QIODevice derived classes from handleConnection. The problem is that they behave differently, so this class adds some consistency. */ ServerIoDevice::ServerIoDevice(QObject *parent) : IoDeviceBase(parent) { } QString ServerIoDevice::deviceType() const { return QStringLiteral("ServerIoDevice"); } QConnectionAbstractServer::QConnectionAbstractServer(QObject *parent) : QObject(parent) { } QConnectionAbstractServer::~QConnectionAbstractServer() { } ServerIoDevice *QConnectionAbstractServer::nextPendingConnection() { ServerIoDevice *iodevice = configureNewConnection(); iodevice->initializeDataStream(); return iodevice; } ExternalIoDevice::ExternalIoDevice(QIODevice *device, QObject *parent) : IoDeviceBase(parent) , m_device(device) { initializeDataStream(); connect(m_device.data(), &QIODevice::aboutToClose, this, [this]() { this->m_isClosing = true; }); connect(m_device.data(), &QIODevice::readyRead, this, &ExternalIoDevice::readyRead); auto meta = device->metaObject(); if (-1 == meta->indexOfSignal(SIGNAL(disconnected()))) connect(m_device.data(), SIGNAL(disconnected()), this, SIGNAL(disconnected())); } QIODevice *ExternalIoDevice::connection() const { return m_device; } bool ExternalIoDevice::isOpen() const { if (!m_device) return false; return m_device->isOpen() && IoDeviceBase::isOpen(); } void ExternalIoDevice::doClose() { if (isOpen()) m_device->close(); } QString ExternalIoDevice::deviceType() const { return QStringLiteral("ExternalIoDevice"); } /*! \class QtROServerFactory \inmodule QtRemoteObjects \brief A class that holds information about server backends available on the Qt Remote Objects network. */ QtROServerFactory::QtROServerFactory() { #if defined(Q_OS_QNX) registerType(QStringLiteral("qnx")); #endif registerType(QStringLiteral("local")); registerType(QStringLiteral("tcp")); } QtROServerFactory *QtROServerFactory::instance() { return &loader->serverFactory; } /*! \class QtROClientFactory \inmodule QtRemoteObjects \brief A class that holds information about client backends available on the Qt Remote Objects network. */ QtROClientFactory::QtROClientFactory() { #if defined(Q_OS_QNX) registerType(QStringLiteral("qnx")); #endif registerType(QStringLiteral("local")); registerType(QStringLiteral("tcp")); } QtROClientFactory *QtROClientFactory::instance() { return &loader->clientFactory; } /*! \fn void qRegisterRemoteObjectsClient(const QString &id) \relates QtROClientFactory Registers the Remote Objects client \a id for the type \c{T}. If you need a custom transport protocol for Qt Remote Objects, you need to register the client & server implementation here. \note This function requires that \c{T} is a fully defined type at the point where the function is called. This example registers the class \c{CustomClientIo} as \c{"myprotocol"}: \code qRegisterRemoteObjectsClient(QStringLiteral("myprotocol")); \endcode With this in place, you can now instantiate nodes using this new custom protocol: \code QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry"))); \endcode \sa {qRegisterRemoteObjectsServer} */ /*! \fn void qRegisterRemoteObjectsServer(const QString &id) \relates QtROServerFactory Registers the Remote Objects server \a id for the type \c{T}. If you need a custom transport protocol for Qt Remote Objects, you need to register the client & server implementation here. \note This function requires that \c{T} is a fully defined type at the point where the function is called. This example registers the class \c{CustomServerImpl} as \c{"myprotocol"}: \code qRegisterRemoteObjectsServer(QStringLiteral("myprotocol")); \endcode With this in place, you can now instantiate nodes using this new custom protocol: \code QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry"))); \endcode \sa {qRegisterRemoteObjectsServer} */ QT_END_NAMESPACE