@@ -80,6 +80,8 @@ namespace web { namespace http
80
80
81
81
void close ()
82
82
{
83
+ std::lock_guard<std::mutex> lock (m_socket_lock);
84
+
83
85
// Ensures closed connections owned by request_context will not be put to pool when they are released.
84
86
m_keep_alive = false ;
85
87
@@ -90,7 +92,8 @@ namespace web { namespace http
90
92
91
93
boost::system::error_code cancel ()
92
94
{
93
- boost::system::error_code error;
95
+ std::lock_guard<std::mutex> lock (m_socket_lock);
96
+ boost::system::error_code error;
94
97
m_socket.cancel (error);
95
98
return error;
96
99
}
@@ -105,13 +108,18 @@ namespace web { namespace http
105
108
void set_keep_alive (bool keep_alive) { m_keep_alive = keep_alive; }
106
109
bool keep_alive () const { return m_keep_alive; }
107
110
108
- bool is_open () const { return m_socket.is_open (); }
111
+ bool is_open ()
112
+ {
113
+ std::lock_guard<std::mutex> lock (m_socket_lock);
114
+ return m_socket.is_open ();
115
+ }
109
116
bool is_ssl () const { return m_ssl_stream ? true : false ; }
110
117
111
118
template <typename Iterator, typename Handler>
112
119
void async_connect (const Iterator &begin, const Handler &handler)
113
120
{
114
- m_socket.async_connect (begin, handler);
121
+ std::lock_guard<std::mutex> lock (m_socket_lock);
122
+ m_socket.async_connect (begin, handler);
115
123
}
116
124
117
125
template <typename HandshakeHandler, typename CertificateHandler>
@@ -121,7 +129,8 @@ namespace web { namespace http
121
129
const HandshakeHandler &handshake_handler,
122
130
const CertificateHandler &cert_handler)
123
131
{
124
- assert (is_ssl ());
132
+ std::lock_guard<std::mutex> lock (m_socket_lock);
133
+ assert (is_ssl ());
125
134
126
135
// Check to turn on/off server certificate verification.
127
136
if (config.validate_certificates ())
@@ -139,7 +148,8 @@ namespace web { namespace http
139
148
template <typename ConstBufferSequence, typename Handler>
140
149
void async_write (ConstBufferSequence &buffer, const Handler &writeHandler)
141
150
{
142
- if (m_ssl_stream)
151
+ std::lock_guard<std::mutex> lock (m_socket_lock);
152
+ if (m_ssl_stream)
143
153
{
144
154
boost::asio::async_write (*m_ssl_stream, buffer, writeHandler);
145
155
}
@@ -152,7 +162,8 @@ namespace web { namespace http
152
162
template <typename MutableBufferSequence, typename CompletionCondition, typename Handler>
153
163
void async_read (MutableBufferSequence &buffer, const CompletionCondition &condition, const Handler &readHandler)
154
164
{
155
- if (m_ssl_stream)
165
+ std::lock_guard<std::mutex> lock (m_socket_lock);
166
+ if (m_ssl_stream)
156
167
{
157
168
boost::asio::async_read (*m_ssl_stream, buffer, condition, readHandler);
158
169
}
@@ -165,6 +176,7 @@ namespace web { namespace http
165
176
template <typename Handler>
166
177
void async_read_until (boost::asio::streambuf &buffer, const std::string &delim, const Handler &readHandler)
167
178
{
179
+ std::lock_guard<std::mutex> lock (m_socket_lock);
168
180
if (m_ssl_stream)
169
181
{
170
182
boost::asio::async_read_until (*m_ssl_stream, buffer, delim, readHandler);
@@ -191,8 +203,13 @@ namespace web { namespace http
191
203
192
204
void handle_pool_timer (const boost::system::error_code& ec);
193
205
206
+ // Guards concurrency access to socket/ssl::stream. This is necessary
207
+ // because timeouts and cancellation can touch the socket at the same time
208
+ // as normal request read/writing.
209
+ std::mutex m_socket_lock;
194
210
tcp::socket m_socket;
195
211
std::unique_ptr<boost::asio::ssl::stream<tcp::socket &> > m_ssl_stream;
212
+
196
213
boost::asio::deadline_timer m_pool_timer;
197
214
bool m_is_reused;
198
215
bool m_keep_alive;
@@ -355,14 +372,14 @@ namespace web { namespace http
355
372
{
356
373
m_ctx = ctx;
357
374
}
358
-
375
+
359
376
void start ()
360
377
{
361
378
assert (m_state == created);
362
379
assert (!m_ctx.expired ());
363
380
m_state = started;
364
-
365
- m_timer. expires_from_now (m_duration);
381
+
382
+ m_timer. expires_from_now (m_duration);
366
383
auto ctx = m_ctx;
367
384
m_timer.async_wait ([ctx](const boost::system::error_code& ec)
368
385
{
@@ -375,7 +392,7 @@ namespace web { namespace http
375
392
assert (m_state == started || m_state == timedout);
376
393
assert (!m_ctx.expired ());
377
394
if (m_timer.expires_from_now (m_duration) > 0 )
378
- {
395
+ {
379
396
auto ctx = m_ctx;
380
397
m_timer.async_wait ([ctx](const boost::system::error_code& ec)
381
398
{
@@ -408,7 +425,7 @@ namespace web { namespace http
408
425
}
409
426
}
410
427
}
411
-
428
+
412
429
enum timer_state
413
430
{
414
431
created,
@@ -555,8 +572,6 @@ namespace web { namespace http
555
572
{
556
573
if (auto ctx_lock = ctx_weak.lock ())
557
574
{
558
- // Cancel operations and all asio async handlers.
559
- ctx_lock->m_connection ->cancel ();
560
575
// Shut down transmissions, close the socket and prevent connection from being pooled.
561
576
ctx_lock->m_connection ->close ();
562
577
}
0 commit comments