CppServer  1.0.0.0
C++ Server Library
websocket_ssl_client.cpp
Go to the documentation of this file.
1 
10 
11 namespace CppServer {
12 namespace Asio {
13 
14 WebSocketSSLClient::WebSocketSSLClient(std::shared_ptr<Service> service, std::shared_ptr<asio::ssl::context> context, const std::string& uri)
15  : _id(CppCommon::UUID::Generate()),
16  _service(service),
17  _context(context),
18  _uri(uri),
19  _initialized(false),
20  _connected(false),
21  _messages_sent(0),
22  _messages_received(0),
23  _bytes_sent(0),
24  _bytes_received(0)
25 {
26  assert((service != nullptr) && "ASIO service is invalid!");
27  if (service == nullptr)
28  throw CppCommon::ArgumentException("ASIO service is invalid!");
29 
30  assert((context != nullptr) && "SSL context is invalid!");
31  if (context == nullptr)
32  throw CppCommon::ArgumentException("SSL context is invalid!");
33 
34  InitAsio();
35 }
36 
37 void WebSocketSSLClient::InitAsio()
38 {
39  assert(!_initialized && "Asio is already initialed!");
40  if (_initialized)
41  return;
42 
43  // Setup WebSocket client core Asio service
44  websocketpp::lib::error_code ec;
45  _core.init_asio(_service->service().get(), ec);
46  if (ec)
47  {
48  SendError(ec);
49  return;
50  }
51 
52  _initialized = true;
53 }
54 
56 {
57  assert(_initialized && "Asio is not initialed!");
58  if (!_initialized)
59  return false;
60 
61  if (IsConnected())
62  return false;
63 
64  // Post the connect routine
65  auto self(this->shared_from_this());
66  _service->service()->post([this, self]()
67  {
68  websocketpp::lib::error_code ec;
69 
70  // Setup WebSocket client core logging
71  _core.set_access_channels(websocketpp::log::alevel::none);
72  _core.set_error_channels(websocketpp::log::elevel::none);
73 
74  // Setup WebSocket server core handlers
75  _core.set_open_handler([this](websocketpp::connection_hdl connection) { Connected(connection); });
76  _core.set_close_handler([this](websocketpp::connection_hdl connection) { Disconnected(connection); });
77  _core.set_tls_init_handler([this](websocketpp::connection_hdl connection) { return _context; });
78 
79  // Get the client connection
80  WebSocketSSLClientCore::connection_ptr connection_ptr = _core.get_connection(_uri, ec);
81  if (ec)
82  {
83  SendError(ec);
85  return;
86  }
87 
88  // Setup WebSocket client handlers
89  connection_ptr->set_message_handler([this](websocketpp::connection_hdl connection, WebSocketSSLMessage message)
90  {
91  size_t size = message->get_raw_payload().size();
92 
93  // Update statistic
94  ++_messages_received;
95  _bytes_received += size;
96 
97  // Call the message received handler
98  onReceived(message);
99  });
100  connection_ptr->set_fail_handler([this](websocketpp::connection_hdl connection)
101  {
102  WebSocketSSLServerCore::connection_ptr con = _core.get_con_from_hdl(connection);
103  websocketpp::lib::error_code ec = con->get_ec();
104  SendError(ec);
105  Disconnected(connection);
106  });
107 
108  // Note that connect here only requests a connection. No network messages are
109  // exchanged until the event loop starts running in the next line.
110  _core.connect(connection_ptr);
111  });
112 
113  return true;
114 }
115 
116 void WebSocketSSLClient::Connected(websocketpp::connection_hdl connection)
117 {
118  // Reset statistic
119  _messages_sent = 0;
120  _messages_received = 0;
121  _bytes_sent = 0;
122  _bytes_received = 0;
123 
124  // Update the connected state
125  _connection = connection;
126  _connected = true;
127 
128  // Call the client connected handler
129  onConnected();
130 }
131 
132 bool WebSocketSSLClient::Disconnect(bool dispatch, websocketpp::close::status::value code, const std::string& reason)
133 {
134  if (!IsConnected())
135  return false;
136 
137  auto self(this->shared_from_this());
138  auto disconnect = [this, self, code, reason]()
139  {
140  // Close the client connection
141  websocketpp::lib::error_code ec;
142  _core.close(_connection, code, reason, ec);
143  if (ec)
144  SendError(ec);
145  };
146 
147  // Dispatch or post the disconnect routine
148  if (dispatch)
149  _service->Dispatch(disconnect);
150  else
151  _service->Post(disconnect);
152 
153  return true;
154 }
155 
156 void WebSocketSSLClient::Disconnected(websocketpp::connection_hdl connection)
157 {
158  // Update the connected state
159  _connection.reset();
160  _connected = false;
161 
162  // Call the client disconnected handler
163  onDisconnected();
164 }
165 
167 {
168  if (!Disconnect())
169  return false;
170 
171  while (IsConnected())
172  CppCommon::Thread::Yield();
173 
174  return Connect();
175 }
176 
177 size_t WebSocketSSLClient::Send(const void* buffer, size_t size, websocketpp::frame::opcode::value opcode)
178 {
179  assert((buffer != nullptr) && "Pointer to the buffer should not be equal to 'nullptr'!");
180  assert((size > 0) && "Buffer size should be greater than zero!");
181  if ((buffer == nullptr) || (size == 0))
182  return 0;
183 
184  if (!IsConnected())
185  return 0;
186 
187  websocketpp::lib::error_code ec;
188  _core.send(_connection, buffer, size, opcode, ec);
189  if (ec)
190  {
191  SendError(ec);
192  return 0;
193  }
194 
195  // Update statistic
196  ++_messages_sent;
197  _bytes_sent += size;
198 
199  return size;
200 }
201 
202 size_t WebSocketSSLClient::Send(const std::string& text, websocketpp::frame::opcode::value opcode)
203 {
204  if (!IsConnected())
205  return 0;
206 
207  websocketpp::lib::error_code ec;
208  _core.send(_connection, text, opcode, ec);
209  if (ec)
210  {
211  SendError(ec);
212  return 0;
213  }
214 
215  size_t size = text.size();
216 
217  // Update statistic
218  ++_messages_sent;
219  _bytes_sent += size;
220 
221  return size;
222 }
223 
225 {
226  if (!IsConnected())
227  return 0;
228 
229  websocketpp::lib::error_code ec;
230  _core.send(_connection, message, ec);
231  if (ec)
232  {
233  SendError(ec);
234  return 0;
235  }
236 
237  size_t size = message->get_raw_payload().size();
238 
239  // Update statistic
240  ++_messages_sent;
241  _bytes_sent += size;
242 
243  return size;
244 }
245 
246 void WebSocketSSLClient::SendError(std::error_code ec)
247 {
248  onError(ec.value(), ec.category().name(), ec.message());
249 }
250 
251 } // namespace Asio
252 } // namespace CppServer
virtual void onConnected()
Handle client connected notification.
WebSocketSSLClient(std::shared_ptr< Service > service, std::shared_ptr< asio::ssl::context > context, const std::string &uri)
Initialize WebSocket client with a given Asio service, SSL context and server URI address...
std::shared_ptr< asio::ssl::context > & context() noexcept
Get the client SSL context.
bool Disconnect(websocketpp::close::status::value code=websocketpp::close::status::normal, const std::string &reason="")
Disconnect the client.
virtual void onError(int error, const std::string &category, const std::string &message)
Handle error notification.
C++ Server project definitions.
Definition: asio.h:24
WebSocketSSLConnection::message_ptr WebSocketSSLMessage
WebSocket SSL message.
Definition: websocket.h:40
virtual void onReceived(const WebSocketSSLMessage &message)
Handle message received notification.
size_t Send(const void *buffer, size_t size, websocketpp::frame::opcode::value opcode=websocketpp::frame::opcode::binary)
Send data to the server.
WebSocket SSL client definition.
bool Reconnect()
Reconnect the client.
virtual void onDisconnected()
Handle client disconnected notification.
bool IsConnected() const noexcept
Is the client connected?
std::shared_ptr< Service > & service() noexcept
Get the Asio service.