40
40
#pragma GCC diagnostic ignored "-Wconversion"
41
41
#pragma GCC diagnostic ignored "-Wunused-parameter"
42
42
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
43
+ #include < websocketpp/config/asio_client.hpp>
43
44
#include < websocketpp/config/asio_no_tls_client.hpp>
44
45
#include < websocketpp/client.hpp>
45
46
#pragma GCC diagnostic pop
55
56
#else
56
57
#define _WEBSOCKETPP_NULLPTR_TOKEN_ 0
57
58
#endif
59
+ #ifndef _MS_WINDOWS
60
+ #include < websocketpp/config/asio_client.hpp>
61
+ #endif
58
62
#include < websocketpp/config/asio_no_tls_client.hpp>
59
63
#include < websocketpp/client.hpp>
60
64
#pragma warning( pop )
@@ -83,8 +87,7 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
83
87
{
84
88
private:
85
89
enum State {
86
- UNINITIALIZED,
87
- INITIALIZED,
90
+ CREATED,
88
91
CONNECTING,
89
92
CONNECTED,
90
93
CLOSING,
@@ -95,23 +98,9 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
95
98
wspp_client (websocket_client_config config) :
96
99
_websocket_client_impl (std::move(config)),
97
100
m_work (utility::details::make_unique<boost::asio::io_service::work>(m_service)),
98
- m_state (UNINITIALIZED ),
101
+ m_state (CREATED ),
99
102
m_num_sends (0 )
100
- {
101
- // TODO tls here.
102
- initialize_impl<websocketpp::config::asio_client>();
103
- }
104
-
105
- template <typename WebsocketConfigType>
106
- void initialize_impl ()
107
- {
108
- auto &client = boost::get<websocketpp::client<WebsocketConfigType>>(m_client);
109
-
110
- client.clear_access_channels (websocketpp::log::alevel::all);
111
- client.clear_error_channels (websocketpp::log::alevel::all);
112
- client.init_asio (&m_service);
113
- m_state = INITIALIZED;
114
- }
103
+ {}
115
104
116
105
~wspp_client ()
117
106
{
@@ -123,11 +112,10 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
123
112
124
113
// Now, what states could we be in?
125
114
switch (m_state) {
126
- case UNINITIALIZED:
127
115
case DESTROYED:
128
116
// These should be impossible
129
117
std::abort ();
130
- case INITIALIZED :
118
+ case CREATED :
131
119
case CLOSED:
132
120
// In these cases, nothing need be done.
133
121
lock.unlock ();
@@ -167,14 +155,22 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
167
155
168
156
pplx::task<void > close (websocket_close_status status, const utility::string_t & reason)
169
157
{
170
- // TODO tls here.
171
- return close_impl<websocketpp::config::asio_client>(status, reason);
158
+ #ifndef _MS_WINDOWS
159
+ if (m_client->is_tls_client ())
160
+ {
161
+ return close_impl<websocketpp::config::asio_tls_client>(status, reason);
162
+ }
163
+ else
164
+ #endif
165
+ {
166
+ return close_impl<websocketpp::config::asio_client>(status, reason);
167
+ }
172
168
}
173
169
174
- template <typename WebsocketConfigType >
170
+ template <typename WebsocketConfig >
175
171
pplx::task<void > close_impl (websocket_close_status status, const utility::string_t & reason)
176
172
{
177
- auto &client = boost::get<websocketpp:: client<WebsocketConfigType>>(m_client );
173
+ auto &client = m_client-> client <WebsocketConfig>( );
178
174
179
175
std::lock_guard<std::mutex> lock (m_receive_queue_lock);
180
176
if (m_state == CONNECTED)
@@ -193,16 +189,43 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
193
189
194
190
pplx::task<void > connect ()
195
191
{
196
- // TODO tls here.
197
- return connect_impl<websocketpp::config::asio_client>();
192
+ #ifndef _MS_WINDOWS
193
+ if (m_uri.scheme () == U (" wss" ))
194
+ {
195
+ m_client = std::unique_ptr<websocketpp_client_base>(new websocketpp_tls_client ());
196
+
197
+ // Options specific to TLS client.
198
+ auto &client = m_client->client <websocketpp::config::asio_tls_client>();
199
+ client.set_tls_init_handler ([this ](websocketpp::connection_hdl)
200
+ {
201
+ auto sslContext = websocketpp::lib::shared_ptr<boost::asio::ssl::context>(new boost::asio::ssl::context (boost::asio::ssl::context::sslv23));
202
+ sslContext->set_default_verify_paths ();
203
+ sslContext->set_options (boost::asio::ssl::context::default_workarounds);
204
+ sslContext->set_verify_mode (boost::asio::ssl::context::verify_peer);
205
+ // Like done with the http_client certificate verification needs more steps for iOS and Android.
206
+ sslContext->set_verify_callback (boost::asio::ssl::rfc2818_verification (m_uri.host ()));
207
+ return sslContext;
208
+ });
209
+ return connect_impl<websocketpp::config::asio_tls_client>();
210
+ }
211
+ else
212
+ #endif
213
+ {
214
+ m_client = std::unique_ptr<websocketpp_client_base>(new websocketpp_client ());
215
+ return connect_impl<websocketpp::config::asio_client>();
216
+ }
198
217
}
199
-
218
+
200
219
template <typename WebsocketConfigType>
201
220
pplx::task<void > connect_impl ()
202
221
{
203
- auto &client = boost::get<websocketpp:: client<WebsocketConfigType>>(m_client );
222
+ auto &client = m_client-> client <WebsocketConfigType>( );
204
223
205
- _ASSERTE (m_state == INITIALIZED);
224
+ client.clear_access_channels (websocketpp::log::alevel::all);
225
+ client.clear_error_channels (websocketpp::log::alevel::all);
226
+ client.init_asio (&m_service);
227
+
228
+ _ASSERTE (m_state == CREATED);
206
229
client.set_open_handler ([this ](websocketpp::connection_hdl)
207
230
{
208
231
_ASSERTE (m_state == CONNECTING);
@@ -219,7 +242,7 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
219
242
m_connect_tce.set_exception (websocket_exception (" Connection attempt failed." ));
220
243
});
221
244
222
- client.set_message_handler ([this ](websocketpp::connection_hdl, WebsocketConfigType ::message_type::ptr msg)
245
+ client.set_message_handler ([this ](websocketpp::connection_hdl, websocketpp::config::asio_client ::message_type::ptr msg)
223
246
{
224
247
_ASSERTE (m_state >= CONNECTED && m_state < CLOSED);
225
248
websocket_incoming_message ws_incoming_message;
@@ -283,7 +306,7 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
283
306
}
284
307
285
308
// Add any request headers specified by the user.
286
- const auto & headers = config () .headers ();
309
+ const auto & headers = m_config .headers ();
287
310
for (const auto & header : headers)
288
311
{
289
312
if (!utility::details::str_icmp (header.first , g_subProtocolHeader))
@@ -295,7 +318,7 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
295
318
// Add any specified subprotocols.
296
319
if (headers.has (g_subProtocolHeader))
297
320
{
298
- const std::vector<utility::string_t > protocols = config () .subprotocols ();
321
+ const std::vector<utility::string_t > protocols = m_config .subprotocols ();
299
322
for (const auto & value : protocols)
300
323
{
301
324
con->add_subprotocol (utility::conversions::to_utf8string (value), ec);
@@ -395,7 +418,16 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
395
418
396
419
void send_msg (websocket_outgoing_message &msg)
397
420
{
398
- send_msg_impl<websocketpp::config::asio_client>(msg);
421
+ #ifndef _MS_WINDOWS
422
+ if (m_client->is_tls_client ())
423
+ {
424
+ send_msg_impl<websocketpp::config::asio_tls_client>(msg);
425
+ }
426
+ else
427
+ #endif
428
+ {
429
+ send_msg_impl<websocketpp::config::asio_client>(msg);
430
+ }
399
431
}
400
432
401
433
template <typename WebsocketClientType>
@@ -445,7 +477,7 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
445
477
// First try to acquire the data (Get a pointer to the next already allocated contiguous block of data)
446
478
// If acquire succeeds, send the data over the socket connection, there is no copy of data from stream to temporary buffer.
447
479
// If acquire fails, copy the data to a temporary buffer managed by sp_allocated and send it over the socket connection.
448
- std::shared_ptr<uint8_t > sp_allocated ( nullptr , []( uint8_t *) {}) ;
480
+ std::shared_ptr<uint8_t > sp_allocated;
449
481
size_t acquired_size = 0 ;
450
482
uint8_t * ptr;
451
483
auto read_task = pplx::task_from_result ();
@@ -473,27 +505,27 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
473
505
}
474
506
else
475
507
{
476
- // Acquire succeeded, assign the acquired pointer to sp_allocated. Keep an empty custom destructor
508
+ // Acquire succeeded, assign the acquired pointer to sp_allocated. Use an empty custom destructor
477
509
// so that the data is not released when sp_allocated goes out of scope. The streambuf will manage its memory.
478
510
sp_allocated.reset (ptr, [](uint8_t *) {});
479
511
}
480
512
481
- auto client = boost::get<websocketpp::client<WebsocketClientType>>(&m_client);
482
- read_task.then ([this_client, client, msg, sp_allocated, length]()
513
+ read_task.then ([this_client, msg, sp_allocated, length]()
483
514
{
515
+ auto &client = this_client->m_client ->client <WebsocketClientType>();
484
516
websocketpp::lib::error_code ec;
485
517
switch (msg._m_impl ->message_type ())
486
518
{
487
519
case websocket_message_type::text_message:
488
- client-> send (
520
+ client. send (
489
521
this_client->m_con ,
490
522
sp_allocated.get (),
491
523
length,
492
524
websocketpp::frame::opcode::text,
493
525
ec);
494
526
break ;
495
527
case websocket_message_type::binary_message:
496
- client-> send (
528
+ client. send (
497
529
this_client->m_con ,
498
530
sp_allocated.get (),
499
531
length,
@@ -570,8 +602,53 @@ class wspp_client : public _websocket_client_impl, public std::enable_shared_fro
570
602
std::unique_ptr<boost::asio::io_service::work> m_work;
571
603
std::thread m_thread;
572
604
573
- boost::variant<
574
- websocketpp::client<websocketpp::config::asio_client>> m_client;
605
+ // Perform type erasure to set the websocketpp client in use at runtime
606
+ // after construction based on the URI.
607
+ struct websocketpp_client_base
608
+ {
609
+ virtual ~websocketpp_client_base () _noexcept {}
610
+ template <typename WebsocketConfig>
611
+ websocketpp::client<WebsocketConfig> & client ()
612
+ {
613
+ if (is_tls_client ())
614
+ {
615
+ return reinterpret_cast <websocketpp::client<WebsocketConfig> &>(tls_client ());
616
+ }
617
+ else
618
+ {
619
+ return reinterpret_cast <websocketpp::client<WebsocketConfig> &>(non_tls_client ());
620
+ }
621
+ }
622
+ virtual websocketpp::client<websocketpp::config::asio_client> & non_tls_client ()
623
+ {
624
+ throw std::bad_cast ();
625
+ }
626
+ virtual websocketpp::client<websocketpp::config::asio_tls_client> & tls_client ()
627
+ {
628
+ throw std::bad_cast ();
629
+ }
630
+ virtual bool is_tls_client () const = 0;
631
+ };
632
+ struct websocketpp_client : websocketpp_client_base
633
+ {
634
+ websocketpp::client<websocketpp::config::asio_client> & non_tls_client () override
635
+ {
636
+ return m_client;
637
+ }
638
+ bool is_tls_client () const override { return false ; }
639
+ websocketpp::client<websocketpp::config::asio_client> m_client;
640
+ };
641
+ struct websocketpp_tls_client : websocketpp_client_base
642
+ {
643
+ websocketpp::client<websocketpp::config::asio_tls_client> & tls_client () override
644
+ {
645
+ return m_client;
646
+ }
647
+ bool is_tls_client () const override { return true ; }
648
+ websocketpp::client<websocketpp::config::asio_tls_client> m_client;
649
+ };
650
+ std::unique_ptr<websocketpp_client_base> m_client;
651
+
575
652
websocketpp::connection_hdl m_con;
576
653
577
654
pplx::task_completion_event<void > m_connect_tce;
0 commit comments