NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
datagram-transport.hpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2018, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #ifndef NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
27 #define NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
28 
29 #include "transport.hpp"
30 #include "socket-utils.hpp"
31 #include "core/global-io.hpp"
32 
33 #include <array>
34 
35 namespace nfd {
36 namespace face {
37 
38 struct Unicast {};
39 struct Multicast {};
40 
45 template<class Protocol, class Addressing = Unicast>
47 {
48 public:
49  typedef Protocol protocol;
50 
55  explicit
56  DatagramTransport(typename protocol::socket&& socket);
57 
58  ssize_t
59  getSendQueueLength() override;
60 
63  void
64  receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
65  const boost::system::error_code& error);
66 
67 protected:
68  void
69  doClose() override;
70 
71  void
72  doSend(Transport::Packet&& packet) override;
73 
74  void
75  handleSend(const boost::system::error_code& error,
76  size_t nBytesSent, const Block& payload);
77 
78  void
79  handleReceive(const boost::system::error_code& error,
80  size_t nBytesReceived);
81 
82  void
83  processErrorCode(const boost::system::error_code& error);
84 
85  bool
86  hasRecentlyReceived() const;
87 
88  void
90 
91  static EndpointId
92  makeEndpointId(const typename protocol::endpoint& ep);
93 
94 protected:
95  typename protocol::socket m_socket;
96  typename protocol::endpoint m_sender;
97 
99 
100 private:
101  std::array<uint8_t, ndn::MAX_NDN_PACKET_SIZE> m_receiveBuffer;
102  bool m_hasRecentlyReceived;
103 };
104 
105 
106 template<class T, class U>
107 DatagramTransport<T, U>::DatagramTransport(typename DatagramTransport::protocol::socket&& socket)
108  : m_socket(std::move(socket))
109  , m_hasRecentlyReceived(false)
110 {
111  boost::asio::socket_base::send_buffer_size sendBufferSizeOption;
112  boost::system::error_code error;
113  m_socket.get_option(sendBufferSizeOption, error);
114  if (error) {
115  NFD_LOG_FACE_WARN("Failed to obtain send queue capacity from socket: " << error.message());
116  this->setSendQueueCapacity(QUEUE_ERROR);
117  }
118  else {
119  this->setSendQueueCapacity(sendBufferSizeOption.value());
120  }
121 
122  m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
124  boost::asio::placeholders::error,
125  boost::asio::placeholders::bytes_transferred));
126 }
127 
128 template<class T, class U>
129 ssize_t
131 {
132  ssize_t queueLength = getTxQueueLength(m_socket.native_handle());
133  if (queueLength == QUEUE_ERROR) {
134  NFD_LOG_FACE_WARN("Failed to obtain send queue length from socket: " << std::strerror(errno));
135  }
136  return queueLength;
137 }
138 
139 template<class T, class U>
140 void
142 {
143  NFD_LOG_FACE_TRACE(__func__);
144 
145  if (m_socket.is_open()) {
146  // Cancel all outstanding operations and close the socket.
147  // Use the non-throwing variants and ignore errors, if any.
148  boost::system::error_code error;
149  m_socket.cancel(error);
150  m_socket.close(error);
151  }
152 
153  // Ensure that the Transport stays alive at least until
154  // all pending handlers are dispatched
155  getGlobalIoService().post([this] {
156  this->setState(TransportState::CLOSED);
157  });
158 }
159 
160 template<class T, class U>
161 void
163 {
164  NFD_LOG_FACE_TRACE(__func__);
165 
166  m_socket.async_send(boost::asio::buffer(packet.packet),
168  boost::asio::placeholders::error,
169  boost::asio::placeholders::bytes_transferred,
170  packet.packet));
171 }
172 
173 template<class T, class U>
174 void
175 DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
176  const boost::system::error_code& error)
177 {
178  if (error)
179  return processErrorCode(error);
180 
181  NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes from " << m_sender);
182 
183  bool isOk = false;
184  Block element;
185  std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
186  if (!isOk) {
187  NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << m_sender);
188  // This packet won't extend the face lifetime
189  return;
190  }
191  if (element.size() != nBytesReceived) {
192  NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
193  // This packet won't extend the face lifetime
194  return;
195  }
196  m_hasRecentlyReceived = true;
197 
198  Transport::Packet tp(std::move(element));
199  tp.remoteEndpoint = makeEndpointId(m_sender);
200  this->receive(std::move(tp));
201 }
202 
203 template<class T, class U>
204 void
205 DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error,
206  size_t nBytesReceived)
207 {
208  receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
209 
210  if (m_socket.is_open())
211  m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
213  boost::asio::placeholders::error,
214  boost::asio::placeholders::bytes_transferred));
215 }
216 
217 template<class T, class U>
218 void
219 DatagramTransport<T, U>::handleSend(const boost::system::error_code& error,
220  size_t nBytesSent, const Block& payload)
221 // 'payload' is unused; it's needed to retain the underlying Buffer
222 {
223  if (error)
224  return processErrorCode(error);
225 
226  NFD_LOG_FACE_TRACE("Successfully sent: " << nBytesSent << " bytes");
227 }
228 
229 template<class T, class U>
230 void
231 DatagramTransport<T, U>::processErrorCode(const boost::system::error_code& error)
232 {
233  NFD_LOG_FACE_TRACE(__func__);
234 
235  if (getState() == TransportState::CLOSING ||
236  getState() == TransportState::FAILED ||
237  getState() == TransportState::CLOSED ||
238  error == boost::asio::error::operation_aborted) {
239  // transport is shutting down, ignore any errors
240  return;
241  }
242 
243  if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
244  NFD_LOG_FACE_DEBUG("Permanent face ignores error: " << error.message());
245  return;
246  }
247 
248  NFD_LOG_FACE_ERROR("Send or receive operation failed: " << error.message());
249  this->setState(TransportState::FAILED);
250  doClose();
251 }
252 
253 template<class T, class U>
254 bool
256 {
257  return m_hasRecentlyReceived;
258 }
259 
260 template<class T, class U>
261 void
263 {
264  m_hasRecentlyReceived = false;
265 }
266 
267 template<class T, class U>
269 DatagramTransport<T, U>::makeEndpointId(const typename protocol::endpoint& ep)
270 {
271  return 0;
272 }
273 
274 } // namespace face
275 } // namespace nfd
276 
277 #endif // NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
void doSend(Transport::Packet &&packet) override
performs Transport specific operations to send a packet
void handleSend(const boost::system::error_code &error, size_t nBytesSent, const Block &payload)
#define NFD_LOG_FACE_TRACE(msg)
Log a message at TRACE level.
Definition: face-log.hpp:79
void doClose() override
performs Transport specific operations to close the transport
#define NFD_LOG_FACE_ERROR(msg)
Log a message at ERROR level.
Definition: face-log.hpp:91
void handleReceive(const boost::system::error_code &error, size_t nBytesReceived)
stores a packet along with the remote endpoint
Definition: transport.hpp:122
STL namespace.
const ssize_t QUEUE_ERROR
indicates that the transport was unable to retrieve the queue capacity/length
Definition: transport.hpp:108
detail::SimulatorIo & getGlobalIoService()
Definition: global-io.cpp:48
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
Implements Transport for datagram-based protocols.
static EndpointId makeEndpointId(const typename protocol::endpoint &ep)
void receiveDatagram(const uint8_t *buffer, size_t nBytesReceived, const boost::system::error_code &error)
Receive datagram, translate buffer into packet, deliver to parent class.
#define NFD_LOG_FACE_DEBUG(msg)
Log a message at DEBUG level.
Definition: face-log.hpp:82
size_t size() const
Get size of encoded wire, including Type-Length-Value.
Definition: block.cpp:301
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
void processErrorCode(const boost::system::error_code &error)
EndpointId remoteEndpoint
identifies the remote endpoint
Definition: transport.hpp:141
void post(const std::function< void()> &callback)
Definition: global-io.cpp:34
ssize_t getTxQueueLength(int fd)
obtain send queue length from a specified system socket
DatagramTransport(typename protocol::socket &&socket)
Construct datagram transport.
uint64_t EndpointId
identifies an endpoint on the link
Definition: transport.hpp:118
the lower part of a Face
Definition: transport.hpp:113
#define NFD_LOG_FACE_WARN(msg)
Log a message at WARN level.
Definition: face-log.hpp:88