qmqtt_network.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. * qmqtt_network.cpp - qmqtt network
  3. *
  4. * Copyright (c) 2013 Ery Lee <ery.lee at gmail dot com>
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * * Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * * Neither the name of mqttc nor the names of its contributors may be used
  16. * to endorse or promote products derived from this software without
  17. * specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  23. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. * POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. */
  32. #include "qmqtt_network_p.h"
  33. #include "qmqtt_socket_p.h"
  34. #include "qmqtt_ssl_socket_p.h"
  35. #include "qmqtt_timer_p.h"
  36. #include "qmqtt_websocket_p.h"
  37. #include "qmqtt_frame.h"
  38. #include <QDataStream>
  39. const quint16 DEFAULT_PORT = 1883;
  40. const quint16 DEFAULT_SSL_PORT = 8883;
  41. const bool DEFAULT_AUTORECONNECT = false;
  42. const int DEFAULT_AUTORECONNECT_INTERVAL_MS = 5000;
  43. QMQTT::Network::Network(QObject* parent)
  44. : NetworkInterface(parent)
  45. , _port(DEFAULT_PORT)
  46. , _autoReconnect(DEFAULT_AUTORECONNECT)
  47. , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  48. , _socket(new QMQTT::Socket)
  49. , _autoReconnectTimer(new QMQTT::Timer)
  50. , _readState(Header)
  51. {
  52. initialize();
  53. }
  54. #ifndef QT_NO_SSL
  55. QMQTT::Network::Network(const QSslConfiguration& config, QObject *parent)
  56. : NetworkInterface(parent)
  57. , _port(DEFAULT_SSL_PORT)
  58. , _autoReconnect(DEFAULT_AUTORECONNECT)
  59. , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  60. , _socket(new QMQTT::SslSocket(config))
  61. , _autoReconnectTimer(new QMQTT::Timer)
  62. , _readState(Header)
  63. {
  64. initialize();
  65. connect(_socket, &QMQTT::SslSocket::sslErrors, this, &QMQTT::Network::sslErrors);
  66. }
  67. #endif // QT_NO_SSL
  68. #ifdef QT_WEBSOCKETS_LIB
  69. #ifndef QT_NO_SSL
  70. QMQTT::Network::Network(const QString& origin,
  71. QWebSocketProtocol::Version version,
  72. const QSslConfiguration* sslConfig,
  73. QObject* parent)
  74. : NetworkInterface(parent)
  75. , _port(DEFAULT_SSL_PORT)
  76. , _autoReconnect(DEFAULT_AUTORECONNECT)
  77. , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  78. , _socket(new QMQTT::WebSocket(origin, version, sslConfig))
  79. , _autoReconnectTimer(new QMQTT::Timer)
  80. , _readState(Header)
  81. {
  82. initialize();
  83. }
  84. #endif // QT_NO_SSL
  85. QMQTT::Network::Network(const QString& origin,
  86. QWebSocketProtocol::Version version,
  87. QObject* parent)
  88. : NetworkInterface(parent)
  89. , _port(DEFAULT_PORT)
  90. , _autoReconnect(DEFAULT_AUTORECONNECT)
  91. , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  92. , _socket(new QMQTT::WebSocket(origin, version))
  93. , _autoReconnectTimer(new QMQTT::Timer)
  94. , _readState(Header)
  95. {
  96. initialize();
  97. }
  98. #endif // QT_WEBSOCKETS_LIB
  99. QMQTT::Network::Network(SocketInterface* socketInterface, TimerInterface* timerInterface,
  100. QObject* parent)
  101. : NetworkInterface(parent)
  102. , _port(DEFAULT_PORT)
  103. , _autoReconnect(DEFAULT_AUTORECONNECT)
  104. , _autoReconnectInterval(DEFAULT_AUTORECONNECT_INTERVAL_MS)
  105. , _socket(socketInterface)
  106. , _autoReconnectTimer(timerInterface)
  107. , _readState(Header)
  108. {
  109. initialize();
  110. }
  111. void QMQTT::Network::initialize()
  112. {
  113. _socket->setParent(this);
  114. _autoReconnectTimer->setParent(this);
  115. _autoReconnectTimer->setSingleShot(true);
  116. _autoReconnectTimer->setInterval(_autoReconnectInterval);
  117. QObject::connect(_socket, &SocketInterface::connected, this, &Network::connected);
  118. QObject::connect(_socket, &SocketInterface::disconnected, this, &Network::onDisconnected);
  119. QObject::connect(_socket->ioDevice(), &QIODevice::readyRead, this, &Network::onSocketReadReady);
  120. QObject::connect(
  121. _autoReconnectTimer, &TimerInterface::timeout,
  122. this, static_cast<void (Network::*)()>(&Network::connectToHost));
  123. QObject::connect(_socket,
  124. static_cast<void (SocketInterface::*)(QAbstractSocket::SocketError)>(&SocketInterface::error),
  125. this, &Network::onSocketError);
  126. }
  127. QMQTT::Network::~Network()
  128. {
  129. }
  130. bool QMQTT::Network::isConnectedToHost() const
  131. {
  132. return _socket->state() == QAbstractSocket::ConnectedState;
  133. }
  134. void QMQTT::Network::connectToHost(const QHostAddress& host, const quint16 port)
  135. {
  136. // Reset the hostname, because if it is not empty connectToHost() will use it instead of _host.
  137. _hostName.clear();
  138. _host = host;
  139. _port = port;
  140. connectToHost();
  141. }
  142. void QMQTT::Network::connectToHost(const QString& hostName, const quint16 port)
  143. {
  144. _hostName = hostName;
  145. _port = port;
  146. connectToHost();
  147. }
  148. void QMQTT::Network::connectToHost()
  149. {
  150. _readState = Header;
  151. if (_hostName.isEmpty())
  152. {
  153. _socket->connectToHost(_host, _port);
  154. }
  155. else
  156. {
  157. _socket->connectToHost(_hostName, _port);
  158. }
  159. }
  160. void QMQTT::Network::onSocketError(QAbstractSocket::SocketError socketError)
  161. {
  162. emit error(socketError);
  163. if(_autoReconnect)
  164. {
  165. _autoReconnectTimer->start();
  166. }
  167. }
  168. void QMQTT::Network::sendFrame(const Frame& frame)
  169. {
  170. if(_socket->state() == QAbstractSocket::ConnectedState)
  171. {
  172. QDataStream out(_socket->ioDevice());
  173. frame.write(out);
  174. }
  175. }
  176. void QMQTT::Network::disconnectFromHost()
  177. {
  178. _socket->disconnectFromHost();
  179. }
  180. QAbstractSocket::SocketState QMQTT::Network::state() const
  181. {
  182. return _socket->state();
  183. }
  184. bool QMQTT::Network::autoReconnect() const
  185. {
  186. return _autoReconnect;
  187. }
  188. void QMQTT::Network::setAutoReconnect(const bool autoReconnect)
  189. {
  190. _autoReconnect = autoReconnect;
  191. }
  192. int QMQTT::Network::autoReconnectInterval() const
  193. {
  194. return _autoReconnectInterval;
  195. }
  196. void QMQTT::Network::setAutoReconnectInterval(const int autoReconnectInterval)
  197. {
  198. _autoReconnectInterval = autoReconnectInterval;
  199. _autoReconnectTimer->setInterval(_autoReconnectInterval);
  200. }
  201. void QMQTT::Network::onSocketReadReady()
  202. {
  203. QIODevice *ioDevice = _socket->ioDevice();
  204. // Only read the available (cached) bytes, so the read will never block.
  205. QByteArray data = ioDevice->read(ioDevice->bytesAvailable());
  206. foreach(char byte, data) {
  207. switch (_readState) {
  208. case Header:
  209. _header = static_cast<quint8>(byte);
  210. _readState = Length;
  211. _length = 0;
  212. _shift = 0;
  213. _data.resize(0); // keep allocated buffer
  214. break;
  215. case Length:
  216. _length |= (byte & 0x7F) << _shift;
  217. _shift += 7;
  218. if ((byte & 0x80) != 0)
  219. break;
  220. if (_length == 0) {
  221. _readState = Header;
  222. Frame frame(_header, _data);
  223. emit received(frame);
  224. break;
  225. }
  226. _readState = PayLoad;
  227. _data.reserve(_length);
  228. break;
  229. case PayLoad:
  230. _data.append(byte);
  231. --_length;
  232. if (_length > 0)
  233. break;
  234. _readState = Header;
  235. Frame frame(_header, _data);
  236. emit received(frame);
  237. break;
  238. }
  239. }
  240. }
  241. void QMQTT::Network::onDisconnected()
  242. {
  243. emit disconnected();
  244. if(_autoReconnect)
  245. {
  246. _autoReconnectTimer->start();
  247. }
  248. }
  249. #ifndef QT_NO_SSL
  250. void QMQTT::Network::ignoreSslErrors(const QList<QSslError>& errors)
  251. {
  252. _socket->ignoreSslErrors(errors);
  253. }
  254. void QMQTT::Network::ignoreSslErrors()
  255. {
  256. _socket->ignoreSslErrors();
  257. }
  258. QSslConfiguration QMQTT::Network::sslConfiguration() const
  259. {
  260. return _socket->sslConfiguration();
  261. }
  262. void QMQTT::Network::setSslConfiguration(const QSslConfiguration& config)
  263. {
  264. _socket->setSslConfiguration(config);
  265. }
  266. #endif // QT_NO_SSL