Virtual Testbed
Ship dynamics simulator for extreme conditions
remote_client.hh
1 #ifndef VTESTBED_SERVER_REMOTE_CLIENT_HH
2 #define VTESTBED_SERVER_REMOTE_CLIENT_HH
3 
4 #include <unistdx/base/log_message>
5 #include <unistdx/base/websocketbuf>
6 #include <unistdx/io/fildesbuf>
7 #include <unistdx/net/pstream>
8 #include <unistdx/net/socket>
9 
10 #include <vtestbed/core/testbed.hh>
11 #include <vtestbed/server/remote_client_state.hh>
12 
13 namespace vtb {
14 
15  namespace srv {
16 
17  class websocketbuf:
18  public sys::basic_websocketbuf<char,std::char_traits<char>>,
19  public sys::basic_fildesbuf<char,std::char_traits<char>,sys::socket>
20  {
21 
22  public:
23 
24  inline explicit
25  websocketbuf(sys::socket&& s):
26  sys::basic_websocketbuf<char,std::char_traits<char>>(),
27  sys::basic_fildesbuf<char,std::char_traits<char>,sys::socket>(std::move(s))
28  {}
29 
30  };
31 
32  template <class T>
33  class Remote_client {
34 
35  private:
37  typedef sys::pstream stream_type;
38  typedef stream_type::ipacket_guard ipacket_guard;
39  typedef sys::opacket_guard<stream_type> opacket_guard;
40 
41  private:
42  websocketbuf _buffer;
43  sys::socket_address _address;
44  Remote_client_state _state = Remote_client_state::Initial;
45  bool _verbose = false;
46 
47  public:
48 
50  sys::socket&& socket,
51  const sys::socket_address& address,
52  bool is_server
53  ):
54  _buffer(std::move(socket)),
55  _address(address) {
56  _buffer.role(
57  is_server
58  ? websocketbuf::role_type::server
59  : websocketbuf::role_type::client
60  );
61  }
62 
64  _buffer(std::move(rhs._buffer.fd())),
65  _address(rhs._address),
66  _state(rhs._state),
67  _verbose(rhs._verbose) {}
68 
69  ~Remote_client() {
70  _buffer.fd().shutdown(sys::shutdown_flag::read_write);
71  _buffer.fd().close();
72  }
73 
74  bool
75  handshake() {
76  if (_state != Remote_client_state::Initial) {
77  return handshake_succeded();
78  }
79  if (_buffer.handshake()) {
80  state(Remote_client_state::Handshake_succeeded);
81  }
82  return handshake_succeded();
83  }
84 
85  void
86  process(const sys::epoll_event& ev, testbed_type& testbed) {
87  fill();
88  if (handshake_succeded()) {
89  if (_buffer.read_packet()) {
90  pull(testbed);
91  }
92  }
93  }
94 
95  void
96  pull(testbed_type& testbed) {
97  if (!handshake_succeded()) {
98  return;
99  }
100  try {
101  stream_type s(&_buffer);
102  ipacket_guard guard(s.rdbuf());
103  s >> testbed;
104  } catch (const std::exception& err) {
105  this->error("Unable to receive packet: _", err.what());
106  }
107  }
108 
109  void
110  push(const testbed_type& testbed) {
111  if (!handshake_succeded()) {
112  return;
113  }
114  try {
115  stream_type s(&_buffer);
116  opacket_guard guard(s);
117  s.begin_packet();
118  s << testbed;
119  s.end_packet();
120  } catch (const std::exception& err) {
121  this->error("Unable to send packet: _", err.what());
122  }
123  }
124 
125  void
126  fill() {
127  auto n1 = _buffer.available();
128  _buffer.pubfill();
129  auto n2 = _buffer.available();
130  this->info("_ received _ bytes", _address, n2-n1);
131  }
132 
133  void
134  flush() {
135  if (!_buffer.dirty()) {
136  return;
137  }
138  try {
139  auto n1 = _buffer.remaining();
140  _buffer.pubflush();
141  auto n2 = _buffer.remaining();
142  this->info("_ sent _ bytes", _address, n1-n2);
143  } catch (const sys::bad_call& err) {
144  if (err.errc() != std::errc::broken_pipe) {
145  throw;
146  }
147  }
148  }
149 
150  inline sys::socket&
151  socket() noexcept {
152  return _buffer.fd();
153  }
154 
155  inline const sys::socket&
156  socket() const noexcept {
157  return _buffer.fd();
158  }
159 
160  inline const sys::socket_address&
161  address() const noexcept {
162  return _address;
163  }
164 
165  inline bool
166  is_server() const noexcept {
167  return _buffer.role() == websocketbuf::role_type::server;
168  }
169 
170  inline bool
171  is_client() const noexcept {
172  return _buffer.role() == websocketbuf::role_type::client;
173  }
174 
175  inline bool
176  handshake_succeded() const noexcept {
177  return _state == Remote_client_state::Handshake_succeeded;
178  }
179 
180  inline bool
181  handshake_failed() const noexcept {
182  return _state == Remote_client_state::Handshake_failed;
183  }
184 
185  inline void
186  verbose(bool rhs) noexcept {
187  _verbose = rhs;
188  }
189 
190  private:
191 
192  inline void
193  state(Remote_client_state rhs) {
194  _state = rhs;
195  this->info("_ _", _address, _state);
196  }
197 
198  template <class ... Args>
199  inline void
200  info(const Args& ... args) {
201  if (_verbose) {
202  sys::log_message("client", args ...);
203  }
204  }
205 
206  template <class ... Args>
207  inline void
208  error(const Args& ... args) {
209  sys::log_message("client", args ...);
210  }
211 
212  };
213 
214  }
215 
216 }
217 
218 #endif // vim:filetype=cpp
Main namespace.
Definition: convert.hh:9