Skip to content

Commit

Permalink
Merge pull request emqx#119 from ejvr/emqtt
Browse files Browse the repository at this point in the history
Support for websockets & minor changes
  • Loading branch information
mwallnoefer authored Oct 2, 2017
2 parents abe5cf6 + 299df0b commit 3b22b35
Show file tree
Hide file tree
Showing 16 changed files with 414 additions and 23 deletions.
13 changes: 9 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
language: cpp
compiler:
- gcc

before_install:
- sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-add-repository -y ppa:beineri/opt-qt56
- sudo apt-add-repository -y ppa:beineri/opt-qt571-trusty
- sudo apt-get update -qq
- sudo apt-get install -qq qt56base qt56tools g++-4.8
- source /opt/qt56/bin/qt56-env.sh
- export CXX="g++-4.8"
- sudo apt-get install -qq qt57base qt57tools qt57websockets g++-5
- source /opt/qt57/bin/qt57-env.sh
- export CXX="g++-5"
- export CC="gcc-5"

script:
- qmake --version
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mqtt client for Qt

**Please compile the library with Qt >= 5.3 version. On Windows you need to specify `CONFIG += NO_UNIT_TESTS`, since gtest is not supported.**

To add websocket support, compile the library with Qt >= 5.7, and specify 'CONFIG += QMQTT_WEBSOCKETS'.

Usage
=====

Expand All @@ -16,6 +18,24 @@ Usage
client->setPassword("password");
client->connectToHost();

Connect using ssl:

QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
// Add custom SSL options here (for example extra certificates)
QMQTT::Client *client = new QMQTT::Client("example.com", 8883, sslConfig);
client->setClientId("clientId");
client->setUsername("user");
client->setPassword("password");
client->connectToHost();

Connect using websockets:

QMQTT::Client *client = new QMQTT::Client("ws://www.example.com/mqtt", "<origin>", QWebSocketProtocol::VersionLatest);
client->setClientId("clientId");
client->setUsername("user");
client->setPassword("password");
client->connectToHost();

Slots
=====

Expand Down
8 changes: 6 additions & 2 deletions src/mqtt/mqtt.pri
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ PRIVATE_HEADERS += \
$$PWD/qmqtt_network_p.h \
$$PWD/qmqtt_socket_p.h \
$$PWD/qmqtt_ssl_socket_p.h \
$$PWD/qmqtt_timer_p.h
$$PWD/qmqtt_timer_p.h \
$$PWD/qmqtt_websocket_p.h \
$$PWD/qmqtt_websocketiodevice_p.h

SOURCES += \
$$PWD/qmqtt_client_p.cpp \
Expand All @@ -29,4 +31,6 @@ SOURCES += \
$$PWD/qmqtt_router.cpp \
$$PWD/qmqtt_socket.cpp \
$$PWD/qmqtt_ssl_socket.cpp \
$$PWD/qmqtt_timer.cpp
$$PWD/qmqtt_timer.cpp \
$$PWD/qmqtt_websocket.cpp \
$$PWD/qmqtt_websocketiodevice.cpp
1 change: 1 addition & 0 deletions src/mqtt/mqtt.pro
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
TARGET = qmqtt
QT = core network
QMQTT_WEBSOCKETS: QT += websockets

DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII

Expand Down
28 changes: 20 additions & 8 deletions src/mqtt/mqtt.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Product {
libraryType,
"mqttmodule",
]
property bool webSocketSupport: false
property string libraryType: "dynamiclibrary"
targetName: "qmqtt"

Expand Down Expand Up @@ -87,10 +88,16 @@ Product {

Depends {
name: "Qt"
submodules: [
"core",
"network",
]
property var baseModules: ["core", "network"]

Properties {
condition: webSocketSupport
submodules: baseModules.concat(["websockets"])
}
Properties {
condition: !webSocketSupport
submodules: baseModules
}
}

Export {
Expand All @@ -100,10 +107,15 @@ Product {

Depends {
name: "Qt"
submodules: [
"core",
"network",
]
property var baseModules: ["core", "network"]
Properties {
condition: product.webSocketSupport
submodules: baseModules.concat(["websockets"])
}
Properties {
condition: !product.webSocketSupport
submodules: baseModules
}
}

cpp.includePaths: product.sourceDirectory
Expand Down
14 changes: 14 additions & 0 deletions src/mqtt/qmqtt_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ QMQTT::Client::Client(const QString &hostName,
d->init(hostName, port, ssl, ignoreSelfSigned);
}

#ifdef QT_WEBSOCKETS_LIB
QMQTT::Client::Client(const QString& url,
const QString& origin,
QWebSocketProtocol::Version version,
bool ignoreSelfSigned,
QObject* parent)
: QObject(parent)
, d_ptr(new ClientPrivate(this))
{
Q_D(Client);
d->init(url, origin, version, ignoreSelfSigned);
}
#endif // QT_WEBSOCKETS_LIB

QMQTT::Client::Client(NetworkInterface* network,
const QHostAddress& host,
const quint16 port,
Expand Down
13 changes: 13 additions & 0 deletions src/mqtt/qmqtt_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#include <QScopedPointer>
#include <QHostAddress>

#ifdef QT_WEBSOCKETS_LIB
#include <QWebSocket>
#endif // QT_WEBSOCKETS_LIB

#ifndef QT_NO_SSL
QT_FORWARD_DECLARE_CLASS(QSslConfiguration)
#endif // QT_NO_SSL
Expand Down Expand Up @@ -140,6 +144,15 @@ class Q_MQTT_EXPORT Client : public QObject
const bool ignoreSelfSigned,
QObject* parent = NULL);

#ifdef QT_WEBSOCKETS_LIB
// Create a connection over websockets
Client(const QString& url,
const QString& origin,
QWebSocketProtocol::Version version,
bool ignoreSelfSigned = false,
QObject* parent = NULL);
#endif // QT_WEBSOCKETS_LIB

// for testing purposes only
Client(NetworkInterface* network,
const QHostAddress& host = QHostAddress::LocalHost,
Expand Down
9 changes: 9 additions & 0 deletions src/mqtt/qmqtt_client_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ void QMQTT::ClientPrivate::init(const QString& hostName, const quint16 port, con
}
}

#ifdef QT_WEBSOCKETS_LIB
void QMQTT::ClientPrivate::init(const QString& url, const QString& origin,
QWebSocketProtocol::Version version, bool ignoreSelfSigned)
{
_hostName = url;
init(new Network(origin, version, ignoreSelfSigned));
}
#endif // QT_WEBSOCKETS_LIB

void QMQTT::ClientPrivate::init(NetworkInterface* network)
{
Q_Q(Client);
Expand Down
11 changes: 11 additions & 0 deletions src/mqtt/qmqtt_client_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#include "qmqtt_network_p.h"
#include <QTimer>

#ifdef QT_WEBSOCKETS_LIB
#include <QWebSocket>
#endif // QT_WEBSOCKETS_LIB

#ifndef QT_NO_SSL
QT_FORWARD_DECLARE_CLASS(QSslConfiguration)
#endif // QT_NO_SSL
Expand All @@ -55,11 +59,18 @@ class ClientPrivate
const bool ignoreSelfSigned=false);
#endif // QT_NO_SSL
void init(const QString& hostName, const quint16 port, const bool ssl, const bool ignoreSelfSigned);
#ifdef QT_WEBSOCKETS_LIB
void init(const QString& url, const QString &origin, QWebSocketProtocol::Version version,
bool ignoreSelfSigned);
#endif // QT_WEBSOCKETS_LIB
void init(NetworkInterface* network);

QHostAddress _host;
QString _hostName;
quint16 _port;
#ifdef QT_WEBSOCKETS_LIB
QWebSocketProtocol::Version _webSocketVersion;
#endif // QT_WEBSOCKETS_LIB
quint16 _gmid;
MQTTVersion _version;
QString _clientId;
Expand Down
17 changes: 17 additions & 0 deletions src/mqtt/qmqtt_network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "qmqtt_socket_p.h"
#include "qmqtt_ssl_socket_p.h"
#include "qmqtt_timer_p.h"
#include "qmqtt_websocket_p.h"

const QString DEFAULT_HOST_NAME = QStringLiteral("localhost");
const QHostAddress DEFAULT_HOST = QHostAddress::LocalHost;
Expand Down Expand Up @@ -70,6 +71,22 @@ QMQTT::Network::Network(const QSslConfiguration &config, bool ignoreSelfSigned,
}
#endif // QT_NO_SSL

#ifdef QT_WEBSOCKETS_LIB
QMQTT::Network::Network(const QString& origin, QWebSocketProtocol::Version version,
bool ignoreSelfSigned, QObject* parent)
: NetworkInterface(parent)
, _port(DEFAULT_SSL_PORT)
, _hostName(DEFAULT_HOST_NAME)
, _autoReconnect(DEFAULT_AUTORECONNECT)
, _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
, _socket(new QMQTT::WebSocket(origin, version, ignoreSelfSigned))
, _autoReconnectTimer(new QMQTT::Timer)
, _readState(Header)
{
initialize();
}
#endif // QT_WEBSOCKETS_LIB

QMQTT::Network::Network(SocketInterface* socketInterface, TimerInterface* timerInterface,
QObject* parent)
: NetworkInterface(parent)
Expand Down
8 changes: 8 additions & 0 deletions src/mqtt/qmqtt_network_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
#include <QByteArray>
#include <QHostAddress>

#ifdef QT_WEBSOCKETS_LIB
#include <QWebSocket>
#endif // QT_WEBSOCKETS_LIB

#ifndef QT_NO_SSL
QT_FORWARD_DECLARE_CLASS(QSslConfiguration)
#endif // QT_NO_SSL
Expand All @@ -58,6 +62,10 @@ class Network : public NetworkInterface
#ifndef QT_NO_SSL
Network(const QSslConfiguration& config, bool ignoreSelfSigned, QObject* parent = NULL);
#endif // QT_NO_SSL
#ifdef QT_WEBSOCKETS_LIB
Network(const QString& origin, QWebSocketProtocol::Version version, bool ignoreSelfSigned,
QObject* parent = NULL);
#endif // QT_WEBSOCKETS_LIB
Network(SocketInterface* socketInterface, TimerInterface* timerInterface,
QObject* parent = NULL);
~Network();
Expand Down
73 changes: 73 additions & 0 deletions src/mqtt/qmqtt_websocket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#ifdef QT_WEBSOCKETS_LIB

#include <QNetworkRequest>
#include <QUrl>
#include "qmqtt_websocket_p.h"

QMQTT::WebSocket::WebSocket(const QString& origin, QWebSocketProtocol::Version version,
bool ignoreSelfSigned, QObject* parent)
: SocketInterface(parent)
, _socket(new QWebSocket(origin, version, this))
, _ioDevice(new WebSocketIODevice(_socket, this))
, _ignoreSelfSigned(ignoreSelfSigned)
{
connect(_socket, &QWebSocket::connected, this, &WebSocket::connected);
connect(_socket, &QWebSocket::disconnected, this, &WebSocket::disconnected);
connect(_socket,
static_cast<void (QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error),
this,
static_cast<void (SocketInterface::*)(QAbstractSocket::SocketError)>(&SocketInterface::error));
connect(_socket, &QWebSocket::sslErrors, this, &WebSocket::sslErrors);
}

QMQTT::WebSocket::~WebSocket()
{
}

void QMQTT::WebSocket::connectToHost(const QHostAddress& address, quint16 port)
{
Q_UNUSED(address)
Q_UNUSED(port)
qFatal("No supported");
}

void QMQTT::WebSocket::connectToHost(const QString& hostName, quint16 port)
{
Q_UNUSED(port)
QUrl url(hostName);
QNetworkRequest request(url);
request.setRawHeader("Sec-WebSocket-Protocol", "mqtt");
_ioDevice->connectToHost(request);
}

void QMQTT::WebSocket::disconnectFromHost()
{
_socket->disconnect();
}

QAbstractSocket::SocketState QMQTT::WebSocket::state() const
{
return _socket->state();
}

QAbstractSocket::SocketError QMQTT::WebSocket::error() const
{
return _socket->error();
}

void QMQTT::WebSocket::sslErrors(const QList<QSslError> &errors)
{
if (!_ignoreSelfSigned)
return;
foreach (QSslError error, errors)
{
if (error.error() != QSslError::SelfSignedCertificate &&
error.error() != QSslError::SelfSignedCertificateInChain)
{
return;
}
}
_socket->ignoreSslErrors();
}

#endif // QT_WEBSOCKETS_LIB
Loading

0 comments on commit 3b22b35

Please sign in to comment.