Fabcoin Core  0.16.2
P2P Digital Currency
UDP.h
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16  */
22 #pragma once
23 
24 #include <atomic>
25 #include <memory>
26 #include <vector>
27 #include <deque>
28 #include <array>
29 
30 #include <libdevcore/Guards.h>
31 #include <libdevcrypto/Common.h>
32 #include <libdevcore/SHA3.h>
33 #include <libdevcore/Log.h>
34 #include <libdevcore/RLP.h>
35 #include "Common.h"
36 namespace ba = boost::asio;
37 namespace bi = ba::ip;
38 
39 namespace dev
40 {
41 namespace p2p
42 {
43 
44 struct RLPXWarn: public LogChannel { static const char* name(); static const int verbosity = 0; };
45 struct RLPXNote: public LogChannel { static const char* name(); static const int verbosity = 1; };
46 
52 {
53 public:
54  UDPDatagram(bi::udp::endpoint const& _ep): locus(_ep) {}
55  UDPDatagram(bi::udp::endpoint const& _ep, bytes _data): data(_data), locus(_ep) {}
56  bi::udp::endpoint const& endpoint() const { return locus; }
57 
59 protected:
60  bi::udp::endpoint locus;
61 };
62 
67 {
68  static uint32_t futureFromEpoch(std::chrono::seconds _sec) { return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now() + _sec).time_since_epoch()).count()); }
69  static uint32_t secondsSinceEpoch() { return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::seconds>((std::chrono::system_clock::now()).time_since_epoch()).count()); }
70  static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp);
71 
72  RLPXDatagramFace(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {}
73 
74  virtual h256 sign(Secret const& _from);
75  virtual uint8_t packetType() const = 0;
76 
77  virtual void streamRLP(RLPStream&) const = 0;
78  virtual void interpretRLP(bytesConstRef _bytes) = 0;
79 };
80 
85 {
86  virtual bool send(UDPDatagram const& _msg) = 0;
87  virtual void disconnect() = 0;
88 };
89 
94 {
95  virtual void onDisconnected(UDPSocketFace*) {}
96  virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0;
97 };
98 
106 template <typename Handler, unsigned MaxDatagramSize>
107 class UDPSocket: UDPSocketFace, public std::enable_shared_from_this<UDPSocket<Handler, MaxDatagramSize>>
108 {
109 public:
110  enum { maxDatagramSize = MaxDatagramSize };
111  static_assert((unsigned)maxDatagramSize < 65507u, "UDP datagrams cannot be larger than 65507 bytes");
112 
114  UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, bi::udp::endpoint _endpoint): m_host(_host), m_endpoint(_endpoint), m_socket(_io) { m_started.store(false); m_closed.store(true); };
115 
117  UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_endpoint(bi::udp::v4(), _port), m_socket(_io) { m_started.store(false); m_closed.store(true); };
118  virtual ~UDPSocket() { disconnect(); }
119 
121  void connect();
122 
124  bool send(UDPDatagram const& _datagram);
125 
127  bool isOpen() { return !m_closed; }
128 
130  void disconnect() { disconnectWithError(boost::asio::error::connection_reset); }
131 
132 protected:
133  void doRead();
134 
135  void doWrite();
136 
137  void disconnectWithError(boost::system::error_code _ec);
138 
139  std::atomic<bool> m_started;
140  std::atomic<bool> m_closed;
141 
143  bi::udp::endpoint m_endpoint;
144 
146  std::deque<UDPDatagram> m_sendQ;
147  std::array<byte, maxDatagramSize> m_recvData;
148  bi::udp::endpoint m_recvEndpoint;
149  bi::udp::socket m_socket;
150 
152  boost::system::error_code m_socketError;
153 };
154 
155 template <typename Handler, unsigned MaxDatagramSize>
157 {
158  bool expect = false;
159  if (!m_started.compare_exchange_strong(expect, true))
160  return;
161 
162  m_socket.open(bi::udp::v4());
163  try
164  {
165  m_socket.bind(m_endpoint);
166  }
167  catch (...)
168  {
169  m_socket.bind(bi::udp::endpoint(bi::udp::v4(), m_endpoint.port()));
170  }
171 
172  // clear write queue so reconnect doesn't send stale messages
173  Guard l(x_sendQ);
174  m_sendQ.clear();
175 
176  m_closed = false;
177  doRead();
178 }
179 
180 template <typename Handler, unsigned MaxDatagramSize>
182 {
183  if (m_closed)
184  return false;
185 
186  Guard l(x_sendQ);
187  m_sendQ.push_back(_datagram);
188  if (m_sendQ.size() == 1)
189  doWrite();
190 
191  return true;
192 }
193 
194 template <typename Handler, unsigned MaxDatagramSize>
196 {
197  if (m_closed)
198  return;
199 
201  m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len)
202  {
203  if (m_closed)
204  return disconnectWithError(_ec);
205 
206  if (_ec != boost::system::errc::success)
207  clog(NetWarn) << "Receiving UDP message failed. " << _ec.value() << ":" << _ec.message();
208 
209  if (_len)
210  m_host.onReceived(this, m_recvEndpoint, bytesConstRef(m_recvData.data(), _len));
211  doRead();
212  });
213 }
214 
215 template <typename Handler, unsigned MaxDatagramSize>
217 {
218  if (m_closed)
219  return;
220 
221  const UDPDatagram& datagram = m_sendQ[0];
223  bi::udp::endpoint endpoint(datagram.endpoint());
224  m_socket.async_send_to(boost::asio::buffer(datagram.data), endpoint, [this, self, endpoint](boost::system::error_code _ec, std::size_t)
225  {
226  if (m_closed)
227  return disconnectWithError(_ec);
228 
229  if (_ec != boost::system::errc::success)
230  clog(NetWarn) << "Failed delivering UDP message. " << _ec.value() << ":" << _ec.message();
231 
232  Guard l(x_sendQ);
233  m_sendQ.pop_front();
234  if (m_sendQ.empty())
235  return;
236  doWrite();
237  });
238 }
239 
240 template <typename Handler, unsigned MaxDatagramSize>
242 {
243  // If !started and already stopped, shutdown has already occured. (EOF or Operation canceled)
244  if (!m_started && m_closed && !m_socket.is_open() /* todo: veirfy this logic*/)
245  return;
246 
247  assert(_ec);
248  {
249  // disconnect-operation following prior non-zero errors are ignored
250  Guard l(x_socketError);
251  if (m_socketError != boost::system::error_code())
252  return;
253  m_socketError = _ec;
254  }
255  // TODO: (if non-zero error) schedule high-priority writes
256 
257  // prevent concurrent disconnect
258  bool expected = true;
259  if (!m_started.compare_exchange_strong(expected, false))
260  return;
261 
262  // set m_closed to true to prevent undeliverable egress messages
263  bool wasClosed = m_closed;
264  m_closed = true;
265 
266  // close sockets
267  boost::system::error_code ec;
268  m_socket.shutdown(bi::udp::socket::shutdown_both, ec);
269  m_socket.close();
270 
271  // socket never started if it never left stopped-state (pre-handshake)
272  if (wasClosed)
273  return;
274 
275  m_host.onDisconnected(this);
276 }
277 
278 }
279 }
bool send(UDPDatagram const &_datagram)
Send datagram.
Definition: UDP.h:181
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
std::deque< UDPDatagram > m_sendQ
Queue for egress data.
Definition: UDP.h:146
UDPSocketEvents & m_host
Interface which owns this socket.
Definition: UDP.h:142
bi::udp::socket m_socket
Boost asio udp socket.
Definition: UDP.h:149
bi::udp::endpoint m_recvEndpoint
Endpoint data was received from.
Definition: UDP.h:148
void doWrite()
Definition: UDP.h:216
UDP Interface Handler must implement UDPSocketEvents.
Definition: UDP.h:107
size_t count
Definition: ExecStats.cpp:37
#define expect(bit)
static uint32_t secondsSinceEpoch()
Definition: UDP.h:69
assert(len-trim+(2 *lenIndices)<=WIDTH)
bi::udp::endpoint m_endpoint
Endpoint which we listen to.
Definition: UDP.h:143
void disconnect()
Disconnect socket.
Definition: UDP.h:130
static const char * name()
Definition: UDP.cpp:27
UDPSocket(ba::io_service &_io, UDPSocketEvents &_host, bi::udp::endpoint _endpoint)
Create socket for specific endpoint.
Definition: UDP.h:114
bool isOpen()
Returns if socket is open.
Definition: UDP.h:127
std::array< byte, maxDatagramSize > m_recvData
Buffer for ingress data.
Definition: UDP.h:147
static const int verbosity
Definition: UDP.h:44
boost::system::error_code m_socketError
Set when shut down due to error.
Definition: UDP.h:152
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
virtual ~UDPSocket()
Definition: UDP.h:118
bi::udp::endpoint locus
Definition: UDP.h:60
std::atomic< bool > m_started
Atomically ensure connection is started once. Start cannot occur unless m_started is false...
Definition: UDP.h:139
std::vector< byte > bytes
Definition: Common.h:75
Mutex x_sendQ
Definition: UDP.h:145
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
void disconnectWithError(boost::system::error_code _ec)
Definition: UDP.h:241
Mutex x_socketError
Mutex for error which can be set from host or IO thread.
Definition: UDP.h:151
RLPX Datagram which can be signed.
Definition: UDP.h:66
static uint32_t futureFromEpoch(std::chrono::seconds _sec)
Definition: UDP.h:68
void doRead()
Definition: UDP.h:195
UDPDatagram(bi::udp::endpoint const &_ep, bytes _data)
Definition: UDP.h:55
Signature sign(Secret const &_k, h256 const &_hash)
Returns siganture of message hash.
Definition: Common.cpp:233
virtual void onDisconnected(UDPSocketFace *)
Definition: UDP.h:95
RLPXDatagramFace(bi::udp::endpoint const &_ep)
Definition: UDP.h:72
bi::udp::endpoint const & endpoint() const
Definition: UDP.h:56
UDPSocket(ba::io_service &_io, UDPSocketEvents &_host, unsigned _port)
Create socket which listens to all ports.
Definition: UDP.h:117
#define clog(X)
Definition: Log.h:295
The default logging channels.
Definition: Log.h:130
Interface which UDPSocket will implement.
Definition: UDP.h:84
std::mutex Mutex
Definition: Guards.h:37
void connect()
Socket will begin listening for and delivering packets.
Definition: UDP.h:156
Class for writing to an RLP bytestream.
Definition: RLP.h:383
uint8_t const * data
Definition: sha3.h:19
UDP Datagram.
Definition: UDP.h:51
UDPDatagram(bi::udp::endpoint const &_ep)
Definition: UDP.h:54
Interface which a UDPSocket&#39;s owner must implement.
Definition: UDP.h:93
std::atomic< bool > m_closed
Connection availability.
Definition: UDP.h:140