CppWAMP
C++11 client library for the WAMP protocol
tcpopener.hpp
1 /*------------------------------------------------------------------------------
2  Copyright Butterfly Energy Systems 2014-2015, 2022.
3  Distributed under the Boost Software License, Version 1.0.
4  http://www.boost.org/LICENSE_1_0.txt
5 ------------------------------------------------------------------------------*/
6 
7 #ifndef CPPWAMP_INTERNAL_TCPOPENER_HPP
8 #define CPPWAMP_INTERNAL_TCPOPENER_HPP
9 
10 #include <cassert>
11 #include <memory>
12 #include <string>
13 #include <boost/asio/connect.hpp>
14 #include <boost/asio/ip/tcp.hpp>
15 #include <boost/asio/strand.hpp>
16 #include "../asiodefs.hpp"
17 #include "../tcphost.hpp"
18 
19 namespace wamp
20 {
21 
22 namespace internal
23 {
24 
25 //------------------------------------------------------------------------------
26 class TcpOpener
27 {
28 public:
29  using Info = TcpHost;
30  using Socket = boost::asio::ip::tcp::socket;
31  using SocketPtr = std::unique_ptr<Socket>;
32 
33  template <typename TExecutorOrStrand>
34  TcpOpener(TExecutorOrStrand&& exec, Info info)
35  : strand_(std::forward<TExecutorOrStrand>(exec)),
36  info_(std::move(info))
37  {}
38 
39  IoStrand strand() {return strand_;}
40 
41  template <typename F>
42  void establish(F&& callback)
43  {
44  struct Resolved
45  {
46  TcpOpener* self;
47  typename std::decay<F>::type callback;
48 
49  void operator()(AsioErrorCode ec, tcp::resolver::iterator iterator)
50  {
51  if (ec)
52  {
53  self->resolver_.reset();
54  callback(ec, nullptr);
55  }
56  else
57  self->connect(iterator, std::move(callback));
58  }
59  };
60 
61  assert(!resolver_ && "Connect already in progress");
62 
63  resolver_.reset(new tcp::resolver(strand_));
64 
65  tcp::resolver::query query(info_.hostName(), info_.serviceName());
66 
67  // AsioConnector will keep this object alive until completion.
68  resolver_->async_resolve(query,
69  Resolved{this, std::forward<F>(callback)});
70  }
71 
72  void cancel()
73  {
74  if (resolver_)
75  resolver_->cancel();
76  if (socket_)
77  socket_->close();
78  }
79 
80 private:
81  using tcp = boost::asio::ip::tcp;
82 
83  template <typename F>
84  void connect(tcp::resolver::iterator iterator, F&& callback)
85  {
86  struct Connected
87  {
88  TcpOpener* self;
89  typename std::decay<F>::type callback;
90 
91  void operator()(AsioErrorCode ec, tcp::resolver::iterator)
92  {
93  self->resolver_.reset();
94  if (ec)
95  self->socket_.reset();
96  callback(ec, std::move(self->socket_));
97  self->socket_.reset();
98  }
99  };
100 
101  assert(!socket_);
102  socket_.reset(new Socket(strand_));
103  socket_->open(boost::asio::ip::tcp::v4());
104  info_.options().applyTo(*socket_);
105 
106  // AsioConnector will keep this object alive until completion.
107  boost::asio::async_connect(*socket_, iterator,
108  Connected{this, std::forward<F>(callback)});
109  }
110 
111  IoStrand strand_;
112  Info info_;
113  std::unique_ptr<tcp::resolver> resolver_;
114  SocketPtr socket_;
115 };
116 
117 } // namespace internal
118 
119 } // namespace wamp
120 
121 #endif // CPPWAMP_INTERNAL_TCPOPENER_HPP
wamp::IoStrand
boost::asio::strand< AnyIoExecutor > IoStrand
Serializes I/O operations.
Definition: asiodefs.hpp:41
wamp
Definition: anyhandler.hpp:36
wamp::AsioErrorCode
boost::system::error_code AsioErrorCode
Type used by Boost.Asio for reporting errors.
Definition: asiodefs.hpp:44