rippled
WorkBase.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2016 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_APP_MISC_DETAIL_WORKBASE_H_INCLUDED
21 #define RIPPLE_APP_MISC_DETAIL_WORKBASE_H_INCLUDED
22 
23 #include <ripple/app/misc/detail/Work.h>
24 #include <ripple/protocol/BuildInfo.h>
25 #include <boost/asio.hpp>
26 #include <boost/beast/core/multi_buffer.hpp>
27 #include <boost/beast/http/empty_body.hpp>
28 #include <boost/beast/http/read.hpp>
29 #include <boost/beast/http/write.hpp>
30 
31 namespace ripple {
32 
33 namespace detail {
34 
35 template <class Impl>
36 class WorkBase : public Work
37 {
38 protected:
39  using error_code = boost::system::error_code;
40 
41 public:
42  using callback_type =
44 
45 protected:
46  using socket_type = boost::asio::ip::tcp::socket;
47  using endpoint_type = boost::asio::ip::tcp::endpoint;
48  using resolver_type = boost::asio::ip::tcp::resolver;
49  using query_type = resolver_type::query;
50  using request_type =
51  boost::beast::http::request<boost::beast::http::empty_body>;
52 
57  boost::asio::io_service& ios_;
58  boost::asio::io_service::strand strand_;
63  boost::beast::multi_buffer read_buf_;
64 
65 public:
66  WorkBase(
67  std::string const& host,
68  std::string const& path,
69  std::string const& port,
70  boost::asio::io_service& ios,
71  callback_type cb);
72  ~WorkBase();
73 
74  Impl&
75  impl()
76  {
77  return *static_cast<Impl*>(this);
78  }
79 
80  void
81  run() override;
82 
83  void
84  cancel() override;
85 
86  void
87  fail(error_code const& ec);
88 
89  void
90  onResolve(error_code const& ec, resolver_type::iterator it);
91 
92  void
93  onStart();
94 
95  void
96  onRequest(error_code const& ec);
97 
98  void
99  onResponse(error_code const& ec);
100 
101 private:
102  void
103  close();
104 };
105 
106 //------------------------------------------------------------------------------
107 
108 template <class Impl>
110  std::string const& host,
111  std::string const& path,
112  std::string const& port,
113  boost::asio::io_service& ios,
114  callback_type cb)
115  : host_(host)
116  , path_(path)
117  , port_(port)
118  , cb_(std::move(cb))
119  , ios_(ios)
120  , strand_(ios)
121  , resolver_(ios)
122  , socket_(ios)
123 {
124 }
125 
126 template <class Impl>
128 {
129  if (cb_)
130  cb_(make_error_code(boost::system::errc::not_a_socket),
131  std::move(res_));
132  close();
133 }
134 
135 template <class Impl>
136 void
138 {
139  if (!strand_.running_in_this_thread())
140  return ios_.post(
141  strand_.wrap(std::bind(&WorkBase::run, impl().shared_from_this())));
142 
143  resolver_.async_resolve(
144  query_type{host_, port_},
145  strand_.wrap(std::bind(
146  &WorkBase::onResolve,
147  impl().shared_from_this(),
148  std::placeholders::_1,
149  std::placeholders::_2)));
150 }
151 
152 template <class Impl>
153 void
155 {
156  if (!strand_.running_in_this_thread())
157  {
158  return ios_.post(strand_.wrap(
159  std::bind(&WorkBase::cancel, impl().shared_from_this())));
160  }
161 
162  error_code ec;
163  resolver_.cancel();
164  socket_.cancel(ec);
165 }
166 
167 template <class Impl>
168 void
170 {
171  if (cb_)
172  {
173  cb_(ec, std::move(res_));
174  cb_ = nullptr;
175  }
176 }
177 
178 template <class Impl>
179 void
180 WorkBase<Impl>::onResolve(error_code const& ec, resolver_type::iterator it)
181 {
182  if (ec)
183  return fail(ec);
184 
185  socket_.async_connect(
186  *it,
187  strand_.wrap(std::bind(
188  &Impl::onConnect,
189  impl().shared_from_this(),
190  std::placeholders::_1)));
191 }
192 
193 template <class Impl>
194 void
196 {
197  req_.method(boost::beast::http::verb::get);
198  req_.target(path_.empty() ? "/" : path_);
199  req_.version(11);
200  req_.set("Host", host_ + ":" + port_);
201  req_.set("User-Agent", BuildInfo::getFullVersionString());
202  req_.prepare_payload();
203  boost::beast::http::async_write(
204  impl().stream(),
205  req_,
206  strand_.wrap(std::bind(
207  &WorkBase::onRequest,
208  impl().shared_from_this(),
209  std::placeholders::_1)));
210 }
211 
212 template <class Impl>
213 void
215 {
216  if (ec)
217  return fail(ec);
218 
219  boost::beast::http::async_read(
220  impl().stream(),
221  read_buf_,
222  res_,
223  strand_.wrap(std::bind(
224  &WorkBase::onResponse,
225  impl().shared_from_this(),
226  std::placeholders::_1)));
227 }
228 
229 template <class Impl>
230 void
232 {
233  if (ec)
234  return fail(ec);
235 
236  close();
237  assert(cb_);
238  cb_(ec, std::move(res_));
239  cb_ = nullptr;
240 }
241 
242 template <class Impl>
243 void
245 {
246  if (socket_.is_open())
247  {
248  error_code ec;
249  socket_.shutdown(boost::asio::socket_base::shutdown_send, ec);
250  if (ec)
251  return;
252  socket_.close(ec);
253  }
254 }
255 
256 } // namespace detail
257 
258 } // namespace ripple
259 
260 #endif
ripple::detail::WorkBase::close
void close()
Definition: WorkBase.h:244
ripple::detail::WorkBase::resolver_
resolver_type resolver_
Definition: WorkBase.h:59
ripple::detail::WorkBase< WorkPlain >::endpoint_type
boost::asio::ip::tcp::endpoint endpoint_type
Definition: WorkBase.h:47
std::bind
T bind(T... args)
std::string
STL class.
ripple::detail::WorkBase::impl
Impl & impl()
Definition: WorkBase.h:75
ripple::detail::WorkBase< WorkPlain >::request_type
boost::beast::http::request< boost::beast::http::empty_body > request_type
Definition: WorkBase.h:51
ripple::detail::WorkBase::~WorkBase
~WorkBase()
Definition: WorkBase.h:127
ripple::detail::WorkBase::fail
void fail(error_code const &ec)
Definition: WorkBase.h:169
ripple::detail::WorkBase::ios_
boost::asio::io_service & ios_
Definition: WorkBase.h:57
ripple::detail::WorkBase< WorkPlain >::resolver_type
boost::asio::ip::tcp::resolver resolver_type
Definition: WorkBase.h:48
ripple::detail::WorkBase< WorkPlain >::query_type
resolver_type::query query_type
Definition: WorkBase.h:49
ripple::detail::WorkBase::host_
std::string host_
Definition: WorkBase.h:53
ripple::detail::WorkBase::socket_
socket_type socket_
Definition: WorkBase.h:60
std::function< void(error_code const &, response_type &&)>
ripple::detail::WorkBase::onResolve
void onResolve(error_code const &ec, resolver_type::iterator it)
Definition: WorkBase.h:180
ripple::detail::response_type
boost::beast::http::response< boost::beast::http::string_body > response_type
Definition: Work.h:31
ripple::detail::WorkBase::req_
request_type req_
Definition: WorkBase.h:61
ripple::detail::WorkBase::onStart
void onStart()
Definition: WorkBase.h:195
ripple::detail::WorkBase::port_
std::string port_
Definition: WorkBase.h:55
ripple::detail::WorkBase::WorkBase
WorkBase(std::string const &host, std::string const &path, std::string const &port, boost::asio::io_service &ios, callback_type cb)
Definition: WorkBase.h:109
ripple::detail::WorkBase
Definition: WorkBase.h:36
ripple::detail::WorkBase::cb_
callback_type cb_
Definition: WorkBase.h:56
ripple::detail::WorkBase::read_buf_
boost::beast::multi_buffer read_buf_
Definition: WorkBase.h:63
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::detail::WorkBase::cancel
void cancel() override
Definition: WorkBase.h:154
std
STL namespace.
ripple::detail::WorkBase::run
void run() override
Definition: WorkBase.h:137
ripple::detail::WorkBase< WorkPlain >::error_code
boost::system::error_code error_code
Definition: WorkBase.h:39
ripple::detail::WorkBase::onRequest
void onRequest(error_code const &ec)
Definition: WorkBase.h:214
ripple::detail::WorkBase::strand_
boost::asio::io_service::strand strand_
Definition: WorkBase.h:58
ripple::detail::WorkBase< WorkPlain >::socket_type
boost::asio::ip::tcp::socket socket_type
Definition: WorkBase.h:46
ripple::detail::WorkBase::onResponse
void onResponse(error_code const &ec)
Definition: WorkBase.h:231
ripple::detail::WorkBase::path_
std::string path_
Definition: WorkBase.h:54
ripple::detail::WorkBase::res_
response_type res_
Definition: WorkBase.h:62
ripple::detail::Work
Definition: Work.h:33