1/*
2 * IXWebSocket.h
3 * Author: Benjamin Sergeant
4 * Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
5 *
6 * WebSocket RFC
7 * https://tools.ietf.org/html/rfc6455
8 */
9
10#pragma once
11
12#include "IXProgressCallback.h"
13#include "IXSocketTLSOptions.h"
14#include "IXWebSocketCloseConstants.h"
15#include "IXWebSocketErrorInfo.h"
16#include "IXWebSocketHttpHeaders.h"
17#include "IXWebSocketMessage.h"
18#include "IXWebSocketPerMessageDeflateOptions.h"
19#include "IXWebSocketSendInfo.h"
20#include "IXWebSocketSendData.h"
21#include "IXWebSocketTransport.h"
22#include <atomic>
23#include <condition_variable>
24#include <mutex>
25#include <string>
26#include <thread>
27
28namespace ix
29{
30 // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Ready_state_constants
31 enum class ReadyState
32 {
33 Connecting = 0,
34 Open = 1,
35 Closing = 2,
36 Closed = 3
37 };
38
39 using OnMessageCallback = std::function<void(const WebSocketMessagePtr&)>;
40
41 using OnTrafficTrackerCallback = std::function<void(size_t size, bool incoming)>;
42
43 class WebSocket
44 {
45 public:
46 WebSocket();
47 ~WebSocket();
48
49 void setUrl(const std::string& url);
50
51 // send extra headers in client handshake request
52 void setExtraHeaders(const WebSocketHttpHeaders& headers);
53 void setPerMessageDeflateOptions(
54 const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions);
55 void setTLSOptions(const SocketTLSOptions& socketTLSOptions);
56 void setPingInterval(int pingIntervalSecs);
57 void enablePong();
58 void disablePong();
59 void enablePerMessageDeflate();
60 void disablePerMessageDeflate();
61 void addSubProtocol(const std::string& subProtocol);
62 void setHandshakeTimeout(int handshakeTimeoutSecs);
63
64 // Run asynchronously, by calling start and stop.
65 void start();
66
67 // stop is synchronous
68 void stop(uint16_t code = WebSocketCloseConstants::kNormalClosureCode,
69 const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage);
70
71 // Run in blocking mode, by connecting first manually, and then calling run.
72 WebSocketInitResult connect(int timeoutSecs);
73 void run();
74
75 // send is in text mode by default
76 WebSocketSendInfo send(const std::string& data,
77 bool binary = false,
78 const OnProgressCallback& onProgressCallback = nullptr);
79 WebSocketSendInfo sendBinary(const std::string& data,
80 const OnProgressCallback& onProgressCallback = nullptr);
81 WebSocketSendInfo sendBinary(const IXWebSocketSendData& data,
82 const OnProgressCallback& onProgressCallback = nullptr);
83 // does not check for valid UTF-8 characters. Caller must check that.
84 WebSocketSendInfo sendUtf8Text(const std::string& text,
85 const OnProgressCallback& onProgressCallback = nullptr);
86 // does not check for valid UTF-8 characters. Caller must check that.
87 WebSocketSendInfo sendUtf8Text(const IXWebSocketSendData& text,
88 const OnProgressCallback& onProgressCallback = nullptr);
89 WebSocketSendInfo sendText(const std::string& text,
90 const OnProgressCallback& onProgressCallback = nullptr);
91 WebSocketSendInfo ping(const std::string& text);
92
93 void close(uint16_t code = WebSocketCloseConstants::kNormalClosureCode,
94 const std::string& reason = WebSocketCloseConstants::kNormalClosureMessage);
95
96 void setOnMessageCallback(const OnMessageCallback& callback);
97 bool isOnMessageCallbackRegistered() const;
98 static void setTrafficTrackerCallback(const OnTrafficTrackerCallback& callback);
99 static void resetTrafficTrackerCallback();
100
101 ReadyState getReadyState() const;
102 static std::string readyStateToString(ReadyState readyState);
103
104 const std::string getUrl() const;
105 const WebSocketPerMessageDeflateOptions getPerMessageDeflateOptions() const;
106 int getPingInterval() const;
107 size_t bufferedAmount() const;
108
109 void enableAutomaticReconnection();
110 void disableAutomaticReconnection();
111 bool isAutomaticReconnectionEnabled() const;
112 void setMaxWaitBetweenReconnectionRetries(uint32_t maxWaitBetweenReconnectionRetries);
113 void setMinWaitBetweenReconnectionRetries(uint32_t minWaitBetweenReconnectionRetries);
114 uint32_t getMaxWaitBetweenReconnectionRetries() const;
115 uint32_t getMinWaitBetweenReconnectionRetries() const;
116 const std::vector<std::string>& getSubProtocols();
117
118 private:
119 WebSocketSendInfo sendMessage(const IXWebSocketSendData& message,
120 SendMessageKind sendMessageKind,
121 const OnProgressCallback& callback = nullptr);
122
123 bool isConnected() const;
124 bool isClosing() const;
125 void checkConnection(bool firstConnectionAttempt);
126 static void invokeTrafficTrackerCallback(size_t size, bool incoming);
127
128 // Server
129 WebSocketInitResult connectToSocket(std::unique_ptr<Socket>,
130 int timeoutSecs,
131 bool enablePerMessageDeflate);
132
133 WebSocketTransport _ws;
134
135 std::string _url;
136 WebSocketHttpHeaders _extraHeaders;
137
138 WebSocketPerMessageDeflateOptions _perMessageDeflateOptions;
139
140 SocketTLSOptions _socketTLSOptions;
141
142 mutable std::mutex _configMutex; // protect all config variables access
143
144 OnMessageCallback _onMessageCallback;
145 static OnTrafficTrackerCallback _onTrafficTrackerCallback;
146
147 std::atomic<bool> _stop;
148 std::thread _thread;
149 std::mutex _writeMutex;
150
151 // Automatic reconnection
152 std::atomic<bool> _automaticReconnection;
153 static const uint32_t kDefaultMaxWaitBetweenReconnectionRetries;
154 static const uint32_t kDefaultMinWaitBetweenReconnectionRetries;
155 uint32_t _maxWaitBetweenReconnectionRetries;
156 uint32_t _minWaitBetweenReconnectionRetries;
157
158 // Make the sleeping in the automatic reconnection cancellable
159 std::mutex _sleepMutex;
160 std::condition_variable _sleepCondition;
161
162 std::atomic<int> _handshakeTimeoutSecs;
163 static const int kDefaultHandShakeTimeoutSecs;
164
165 // enable or disable PONG frame response to received PING frame
166 bool _enablePong;
167 static const bool kDefaultEnablePong;
168
169 // Optional ping and pong timeout
170 int _pingIntervalSecs;
171 int _pingTimeoutSecs;
172 static const int kDefaultPingIntervalSecs;
173 static const int kDefaultPingTimeoutSecs;
174
175 // Subprotocols
176 std::vector<std::string> _subProtocols;
177
178 friend class WebSocketServer;
179 };
180} // namespace ix
181