NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
udp-factory.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "udp-factory.hpp"
27 #include "core/global-io.hpp"
29 
30 #ifdef __linux__
31 #include <cerrno> // for errno
32 #include <cstring> // for std::strerror()
33 #include <sys/socket.h> // for setsockopt()
34 #endif
35 
36 namespace nfd {
37 
38 using namespace boost::asio;
39 
40 NFD_LOG_INIT("UdpFactory");
41 
42 static const boost::asio::ip::address_v4 ALL_V4_ENDPOINT(
43  boost::asio::ip::address_v4::from_string("0.0.0.0"));
44 
45 static const boost::asio::ip::address_v6 ALL_V6_ENDPOINT(
46  boost::asio::ip::address_v6::from_string("::"));
47 
48 UdpFactory::UdpFactory(const std::string& defaultPort/* = "6363"*/)
49  : m_defaultPort(defaultPort)
50 {
51 }
52 
53 void
54 UdpFactory::prohibitEndpoint(const udp::Endpoint& endpoint)
55 {
56  using namespace boost::asio::ip;
57 
58  const address& address = endpoint.address();
59 
60  if (address.is_v4() && address == ALL_V4_ENDPOINT)
61  {
62  prohibitAllIpv4Endpoints(endpoint.port());
63  }
64  else if (endpoint.address().is_v6() && address == ALL_V6_ENDPOINT)
65  {
66  prohibitAllIpv6Endpoints(endpoint.port());
67  }
68 
69  NFD_LOG_TRACE("prohibiting UDP " << endpoint);
70 
71  m_prohibitedEndpoints.insert(endpoint);
72 }
73 
74 void
75 UdpFactory::prohibitAllIpv4Endpoints(const uint16_t port)
76 {
77  using namespace boost::asio::ip;
78 
79  for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
80  for (const address_v4& addr : nic.ipv4Addresses) {
81  if (addr != ALL_V4_ENDPOINT) {
82  prohibitEndpoint(udp::Endpoint(addr, port));
83  }
84  }
85 
86  if (nic.isBroadcastCapable() && nic.broadcastAddress != ALL_V4_ENDPOINT)
87  {
88  NFD_LOG_TRACE("prohibiting broadcast address: " << nic.broadcastAddress.to_string());
89  prohibitEndpoint(udp::Endpoint(nic.broadcastAddress, port));
90  }
91  }
92 
93  prohibitEndpoint(udp::Endpoint(address::from_string("255.255.255.255"), port));
94 }
95 
96 void
97 UdpFactory::prohibitAllIpv6Endpoints(const uint16_t port)
98 {
99  using namespace boost::asio::ip;
100 
101  for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
102  for (const address_v6& addr : nic.ipv6Addresses) {
103  if (addr != ALL_V6_ENDPOINT) {
104  prohibitEndpoint(udp::Endpoint(addr, port));
105  }
106  }
107  }
108 }
109 
110 shared_ptr<UdpChannel>
112  const time::seconds& timeout)
113 {
114  NFD_LOG_DEBUG("Creating unicast channel " << endpoint);
115 
116  shared_ptr<UdpChannel> channel = findChannel(endpoint);
117  if (static_cast<bool>(channel))
118  return channel;
119 
120  //checking if the endpoint is already in use for multicast face
121  shared_ptr<MulticastUdpFace> multicast = findMulticastFace(endpoint);
122  if (static_cast<bool>(multicast))
123  BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP unicast channel, local "
124  "endpoint is already allocated for a UDP multicast face"));
125 
126  if (endpoint.address().is_multicast()) {
127  BOOST_THROW_EXCEPTION(Error("This method is only for unicast channel. The provided "
128  "endpoint is multicast. Use createMulticastFace to "
129  "create a multicast face"));
130  }
131 
132  channel = make_shared<UdpChannel>(endpoint, timeout);
133  m_channels[endpoint] = channel;
134  prohibitEndpoint(endpoint);
135 
136  return channel;
137 }
138 
139 shared_ptr<UdpChannel>
140 UdpFactory::createChannel(const std::string& localIp,
141  const std::string& localPort,
142  const time::seconds& timeout)
143 {
144  using namespace boost::asio::ip;
145  udp::Endpoint endpoint(address::from_string(localIp), boost::lexical_cast<uint16_t>(localPort));
146  return createChannel(endpoint, timeout);
147 }
148 
149 shared_ptr<MulticastUdpFace>
151  const udp::Endpoint& multicastEndpoint,
152  const std::string& networkInterfaceName/* = ""*/)
153 {
154  // checking if the local and multicast endpoints are already in use for a multicast face
155  shared_ptr<MulticastUdpFace> face = findMulticastFace(localEndpoint);
156  if (static_cast<bool>(face)) {
157  if (face->getMulticastGroup() == multicastEndpoint)
158  return face;
159  else
160  BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, local "
161  "endpoint is already allocated for a UDP multicast face "
162  "on a different multicast group"));
163  }
164 
165  // checking if the local endpoint is already in use for a unicast channel
166  shared_ptr<UdpChannel> unicast = findChannel(localEndpoint);
167  if (static_cast<bool>(unicast)) {
168  BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, local "
169  "endpoint is already allocated for a UDP unicast channel"));
170  }
171 
172  if (m_prohibitedEndpoints.find(multicastEndpoint) != m_prohibitedEndpoints.end()) {
173  BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, "
174  "remote endpoint is owned by this NFD instance"));
175  }
176 
177  if (localEndpoint.address().is_v6() || multicastEndpoint.address().is_v6()) {
178  BOOST_THROW_EXCEPTION(Error("IPv6 multicast is not supported yet. Please provide an IPv4 "
179  "address"));
180  }
181 
182  if (localEndpoint.port() != multicastEndpoint.port()) {
183  BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, "
184  "both endpoints should have the same port number. "));
185  }
186 
187  if (!multicastEndpoint.address().is_multicast()) {
188  BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, "
189  "the multicast group given as input is not a multicast address"));
190  }
191 
192  ip::udp::socket receiveSocket(getGlobalIoService());
193  receiveSocket.open(multicastEndpoint.protocol());
194  receiveSocket.set_option(ip::udp::socket::reuse_address(true));
195  receiveSocket.bind(multicastEndpoint);
196 
197  ip::udp::socket sendSocket(getGlobalIoService());
198  sendSocket.open(multicastEndpoint.protocol());
199  sendSocket.set_option(ip::udp::socket::reuse_address(true));
200  sendSocket.set_option(ip::multicast::enable_loopback(false));
201  sendSocket.bind(udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
202  if (localEndpoint.address() != ALL_V4_ENDPOINT)
203  sendSocket.set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
204 
205  sendSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
206  localEndpoint.address().to_v4()));
207  receiveSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
208  localEndpoint.address().to_v4()));
209 
210 #ifdef __linux__
211  /*
212  * On Linux, if there is more than one MulticastUdpFace for the same multicast
213  * group but they are bound to different network interfaces, the socket needs
214  * to be bound to the specific interface using SO_BINDTODEVICE, otherwise the
215  * face will receive all packets sent to the other interfaces as well.
216  * This happens only on Linux. On OS X, the ip::multicast::join_group option
217  * is enough to get the desired behaviour.
218  */
219  if (!networkInterfaceName.empty()) {
220  if (::setsockopt(receiveSocket.native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
221  networkInterfaceName.c_str(), networkInterfaceName.size() + 1) < 0) {
222  BOOST_THROW_EXCEPTION(Error("Cannot bind multicast face to " + networkInterfaceName +
223  ": " + std::strerror(errno)));
224  }
225  }
226 #endif
227 
228  face = make_shared<MulticastUdpFace>(multicastEndpoint, FaceUri(localEndpoint),
229  std::move(receiveSocket), std::move(sendSocket));
230 
231  face->onFail.connectSingleShot([this, localEndpoint] (const std::string& reason) {
232  m_multicastFaces.erase(localEndpoint);
233  });
234  m_multicastFaces[localEndpoint] = face;
235 
236  return face;
237 }
238 
239 shared_ptr<MulticastUdpFace>
240 UdpFactory::createMulticastFace(const std::string& localIp,
241  const std::string& multicastIp,
242  const std::string& multicastPort,
243  const std::string& networkInterfaceName/* = ""*/)
244 {
245  udp::Endpoint localEndpoint(ip::address::from_string(localIp),
246  boost::lexical_cast<uint16_t>(multicastPort));
247  udp::Endpoint multicastEndpoint(ip::address::from_string(multicastIp),
248  boost::lexical_cast<uint16_t>(multicastPort));
249  return createMulticastFace(localEndpoint, multicastEndpoint, networkInterfaceName);
250 }
251 
252 void
254  ndn::nfd::FacePersistency persistency,
255  const FaceCreatedCallback& onCreated,
256  const FaceConnectFailedCallback& onConnectFailed)
257 {
259  BOOST_THROW_EXCEPTION(Error("UdpFactory::createFace does not support creating on-demand face"));
260  }
261 
262  BOOST_ASSERT(uri.isCanonical());
263 
264  boost::asio::ip::address ipAddress = boost::asio::ip::address::from_string(uri.getHost());
265  udp::Endpoint endpoint(ipAddress, boost::lexical_cast<uint16_t>(uri.getPort()));
266 
267  if (endpoint.address().is_multicast()) {
268  onConnectFailed("The provided address is multicast. Please use createMulticastFace method");
269  return;
270  }
271 
272  if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
273  onConnectFailed("Requested endpoint is prohibited "
274  "(reserved by this NFD or disallowed by face management protocol)");
275  return;
276  }
277 
278  // very simple logic for now
279  for (ChannelMap::iterator channel = m_channels.begin();
280  channel != m_channels.end();
281  ++channel)
282  {
283  if ((channel->first.address().is_v4() && endpoint.address().is_v4()) ||
284  (channel->first.address().is_v6() && endpoint.address().is_v6()))
285  {
286  channel->second->connect(endpoint, persistency, onCreated, onConnectFailed);
287  return;
288  }
289  }
290 
291  onConnectFailed("No channels available to connect to " +
292  boost::lexical_cast<std::string>(endpoint));
293 }
294 
295 shared_ptr<UdpChannel>
296 UdpFactory::findChannel(const udp::Endpoint& localEndpoint)
297 {
298  ChannelMap::iterator i = m_channels.find(localEndpoint);
299  if (i != m_channels.end())
300  return i->second;
301  else
302  return shared_ptr<UdpChannel>();
303 }
304 
305 shared_ptr<MulticastUdpFace>
306 UdpFactory::findMulticastFace(const udp::Endpoint& localEndpoint)
307 {
308  MulticastFaceMap::iterator i = m_multicastFaces.find(localEndpoint);
309  if (i != m_multicastFaces.end())
310  return i->second;
311  else
312  return shared_ptr<MulticastUdpFace>();
313 }
314 
315 std::list<shared_ptr<const Channel>>
317 {
318  std::list<shared_ptr<const Channel>> channels;
319  for (ChannelMap::const_iterator i = m_channels.begin(); i != m_channels.end(); ++i)
320  {
321  channels.push_back(i->second);
322  }
323 
324  return channels;
325 }
326 
327 } // namespace nfd
function< void(const std::string &reason)> FaceConnectFailedCallback
Prototype for the callback that is called when face is failed to get created.
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:36
virtual void createFace(const FaceUri &uri, ndn::nfd::FacePersistency persistency, const FaceCreatedCallback &onCreated, const FaceConnectFailedCallback &onConnectFailed) 1
Try to create Face using the supplied FaceUri.
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:44
static const boost::asio::ip::address_v6 ALL_V6_ENDPOINT(boost::asio::ip::address_v6::from_string("::"))
contains information about a network interface
UdpFactory(const std::string &defaultPort="6363")
Definition: udp-factory.cpp:48
virtual std::list< shared_ptr< const Channel > > getChannels() const
shared_ptr< UdpChannel > createChannel(const udp::Endpoint &localEndpoint, const time::seconds &timeout=time::seconds(600))
Create UDP-based channel using udp::Endpoint.
Exception of UdpFactory.
Definition: udp-factory.hpp:43
const std::string & getPort() const
get port
Definition: face-uri.hpp:123
std::vector< NetworkInterfaceInfo > listNetworkInterfaces()
List configured network interfaces on the system and their info.
Table::const_iterator iterator
Definition: cs-internal.hpp:41
bool isCanonical() const
determine whether this FaceUri is in canonical form
Definition: face-uri.cpp:507
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:38
shared_ptr< MulticastUdpFace > createMulticastFace(const udp::Endpoint &localEndpoint, const udp::Endpoint &multicastEndpoint, const std::string &networkInterfaceName="")
Create MulticastUdpFace using udp::Endpoint.
boost::asio::ip::udp::endpoint Endpoint
Definition: udp-channel.hpp:34
#define NFD_LOG_INIT(name)
Definition: logger.hpp:33
const std::string & getHost() const
get host (domain)
Definition: face-uri.hpp:116
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:35
function< void(const shared_ptr< Face > &newFace)> FaceCreatedCallback
Prototype for the callback called when face is created (as a response to incoming connection or after...
boost::asio::io_service & getGlobalIoService()
Definition: global-io.hpp:35
static const boost::asio::ip::address_v4 ALL_V4_ENDPOINT(boost::asio::ip::address_v4::from_string("0.0.0.0"))