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  virtual ~WebSocketServer();
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  typedef enum OpCodes
102  {
106  // Reserved
107  kOpClose = 0x8,
108  kOpPing = 0x9,
109  kOpPong = 0xA
110  // Reserved
111  } OpCode;
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() : QObject() { };
142  virtual ~WebSocketExtension() = 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  virtual ~WebSocketWorkerThread() = 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  virtual ~WebSocketWorker();
216 
217  void Exec();
218 
219  typedef enum ErrorCodes
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  } ErrorCode;
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 *);
253  void ProcessFrames(QTcpSocket *);
254 
255  void HandleControlFrame(const WebSocketFrame &frame);
256  void HandleDataFrame(const WebSocketFrame &frame);
257 
258  void HandleCloseConnection(const QByteArray &payload);
259 
260  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
WebSocketServer & m_webSocketServer
Definition: websocket.h:274
bool SendText(const QString &message)
Definition: websocket.cpp:853
unsigned int slots[4]
Definition: element.c:38
QSslConfiguration m_sslConfig
Definition: websocket.h:175
bool m_finalFrame
Definition: websocket.h:113
void CleanupSocket()
Definition: websocket.cpp:222
bool IsRunning(void) const
Definition: websocket.h:45
bool m_fuzzTesting
Definition: websocket.h:292
qt_socket_fd_t m_socketFD
Definition: websocket.h:275
enum WebSocketFrame::OpCodes OpCode
QTcpSocket * m_socket
Definition: websocket.h:276
virtual ~WebSocketExtension()=default
PoolServerType m_connectionType
Definition: websocket.h:277
QList< WebSocketExtension * > m_extensions
Definition: websocket.h:294
QByteArray m_mask
Definition: websocket.h:118
QSslConfiguration m_sslConfig
Definition: websocket.h:62
void SendTextMessage(const QString &)
static guint32 * tmp
Definition: goom_core.c:35
qintptr qt_socket_fd_t
Definition: mythqtcompat.h:4
bool SendFrame(const QByteArray &frame)
Definition: websocket.cpp:838
WebSocketWorker(WebSocketServer &webSocketServer, qt_socket_fd_t sock, PoolServerType type, const QSslConfiguration &sslConfig)
Definition: websocket.cpp:101
virtual bool HandleTextFrame(const WebSocketFrame &)
Definition: websocket.h:144
WebSocketWorkerThread(WebSocketServer &webSocketServer, qt_socket_fd_t sock, PoolServerType type, const QSslConfiguration &sslConfig)
Definition: websocket.cpp:69
QSslConfiguration m_sslConfig
Definition: websocket.h:289
QByteArray m_payload
Definition: websocket.h:114
uint64_t m_payloadSize
Definition: websocket.h:115
QReadWriteLock m_rwlock
Definition: websocket.h:57
Performs all the protocol-level work for a single websocket connection.
Definition: websocket.h:197
WebSocketFrame m_readFrame
Definition: websocket.h:281
void HandleControlFrame(const WebSocketFrame &frame)
Returns false if an error occurs.
Definition: websocket.cpp:662
void CloseConnection()
Definition: websocket.cpp:151
bool SendClose(ErrorCode errCode, const QString &message=QString())
Definition: websocket.cpp:894
QByteArray CreateFrame(WebSocketFrame::OpCode type, const QByteArray &payload)
Definition: websocket.cpp:762
void run(void) override
Definition: websocket.cpp:84
qt_socket_fd_t m_socketFD
Definition: websocket.h:172
bool m_fragmented
Definition: websocket.h:119
bool ProcessHandshake(QTcpSocket *)
Definition: websocket.cpp:311
The thread in which WebSocketWorker does it's thing.
Definition: websocket.h:157
Manages a collection of sockets listening on different ports.
Definition: serverpool.h:59
virtual ~WebSocketWorker()
Definition: websocket.cpp:128
The WebSocket server, which listens for connections.
Definition: websocket.h:37
bool SendBinary(const QByteArray &data)
Definition: websocket.cpp:873
PoolServerType m_connectionType
Definition: websocket.h:173
#define UPNP_PUBLIC
Definition: upnpexp.h:9
enum WebSocketWorker::ErrorCodes ErrorCode
void SetupSocket()
Definition: websocket.cpp:160
MThreadPool m_threadPool
Definition: websocket.h:58
enum PoolServerTypes PoolServerType
uint8_t m_errorCount
Definition: websocket.h:283
Base class for extensions.
Definition: websocket.h:136
void reset(void)
Definition: websocket.h:89
OpCode m_opCode
Definition: websocket.h:116
virtual void newTcpConnection(qt_socket_fd_t socket)
Definition: serverpool.cpp:630
virtual ~WebSocketWorkerThread()=default
void RegisterExtension(WebSocketExtension *extension)
Definition: websocket.cpp:923
void DeregisterExtension(WebSocketExtension *extension)
Definition: websocket.cpp:936
bool SendPong(const QByteArray &payload)
Definition: websocket.cpp:887
void ProcessFrames(QTcpSocket *)
Returns false if an error occurs.
Definition: websocket.cpp:475
bool m_webSocketMode
Definition: websocket.h:280
bool SendPing(const QByteArray &payload)
Definition: websocket.cpp:880
void HandleDataFrame(const WebSocketFrame &frame)
Definition: websocket.cpp:666
void HandleCloseConnection(const QByteArray &payload)
Definition: websocket.cpp:717
virtual bool HandleBinaryFrame(const WebSocketFrame &)
Definition: websocket.h:145
void SendBinaryMessage(const QByteArray &)
QTimer * m_heartBeat
Definition: websocket.h:286
WebSocketServer & m_webSocketServer
Definition: websocket.h:171
A representation of a single WebSocket frame.
Definition: websocket.h:75
void SendHeartBeat()
Definition: websocket.cpp:918
QEventLoop * m_eventLoop
Definition: websocket.h:273