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