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 
102 //------------------------------------------------------------------------------
103 
104 template <class Impl>
106  std::string const& host,
107  std::string const& path,
108  std::string const& port,
109  boost::asio::io_service& ios,
110  callback_type cb)
111  : host_(host)
112  , path_(path)
113  , port_(port)
114  , cb_(std::move(cb))
115  , ios_(ios)
116  , strand_(ios)
117  , resolver_(ios)
118  , socket_(ios)
119 {
120 }
121 
122 template <class Impl>
124 {
125  if (cb_)
126  cb_(make_error_code(boost::system::errc::not_a_socket),
127  std::move(res_));
128 }
129 
130 template <class Impl>
131 void
133 {
134  if (!strand_.running_in_this_thread())
135  return ios_.post(
136  strand_.wrap(std::bind(&WorkBase::run, impl().shared_from_this())));
137 
138  resolver_.async_resolve(
139  query_type{host_, port_},
140  strand_.wrap(std::bind(
141  &WorkBase::onResolve,
142  impl().shared_from_this(),
143  std::placeholders::_1,
144  std::placeholders::_2)));
145 }
146 
147 template <class Impl>
148 void
150 {
151  if (!strand_.running_in_this_thread())
152  {
153  return ios_.post(strand_.wrap(
154  std::bind(&WorkBase::cancel, impl().shared_from_this())));
155  }
156 
157  error_code ec;
158  resolver_.cancel();
159  socket_.cancel(ec);
160 }
161 
162 template <class Impl>
163 void
165 {
166  if (cb_)
167  {
168  cb_(ec, std::move(res_));
169  cb_ = nullptr;
170  }
171 }
172 
173 template <class Impl>
174 void
175 WorkBase<Impl>::onResolve(error_code const& ec, resolver_type::iterator it)
176 {
177  if (ec)
178  return fail(ec);
179 
180  socket_.async_connect(
181  *it,
182  strand_.wrap(std::bind(
183  &Impl::onConnect,
184  impl().shared_from_this(),
185  std::placeholders::_1)));
186 }
187 
188 template <class Impl>
189 void
191 {
192  req_.method(boost::beast::http::verb::get);
193  req_.target(path_.empty() ? "/" : path_);
194  req_.version(11);
195  req_.set("Host", host_ + ":" + port_);
196  req_.set("User-Agent", BuildInfo::getFullVersionString());
197  req_.prepare_payload();
198  boost::beast::http::async_write(
199  impl().stream(),
200  req_,
201  strand_.wrap(std::bind(
202  &WorkBase::onRequest,
203  impl().shared_from_this(),
204  std::placeholders::_1)));
205 }
206 
207 template <class Impl>
208 void
210 {
211  if (ec)
212  return fail(ec);
213 
214  boost::beast::http::async_read(
215  impl().stream(),
216  read_buf_,
217  res_,
218  strand_.wrap(std::bind(
219  &WorkBase::onResponse,
220  impl().shared_from_this(),
221  std::placeholders::_1)));
222 }
223 
224 template <class Impl>
225 void
227 {
228  if (ec)
229  return fail(ec);
230 
231  assert(cb_);
232  cb_(ec, std::move(res_));
233  cb_ = nullptr;
234 }
235 
236 } // namespace detail
237 
238 } // namespace ripple
239 
240 #endif
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:123
ripple::detail::WorkBase::fail
void fail(error_code const &ec)
Definition: WorkBase.h:164
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:175
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:190
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:105
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:149
std
STL namespace.
ripple::detail::WorkBase::run
void run() override
Definition: WorkBase.h:132
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:209
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:226
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