WPILibC++  2019.1.1-beta-3-2-g4159660
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
WebSocket.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2018 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #ifndef WPIUTIL_WPI_WEBSOCKET_H_
9 #define WPIUTIL_WPI_WEBSOCKET_H_
10 
11 #include <stdint.h>
12 
13 #include <functional>
14 #include <memory>
15 #include <string>
16 #include <utility>
17 
18 #include "wpi/ArrayRef.h"
19 #include "wpi/Signal.h"
20 #include "wpi/SmallVector.h"
21 #include "wpi/StringRef.h"
22 #include "wpi/Twine.h"
23 #include "wpi/uv/Buffer.h"
24 #include "wpi/uv/Error.h"
25 #include "wpi/uv/Timer.h"
26 
27 namespace wpi {
28 
29 namespace uv {
30 class Stream;
31 } // namespace uv
32 
36 class WebSocket : public std::enable_shared_from_this<WebSocket> {
37  struct private_init {};
38 
39  static constexpr uint8_t kOpCont = 0x00;
40  static constexpr uint8_t kOpText = 0x01;
41  static constexpr uint8_t kOpBinary = 0x02;
42  static constexpr uint8_t kOpClose = 0x08;
43  static constexpr uint8_t kOpPing = 0x09;
44  static constexpr uint8_t kOpPong = 0x0A;
45  static constexpr uint8_t kOpMask = 0x0F;
46  static constexpr uint8_t kFlagFin = 0x80;
47  static constexpr uint8_t kFlagMasking = 0x80;
48  static constexpr uint8_t kLenMask = 0x7f;
49 
50  public:
51  WebSocket(uv::Stream& stream, bool server, const private_init&);
52  WebSocket(const WebSocket&) = delete;
53  WebSocket(WebSocket&&) = delete;
54  WebSocket& operator=(const WebSocket&) = delete;
55  WebSocket& operator=(WebSocket&&) = delete;
56  ~WebSocket();
57 
61  enum State {
72  };
73 
77  struct ClientOptions {
78  ClientOptions() : handshakeTimeout{uv::Timer::Time::max()} {}
79 
81  uv::Timer::Time handshakeTimeout;
82 
85  };
86 
97  static std::shared_ptr<WebSocket> CreateClient(
98  uv::Stream& stream, const Twine& uri, const Twine& host,
100  const ClientOptions& options = ClientOptions{});
101 
115  static std::shared_ptr<WebSocket> CreateServer(
116  uv::Stream& stream, StringRef key, StringRef version,
117  StringRef protocol = StringRef{});
118 
122  State GetState() const { return m_state; }
123 
128  bool IsOpen() const { return m_state == OPEN; }
129 
133  uv::Stream& GetStream() const { return m_stream; }
134 
138  StringRef GetProtocol() const { return m_protocol; }
139 
146  void SetMaxMessageSize(size_t size) { m_maxMessageSize = size; }
147 
154  void SetCombineFragments(bool combine) { m_combineFragments = combine; }
155 
162  void Close(uint16_t code = 1005, const Twine& reason = Twine{});
163 
169  void SendText(
171  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback) {
172  Send(kFlagFin | kOpText, data, callback);
173  }
174 
182  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback) {
183  Send(kFlagFin | kOpBinary, data, callback);
184  }
185 
195  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback) {
196  Send(kOpText, data, callback);
197  }
198 
208  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback) {
209  Send(kOpBinary, data, callback);
210  }
211 
220  ArrayRef<uv::Buffer> data, bool fin,
221  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback) {
222  Send(kOpCont | (fin ? kFlagFin : 0), data, callback);
223  }
224 
230  void SendPing(std::function<void(uv::Error)> callback = nullptr) {
231  SendPing(ArrayRef<uv::Buffer>{}, [callback](auto bufs, uv::Error err) {
232  if (callback) callback(err);
233  });
234  }
235 
242  void SendPing(
244  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback) {
245  Send(kFlagFin | kOpPing, data, callback);
246  }
247 
253  void SendPong(std::function<void(uv::Error)> callback = nullptr) {
254  SendPong(ArrayRef<uv::Buffer>{}, [callback](auto bufs, uv::Error err) {
255  if (callback) callback(err);
256  });
257  }
258 
265  void SendPong(
267  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback) {
268  Send(kFlagFin | kOpPong, data, callback);
269  }
270 
274  void Fail(uint16_t code = 1002, const Twine& reason = "protocol error");
275 
279  void Terminate(uint16_t code = 1006, const Twine& reason = "terminated");
280 
285  template <typename T = void>
286  std::shared_ptr<T> GetData() const {
287  return std::static_pointer_cast<T>(m_data);
288  }
289 
294  void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
295 
301 
309 
316 
323 
328 
333 
334  private:
335  // user data
336  std::shared_ptr<void> m_data;
337 
338  // constructor parameters
339  uv::Stream& m_stream;
340  bool m_server;
341 
342  // subprotocol, set via constructor (server) or handshake (client)
343  std::string m_protocol;
344 
345  // user-settable configuration
346  size_t m_maxMessageSize = 128 * 1024;
347  bool m_combineFragments = true;
348 
349  // operating state
350  State m_state = CONNECTING;
351 
352  // incoming message buffers/state
353  SmallVector<uint8_t, 14> m_header;
354  size_t m_headerSize = 0;
355  SmallVector<uint8_t, 1024> m_payload;
356  size_t m_frameStart = 0;
357  uint64_t m_frameSize = UINT64_MAX;
358  uint8_t m_fragmentOpcode = 0;
359 
360  // temporary data used only during client handshake
361  class ClientHandshakeData;
362  std::unique_ptr<ClientHandshakeData> m_clientHandshake;
363 
364  void StartClient(const Twine& uri, const Twine& host,
365  ArrayRef<StringRef> protocols, const ClientOptions& options);
366  void StartServer(StringRef key, StringRef version, StringRef protocol);
367  void SendClose(uint16_t code, const Twine& reason);
368  void SetClosed(uint16_t code, const Twine& reason, bool failed = false);
369  void Shutdown();
370  void HandleIncoming(uv::Buffer& buf, size_t size);
371  void Send(
372  uint8_t opcode, ArrayRef<uv::Buffer> data,
373  std::function<void(MutableArrayRef<uv::Buffer>, uv::Error)> callback);
374 };
375 
376 } // namespace wpi
377 
378 #endif // WPIUTIL_WPI_WEBSOCKET_H_
sig::Signal< ArrayRef< uint8_t >, bool > binary
Binary message event.
Definition: WebSocket.h:322
sig::Signal< ArrayRef< uint8_t > > pong
Pong event.
Definition: WebSocket.h:332
void Fail(uint16_t code=1002, const Twine &reason="protocol error")
Fail the connection.
The connection is in the process of closing.
Definition: WebSocket.h:67
void SendFragment(ArrayRef< uv::Buffer > data, bool fin, std::function< void(MutableArrayRef< uv::Buffer >, uv::Error)> callback)
Send a continuation frame.
Definition: WebSocket.h:219
void SendText(ArrayRef< uv::Buffer > data, std::function< void(MutableArrayRef< uv::Buffer >, uv::Error)> callback)
Send a text message.
Definition: WebSocket.h:169
bool IsOpen() const
Return if the connection is open.
Definition: WebSocket.h:128
static std::shared_ptr< WebSocket > CreateServer(uv::Stream &stream, StringRef key, StringRef version, StringRef protocol=StringRef{})
Starts a server connection by performing the initial server side handshake.
std::shared_ptr< T > GetData() const
Gets user-defined data.
Definition: WebSocket.h:286
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: ArrayRef.h:41
void SendPong(ArrayRef< uv::Buffer > data, std::function< void(MutableArrayRef< uv::Buffer >, uv::Error)> callback)
Send a pong frame.
Definition: WebSocket.h:265
RFC 6455 compliant WebSocket client and server implementation.
Definition: WebSocket.h:36
WPILib C++ utilities (wpiutil) namespace.
Definition: SmallString.h:21
Stream handle.
Definition: Stream.h:68
The connection is not yet open.
Definition: WebSocket.h:63
void StartServer(StringRef persist_filename, const char *listen_address, unsigned int port)
Starts a server using the specified filename, listening address, and port.
void SetData(std::shared_ptr< void > data)
Sets user-defined data.
Definition: WebSocket.h:294
StringRef GetProtocol() const
Get the selected sub-protocol.
Definition: WebSocket.h:138
sig::Signal< StringRef > open
Open event.
Definition: WebSocket.h:300
The connection is closed.
Definition: WebSocket.h:71
void SendPing(std::function< void(uv::Error)> callback=nullptr)
Send a ping frame with no data.
Definition: WebSocket.h:230
static std::shared_ptr< WebSocket > CreateClient(uv::Stream &stream, const Twine &uri, const Twine &host, ArrayRef< StringRef > protocols=ArrayRef< StringRef >{}, const ClientOptions &options=ClientOptions{})
Starts a client connection by performing the initial client handshake.
void SendBinary(ArrayRef< uv::Buffer > data, std::function< void(MutableArrayRef< uv::Buffer >, uv::Error)> callback)
Send a binary message.
Definition: WebSocket.h:180
ArrayRef< std::pair< StringRef, StringRef > > extraHeaders
Additional headers to include in handshake.
Definition: WebSocket.h:84
void SendTextFragment(ArrayRef< uv::Buffer > data, std::function< void(MutableArrayRef< uv::Buffer >, uv::Error)> callback)
Send a text message fragment.
Definition: WebSocket.h:193
void StartClient()
Starts a client.
State
Connection states.
Definition: WebSocket.h:61
void SendPong(std::function< void(uv::Error)> callback=nullptr)
Send a pong frame with no data.
Definition: WebSocket.h:253
uv::Timer::Time handshakeTimeout
Timeout for the handshake request.
Definition: WebSocket.h:81
sig::Signal< uint16_t, StringRef > closed
Close event.
Definition: WebSocket.h:308
void Close(uint16_t code=1005, const Twine &reason=Twine{})
Initiate a closing handshake.
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
Definition: STLExtras.h:999
State GetState() const
Get connection state.
Definition: WebSocket.h:122
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
void SendPing(ArrayRef< uv::Buffer > data, std::function< void(MutableArrayRef< uv::Buffer >, uv::Error)> callback)
Send a ping frame.
Definition: WebSocket.h:242
The connection failed.
Definition: WebSocket.h:69
void Terminate(uint16_t code=1006, const Twine &reason="terminated")
Forcibly close the connection.
Error code.
Definition: Error.h:19
void SetCombineFragments(bool combine)
Set whether or not fragmented frames should be combined.
Definition: WebSocket.h:154
sig::Signal< StringRef, bool > text
Text message event.
Definition: WebSocket.h:315
Data buffer.
Definition: Buffer.h:27
SignalBase is an implementation of the observer pattern, through the use of an emitting object and sl...
Definition: Signal.h:495
The connection is open and ready to communicate.
Definition: WebSocket.h:65
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:79
void SetMaxMessageSize(size_t size)
Set the maximum message size.
Definition: WebSocket.h:146
uv::Stream & GetStream() const
Get the underlying stream.
Definition: WebSocket.h:133
void SendBinaryFragment(ArrayRef< uv::Buffer > data, std::function< void(MutableArrayRef< uv::Buffer >, uv::Error)> callback)
Send a text message fragment.
Definition: WebSocket.h:206
sig::Signal< ArrayRef< uint8_t > > ping
Ping event.
Definition: WebSocket.h:327
Client connection options.
Definition: WebSocket.h:77
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:291