Skip to content

Commit 9fbc300

Browse files
committed
Fix some issues with the (deprecated) synchronous client implementation running under tsan; also require C++11 in GNU compilers moving forward by default
1 parent 511dd04 commit 9fbc300

File tree

3 files changed

+59
-51
lines changed

3 files changed

+59
-51
lines changed

CMakeLists.txt

+5-9
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,12 @@ if (OPENSSL_FOUND)
7171
endif()
7272

7373
if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU)
74-
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
74+
# Use C++11 when using GNU compilers.
75+
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
7576
elseif (${CMAKE_CXX_COMPILER_ID} MATCHES Clang)
76-
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
77-
# We want to link in C++11 mode if we're using Clang and on OS X.
78-
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -ftemplate-depth=256 -std=c++11 -stdlib=libc++")
79-
else()
80-
# We just add the -Wall and a high enough template depth
81-
# flag for Clang in other systems.
82-
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -ftemplate-depth=256")
83-
endif()
77+
# We want to link in C++11 mode in Clang too, but also set a high enough
78+
# template depth for the template metaprogramming.
79+
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -ftemplate-depth=256 -std=c++11 -stdlib=libc++")
8480
endif()
8581

8682

boost/network/protocol/http/client/connection/sync_normal.hpp

+12-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// http://www.boost.org/LICENSE_1_0.txt)
1010

1111
#include <boost/asio/deadline_timer.hpp>
12+
#include <boost/asio/streambuf.hpp>
1213
#include <boost/network/protocol/http/algorithms/linearize.hpp>
1314
#include <boost/network/protocol/http/response.hpp>
1415
#include <boost/network/protocol/http/traits/resolver_policy.hpp>
@@ -97,7 +98,8 @@ struct http_sync_connection
9798
connection_base::read_body(socket_, response_, response_buffer);
9899
typename headers_range<basic_response<Tag> >::type connection_range =
99100
headers(response_)["Connection"];
100-
if (version_major == 1 && version_minor == 1 && !boost::empty(connection_range) &&
101+
if (version_major == 1 && version_minor == 1 &&
102+
!boost::empty(connection_range) &&
101103
boost::iequals(boost::begin(connection_range)->second, "close")) {
102104
close_socket();
103105
} else if (version_major == 1 && version_minor == 0) {
@@ -109,19 +111,22 @@ struct http_sync_connection
109111

110112
void close_socket() {
111113
timer_.cancel();
112-
if (!is_open()) { return;
113-
}
114+
if (!is_open()) {
115+
return;
116+
}
114117
boost::system::error_code ignored;
115118
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored);
116-
if (ignored != nullptr) { return;
117-
}
119+
if (ignored != nullptr) {
120+
return;
121+
}
118122
socket_.close(ignored);
119123
}
120124

121125
private:
122126
void handle_timeout(boost::system::error_code const& ec) {
123-
if (!ec) { close_socket();
124-
}
127+
if (!ec) {
128+
close_socket();
129+
}
125130
}
126131

127132
int timeout_;

boost/network/protocol/http/policies/pooled_connection.hpp

+42-35
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
// (See accompanying file LICENSE_1_0.txt or copy at
88
// http://www.boost.org/LICENSE_1_0.txt)
99

10-
#include <boost/network/protocol/http/traits/resolver_policy.hpp>
11-
1210
#include <boost/algorithm/string/predicate.hpp>
1311
#include <boost/network/protocol/http/client/connection/sync_base.hpp>
1412
#include <boost/network/protocol/http/response.hpp>
13+
#include <boost/network/protocol/http/traits/resolver_policy.hpp>
1514
#include <boost/shared_ptr.hpp>
15+
#include <boost/thread/mutex.hpp>
1616
#include <boost/unordered_map.hpp>
1717
#include <utility>
1818

@@ -37,7 +37,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
3737
system::error_code const&)> body_callback_function_type;
3838
typedef function<bool(string_type&)> body_generator_function_type;
3939

40-
void cleanup() { host_connection_map().swap(host_connections); }
40+
void cleanup() { host_connection_map().swap(host_connections_); }
4141

4242
struct connection_impl {
4343
typedef function<shared_ptr<connection_impl>(
@@ -47,10 +47,10 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
4747
get_connection_function;
4848

4949
connection_impl(
50-
resolver_type& resolver, bool follow_redirect, string_type /*unused*/const& host,
51-
string_type const& port, resolver_function_type resolve,
52-
get_connection_function get_connection, bool https,
53-
bool always_verify_peer, int timeout,
50+
resolver_type& resolver, bool follow_redirect,
51+
string_type /*unused*/ const& host, string_type const& port,
52+
resolver_function_type resolve, get_connection_function get_connection,
53+
bool https, bool always_verify_peer, int timeout,
5454
optional<string_type> const& certificate_filename =
5555
optional<string_type>(),
5656
optional<string_type> const& verify_path = optional<string_type>(),
@@ -77,7 +77,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
7777
(void)port;
7878
}
7979

80-
basic_response<Tag> send_request(string_type /*unused*/const& method,
80+
basic_response<Tag> send_request(string_type const& method,
8181
basic_request<Tag> request_, bool get_body,
8282
body_callback_function_type callback,
8383
body_generator_function_type generator) {
@@ -86,7 +86,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
8686

8787
private:
8888
basic_response<Tag> send_request_impl(
89-
string_type /*unused*/const& method, basic_request<Tag> request_, bool get_body,
89+
string_type const& method, basic_request<Tag> request_, bool get_body,
9090
body_callback_function_type callback,
9191
body_generator_function_type generator) {
9292
// TODO(dberris): review parameter necessity.
@@ -113,8 +113,7 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
113113

114114
try {
115115
pimpl->read_status(response_, response_buffer);
116-
}
117-
catch (boost::system::system_error& e) {
116+
} catch (boost::system::system_error& e) {
118117
if (!retry && e.code() == boost::asio::error::eof) {
119118
retry = true;
120119
pimpl->init_socket(request_.host(),
@@ -182,49 +181,57 @@ struct pooled_connection_policy : resolver_policy<Tag>::type {
182181

183182
typedef shared_ptr<connection_impl> connection_ptr;
184183

185-
typedef unordered_map<string_type, connection_ptr> host_connection_map;
186-
host_connection_map host_connections;
184+
typedef unordered_map<string_type, weak_ptr<connection_impl>> host_connection_map;
185+
boost::mutex host_mutex_;
186+
host_connection_map host_connections_;
187187
bool follow_redirect_;
188188
int timeout_;
189189

190190
connection_ptr get_connection(
191191
resolver_type& resolver, basic_request<Tag> const& request_,
192192
bool always_verify_peer,
193-
optional<string_type> /*unused*/const& certificate_filename =
193+
optional<string_type> const& certificate_filename =
194194
optional<string_type>(),
195195
optional<string_type> const& verify_path = optional<string_type>(),
196196
optional<string_type> const& certificate_file = optional<string_type>(),
197197
optional<string_type> const& private_key_file = optional<string_type>(),
198198
optional<string_type> const& ciphers = optional<string_type>()) {
199199
string_type index =
200200
(request_.host() + ':') + lexical_cast<string_type>(request_.port());
201-
connection_ptr connection_;
202-
typename host_connection_map::iterator it = host_connections.find(index);
203-
if (it == host_connections.end()) {
204-
connection_.reset(new connection_impl(
205-
resolver, follow_redirect_, request_.host(),
206-
lexical_cast<string_type>(request_.port()),
207-
boost::bind(&pooled_connection_policy<Tag, version_major,
208-
version_minor>::resolve,
209-
this, boost::arg<1>(), boost::arg<2>(), boost::arg<3>()),
210-
boost::bind(&pooled_connection_policy<Tag, version_major,
211-
version_minor>::get_connection,
212-
this, boost::arg<1>(), boost::arg<2>(),
213-
always_verify_peer, boost::arg<3>(), boost::arg<4>(),
214-
boost::arg<5>(), boost::arg<6>(), boost::arg<7>()),
215-
boost::iequals(request_.protocol(), string_type("https")),
216-
always_verify_peer, timeout_, certificate_filename, verify_path,
217-
certificate_file, private_key_file, ciphers, 0));
218-
host_connections.insert(std::make_pair(index, connection_));
219-
return connection_;
201+
boost::mutex::scoped_lock lock(host_mutex_);
202+
auto it = host_connections_.find(index);
203+
if (it != host_connections_.end()) {
204+
// We've found an existing connection; but we should check if that
205+
// connection hasn't been deleted yet.
206+
auto result = it->second.lock();
207+
if (!result) return result;
220208
}
221-
return it->second;
209+
210+
connection_ptr connection(new connection_impl(
211+
resolver, follow_redirect_, request_.host(),
212+
lexical_cast<string_type>(request_.port()),
213+
// resolver function
214+
boost::bind(&pooled_connection_policy<Tag, version_major,
215+
version_minor>::resolve,
216+
this, boost::arg<1>(), boost::arg<2>(), boost::arg<3>()),
217+
// connection factory
218+
boost::bind(&pooled_connection_policy<Tag, version_major,
219+
version_minor>::get_connection,
220+
this, boost::arg<1>(), boost::arg<2>(), always_verify_peer,
221+
boost::arg<3>(), boost::arg<4>(), boost::arg<5>(),
222+
boost::arg<6>(), boost::arg<7>()),
223+
boost::iequals(request_.protocol(), string_type("https")),
224+
always_verify_peer, timeout_, certificate_filename, verify_path,
225+
certificate_file, private_key_file, ciphers, 0));
226+
host_connections_.insert(std::make_pair(index, connection));
227+
return connection;
222228
}
223229

224230
pooled_connection_policy(bool cache_resolved, bool follow_redirect,
225231
int timeout)
226232
: resolver_base(cache_resolved),
227-
host_connections(),
233+
host_mutex_(),
234+
host_connections_(),
228235
follow_redirect_(follow_redirect),
229236
timeout_(timeout) {}
230237
};

0 commit comments

Comments
 (0)