MythTV  master
websocket.h
Go to the documentation of this file.
1 // Program Name: websocket.h
3 // Created : 18 Jan 2015
4 //
5 // Purpose : Web Socket server
6 //
7 // Copyright (c) 2015 Stuart Morgan <smorgan@mythtv.org>
8 //
9 // Licensed under the GPL v2 or later, see LICENSE for details
10 //
12 
13 #ifndef WEBSOCKET_H
14 #define WEBSOCKET_H
15 
17 #include "libmythbase/serverpool.h"
18 
19 #include "upnpexp.h"
20 
21 #include <QRunnable>
22 #include <QSslConfiguration>
23 #include <QReadWriteLock>
24 #include <QEvent>
25 #include <QEventLoop>
26 #include <QTimer>
27 
28 #include <cstdint>
29 
39 {
40  Q_OBJECT
41 
42  public:
44  ~WebSocketServer() override;
45 
46  bool IsRunning(void) const
47  {
48  m_rwlock.lockForRead();
49  bool tmp = m_running;
50  m_rwlock.unlock();
51  return tmp;
52  }
53 
54  protected slots:
55  void newTcpConnection(qintptr socket) override; // QTcpServer
56 
57  protected:
58  mutable QReadWriteLock m_rwlock;
60  bool m_running {true}; // protected by m_rwlock
61 
62 #ifndef QT_NO_OPENSSL
63  QSslConfiguration m_sslConfig;
64 #endif
65 
66  private:
67  //void LoadSSLConfig();
68 };
69 
70 
77 {
78  public:
80  {
81  m_mask.reserve(4);
82  }
83 
85  {
86  m_payload.clear();
87  m_mask.clear();
88  }
89 
90  void reset(void)
91  {
92  m_finalFrame = false;
93  m_payload.clear();
94  m_payload.resize(128);
95  m_payload.squeeze();
96  m_mask.clear();
97  m_payloadSize = 0;
99  m_fragmented = false;
100  }
101 
102  enum OpCode
103  {
107  // Reserved
108  kOpClose = 0x8,
109  kOpPing = 0x9,
110  kOpPong = 0xA
111  // Reserved
112  };
113 
114  bool m_finalFrame {false};
115  QByteArray m_payload;
116  uint64_t m_payloadSize {0};
118  bool m_isMasked {false};
119  QByteArray m_mask;
120  bool m_fragmented {false};
121 };
122 
123 class WebSocketWorker;
124 
137 class WebSocketExtension : public QObject
138 {
139  Q_OBJECT
140 
141  public:
142  WebSocketExtension() = default;;
143  ~WebSocketExtension() override = default;
144 
145  virtual bool HandleTextFrame(const WebSocketFrame &/*frame*/) { return false; }
146  virtual bool HandleBinaryFrame(const WebSocketFrame &/*frame*/) { return false; }
147 
148  signals:
149  void SendTextMessage(const QString &);
150  void SendBinaryMessage(const QByteArray &);
151 };
152 
158 class WebSocketWorkerThread : public QRunnable
159 {
160  public:
161  WebSocketWorkerThread(WebSocketServer &webSocketServer, qintptr sock,
163 #ifndef QT_NO_OPENSSL
164  , const QSslConfiguration& sslConfig
165 #endif
166  );
167  ~WebSocketWorkerThread() override = default;
168 
169  void run(void) override; // QRunnable
170 
171  private:
173  qintptr m_socketFD;
175 #ifndef QT_NO_OPENSSL
176  QSslConfiguration m_sslConfig;
177 #endif
178 };
179 
198 class WebSocketWorker : public QObject
199 {
200  Q_OBJECT
201 
202  public:
203 
210  WebSocketWorker(WebSocketServer &webSocketServer, qintptr sock,
212 #ifndef QT_NO_OPENSSL
213  , const QSslConfiguration& sslConfig
214 #endif
215  );
216  ~WebSocketWorker() override;
217 
218  void Exec();
219 
221  {
222  kCloseNormal = 1000,
226  // Reserved - 1004
227  // The following codes, 1005 and 1006 should not go over the wire,
228  // they are internal codes generated if the client has disconnected
229  // without sending a Close event or without indicating a reason for
230  // closure.
234  kClosePolicy = 1008, // Message violates server policy and 1003/1009 don't apply
235  kCloseTooLarge = 1009, // Message is larger than we support (32KB)
236  kCloseNoExtensions = 1010, // CLIENT ONLY
237  kCloseUnexpectedErr = 1011, // SERVER ONLY
238  // Reserved - 1012-1014
239  kCloseNoTLS = 1012 // Connection closed because it must use TLS
240  // Reserved
241  };
242 
243  public slots:
244  void doRead();
245  void CloseConnection();
246 
247  void SendHeartBeat();
248  bool SendText(const QString &message);
249  bool SendText(const QByteArray &message);
250  bool SendBinary(const QByteArray &data);
251 
252  protected:
253  bool ProcessHandshake(QTcpSocket *socket);
254  void ProcessFrames(QTcpSocket *socket);
255 
256  void HandleControlFrame(const WebSocketFrame &frame);
257  void HandleDataFrame(const WebSocketFrame &frame);
258 
259  void HandleCloseConnection(const QByteArray &payload);
260 
261  static QByteArray CreateFrame(WebSocketFrame::OpCode type, const QByteArray &payload);
262 
263  bool SendFrame(const QByteArray &frame);
264  bool SendPing(const QByteArray &payload);
265  bool SendPong(const QByteArray &payload);
266  bool SendClose(ErrorCode errCode, const QString &message = QString());
267 
268  void SetupSocket();
269  void CleanupSocket();
270 
271  void RegisterExtension(WebSocketExtension *extension);
272  void DeregisterExtension(WebSocketExtension *extension);
273 
274  QEventLoop *m_eventLoop {nullptr};
276  qintptr m_socketFD;
277  QTcpSocket *m_socket {nullptr};
279 
280  // True if we've successfully upgraded from HTTP
281  bool m_webSocketMode {false};
283 
284  uint8_t m_errorCount {0};
285  bool m_isRunning {false};
286 
287  QTimer *m_heartBeat {nullptr};
288 
289 #ifndef QT_NO_OPENSSL
290  QSslConfiguration m_sslConfig;
291 #endif
292 
293  bool m_fuzzTesting {false};
294 
295  QList<WebSocketExtension *> m_extensions;
296 };
297 
298 #endif // WEBSOCKET_H
WebSocketWorker::m_webSocketServer
WebSocketServer & m_webSocketServer
Definition: websocket.h:275
WebSocketWorkerThread::m_webSocketServer
WebSocketServer & m_webSocketServer
Definition: websocket.h:172
WebSocketWorker::kCloseUnsupported
@ kCloseUnsupported
Definition: websocket.h:225
WebSocketExtension::HandleTextFrame
virtual bool HandleTextFrame(const WebSocketFrame &)
Definition: websocket.h:145
WebSocketWorker::ProcessFrames
void ProcessFrames(QTcpSocket *socket)
Returns false if an error occurs.
Definition: websocket.cpp:478
WebSocketWorker::m_eventLoop
QEventLoop * m_eventLoop
Definition: websocket.h:274
WebSocketFrame::m_opCode
OpCode m_opCode
Definition: websocket.h:117
WebSocketWorker::kCloseNoTLS
@ kCloseNoTLS
Definition: websocket.h:239
WebSocketWorker::kCloseBadData
@ kCloseBadData
Definition: websocket.h:233
WebSocketWorker::ErrorCode
ErrorCode
Definition: websocket.h:220
WebSocketFrame::m_finalFrame
bool m_finalFrame
Definition: websocket.h:114
WebSocketExtension::~WebSocketExtension
~WebSocketExtension() override=default
WebSocketFrame
A representation of a single WebSocket frame.
Definition: websocket.h:76
ServerPool
Manages a collection of sockets listening on different ports.
Definition: serverpool.h:59
WebSocketFrame::m_isMasked
bool m_isMasked
Definition: websocket.h:118
WebSocketWorker::~WebSocketWorker
~WebSocketWorker() override
Definition: websocket.cpp:132
WebSocketExtension::WebSocketExtension
WebSocketExtension()=default
WebSocketWorker::m_sslConfig
QSslConfiguration m_sslConfig
Definition: websocket.h:290
WebSocketWorker::m_extensions
QList< WebSocketExtension * > m_extensions
Definition: websocket.h:295
WebSocketWorker::HandleDataFrame
void HandleDataFrame(const WebSocketFrame &frame)
Definition: websocket.cpp:669
WebSocketExtension
Base class for extensions.
Definition: websocket.h:137
WebSocketWorkerThread::~WebSocketWorkerThread
~WebSocketWorkerThread() override=default
WebSocketFrame::kOpTextFrame
@ kOpTextFrame
Definition: websocket.h:105
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
WebSocketWorker::SendBinary
bool SendBinary(const QByteArray &data)
Definition: websocket.cpp:873
WebSocketWorkerThread::m_connectionType
PoolServerType m_connectionType
Definition: websocket.h:174
WebSocketExtension::SendBinaryMessage
void SendBinaryMessage(const QByteArray &)
WebSocketWorker::CloseConnection
void CloseConnection()
Definition: websocket.cpp:155
WebSocketWorker::m_connectionType
PoolServerType m_connectionType
Definition: websocket.h:278
WebSocketWorker::kCloseAbnormal
@ kCloseAbnormal
Definition: websocket.h:232
WebSocketFrame::kOpPong
@ kOpPong
Definition: websocket.h:110
WebSocketWorker::m_heartBeat
QTimer * m_heartBeat
Definition: websocket.h:287
WebSocketWorker::SendPing
bool SendPing(const QByteArray &payload)
Definition: websocket.cpp:880
WebSocketWorker::SetupSocket
void SetupSocket()
Definition: websocket.cpp:164
WebSocketFrame::kOpContinuation
@ kOpContinuation
Definition: websocket.h:104
WebSocketExtension::HandleBinaryFrame
virtual bool HandleBinaryFrame(const WebSocketFrame &)
Definition: websocket.h:146
WebSocketExtension::SendTextMessage
void SendTextMessage(const QString &)
WebSocketWorker::HandleControlFrame
void HandleControlFrame(const WebSocketFrame &frame)
Returns false if an error occurs.
Definition: websocket.cpp:665
WebSocketWorker::SendFrame
bool SendFrame(const QByteArray &frame)
Definition: websocket.cpp:838
WebSocketWorkerThread
The thread in which WebSocketWorker does it's thing.
Definition: websocket.h:158
WebSocketWorker::m_isRunning
bool m_isRunning
Definition: websocket.h:285
WebSocketWorker::SendClose
bool SendClose(ErrorCode errCode, const QString &message=QString())
Definition: websocket.cpp:894
PoolServerType
PoolServerType
Definition: serverpool.h:29
WebSocketFrame::m_payload
QByteArray m_payload
Definition: websocket.h:115
WebSocketWorker::RegisterExtension
void RegisterExtension(WebSocketExtension *extension)
Definition: websocket.cpp:923
WebSocketWorker::m_webSocketMode
bool m_webSocketMode
Definition: websocket.h:281
WebSocketWorker::SendPong
bool SendPong(const QByteArray &payload)
Definition: websocket.cpp:887
WebSocketWorker::kCloseUnexpectedErr
@ kCloseUnexpectedErr
Definition: websocket.h:237
ServerPool::newTcpConnection
virtual void newTcpConnection(qintptr socket)
Definition: serverpool.cpp:674
WebSocketServer::m_threadPool
MThreadPool m_threadPool
Definition: websocket.h:59
WebSocketServer::m_rwlock
QReadWriteLock m_rwlock
Definition: websocket.h:58
WebSocketWorker::kClosePolicy
@ kClosePolicy
Definition: websocket.h:234
WebSocketServer::IsRunning
bool IsRunning(void) const
Definition: websocket.h:46
WebSocketWorker::doRead
void doRead()
Definition: websocket.cpp:287
WebSocketFrame::m_payloadSize
uint64_t m_payloadSize
Definition: websocket.h:116
mthreadpool.h
WebSocketWorker::kCloseNoStatus
@ kCloseNoStatus
Definition: websocket.h:231
WebSocketFrame::reset
void reset(void)
Definition: websocket.h:90
MThreadPool
Definition: mthreadpool.h:18
WebSocketFrame::kOpClose
@ kOpClose
Definition: websocket.h:108
WebSocketWorker
Performs all the protocol-level work for a single websocket connection.
Definition: websocket.h:198
WebSocketFrame::WebSocketFrame
WebSocketFrame()
Definition: websocket.h:79
WebSocketWorker::m_readFrame
WebSocketFrame m_readFrame
Definition: websocket.h:282
WebSocketWorker::kCloseTooLarge
@ kCloseTooLarge
Definition: websocket.h:235
serverpool.h
WebSocketWorker::kCloseGoingAway
@ kCloseGoingAway
Definition: websocket.h:223
WebSocketWorkerThread::run
void run(void) override
Definition: websocket.cpp:88
UPNP_PUBLIC
#define UPNP_PUBLIC
Definition: upnpexp.h:9
WebSocketWorker::SendHeartBeat
void SendHeartBeat()
Definition: websocket.cpp:918
WebSocketFrame::OpCode
OpCode
Definition: websocket.h:102
WebSocketWorker::Exec
void Exec()
Definition: websocket.cpp:150
WebSocketWorker::WebSocketWorker
WebSocketWorker(WebSocketServer &webSocketServer, qintptr sock, PoolServerType type, const QSslConfiguration &sslConfig)
Definition: websocket.cpp:105
WebSocketWorker::HandleCloseConnection
void HandleCloseConnection(const QByteArray &payload)
Definition: websocket.cpp:717
WebSocketFrame::m_mask
QByteArray m_mask
Definition: websocket.h:119
WebSocketWorker::m_socketFD
qintptr m_socketFD
Definition: websocket.h:276
WebSocketWorker::m_socket
QTcpSocket * m_socket
Definition: websocket.h:277
WebSocketServer
The WebSocket server, which listens for connections.
Definition: websocket.h:38
WebSocketWorker::DeregisterExtension
void DeregisterExtension(WebSocketExtension *extension)
Definition: websocket.cpp:936
WebSocketWorker::CreateFrame
static QByteArray CreateFrame(WebSocketFrame::OpCode type, const QByteArray &payload)
Definition: websocket.cpp:762
WebSocketWorker::kCloseNoExtensions
@ kCloseNoExtensions
Definition: websocket.h:236
WebSocketWorker::m_errorCount
uint8_t m_errorCount
Definition: websocket.h:284
WebSocketWorkerThread::m_sslConfig
QSslConfiguration m_sslConfig
Definition: websocket.h:176
WebSocketFrame::~WebSocketFrame
~WebSocketFrame()
Definition: websocket.h:84
WebSocketFrame::m_fragmented
bool m_fragmented
Definition: websocket.h:120
WebSocketFrame::kOpPing
@ kOpPing
Definition: websocket.h:109
WebSocketWorkerThread::WebSocketWorkerThread
WebSocketWorkerThread(WebSocketServer &webSocketServer, qintptr sock, PoolServerType type, const QSslConfiguration &sslConfig)
Definition: websocket.cpp:73
WebSocketServer::m_sslConfig
QSslConfiguration m_sslConfig
Definition: websocket.h:63
WebSocketFrame::kOpBinaryFrame
@ kOpBinaryFrame
Definition: websocket.h:106
WebSocketWorker::kCloseNormal
@ kCloseNormal
Definition: websocket.h:222
WebSocketWorker::CleanupSocket
void CleanupSocket()
Definition: websocket.cpp:226
WebSocketWorker::kCloseProtocolError
@ kCloseProtocolError
Definition: websocket.h:224
WebSocketWorker::SendText
bool SendText(const QString &message)
Definition: websocket.cpp:853
WebSocketWorkerThread::m_socketFD
qintptr m_socketFD
Definition: websocket.h:173
upnpexp.h
WebSocketWorker::m_fuzzTesting
bool m_fuzzTesting
Definition: websocket.h:293
WebSocketWorker::ProcessHandshake
bool ProcessHandshake(QTcpSocket *socket)
Definition: websocket.cpp:315