tcp-factory.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "tcp-factory.hpp"
27 #include "core/logger.hpp"
28 
29 namespace nfd {
30 namespace face {
31 
32 namespace ip = boost::asio::ip;
33 
34 NFD_LOG_INIT("TcpFactory");
36 
37 const std::string&
39 {
40  static std::string id("tcp");
41  return id;
42 }
43 
44 void
47 {
48  // tcp
49  // {
50  // listen yes
51  // port 6363
52  // enable_v4 yes
53  // enable_v6 yes
54  // }
55 
56  if (!configSection) {
57  if (!context.isDryRun && !m_channels.empty()) {
58  NFD_LOG_WARN("Cannot disable tcp4 and tcp6 channels after initialization");
59  }
60  return;
61  }
62 
63  bool wantListen = true;
64  uint16_t port = 6363;
65  bool enableV4 = true;
66  bool enableV6 = true;
67 
68  for (const auto& pair : *configSection) {
69  const std::string& key = pair.first;
70 
71  if (key == "listen") {
72  wantListen = ConfigFile::parseYesNo(pair, "face_system.tcp");
73  }
74  else if (key == "port") {
75  port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.tcp");
76  }
77  else if (key == "enable_v4") {
78  enableV4 = ConfigFile::parseYesNo(pair, "face_system.tcp");
79  }
80  else if (key == "enable_v6") {
81  enableV6 = ConfigFile::parseYesNo(pair, "face_system.tcp");
82  }
83  else {
84  BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.tcp." + key));
85  }
86  }
87 
88  if (!enableV4 && !enableV6) {
89  BOOST_THROW_EXCEPTION(ConfigFile::Error(
90  "IPv4 and IPv6 TCP channels have been disabled. Remove face_system.tcp section to disable "
91  "TCP channels or enable at least one channel type."));
92  }
93 
94  if (!context.isDryRun) {
95  providedSchemes.insert("tcp");
96 
97  if (enableV4) {
98  tcp::Endpoint endpoint(ip::tcp::v4(), port);
99  shared_ptr<TcpChannel> v4Channel = this->createChannel(endpoint);
100  if (wantListen && !v4Channel->isListening()) {
101  v4Channel->listen(context.addFace, nullptr);
102  }
103  providedSchemes.insert("tcp4");
104  }
105  else if (providedSchemes.count("tcp4") > 0) {
106  NFD_LOG_WARN("Cannot close tcp4 channel after its creation");
107  }
108 
109  if (enableV6) {
110  tcp::Endpoint endpoint(ip::tcp::v6(), port);
111  shared_ptr<TcpChannel> v6Channel = this->createChannel(endpoint);
112  if (wantListen && !v6Channel->isListening()) {
113  v6Channel->listen(context.addFace, nullptr);
114  }
115  providedSchemes.insert("tcp6");
116  }
117  else if (providedSchemes.count("tcp6") > 0) {
118  NFD_LOG_WARN("Cannot close tcp6 channel after its creation");
119  }
120  }
121 }
122 
123 void
124 TcpFactory::createFace(const FaceUri& uri,
125  ndn::nfd::FacePersistency persistency,
126  bool wantLocalFieldsEnabled,
127  const FaceCreatedCallback& onCreated,
128  const FaceCreationFailedCallback& onFailure)
129 {
130  BOOST_ASSERT(uri.isCanonical());
131 
132  if (persistency != ndn::nfd::FACE_PERSISTENCY_PERSISTENT) {
133  NFD_LOG_TRACE("createFace only supports FACE_PERSISTENCY_PERSISTENT");
134  onFailure(406, "Outgoing TCP faces only support persistent persistency");
135  return;
136  }
137 
138  tcp::Endpoint endpoint(ip::address::from_string(uri.getHost()),
139  boost::lexical_cast<uint16_t>(uri.getPort()));
140 
141  if (endpoint.address().is_multicast()) {
142  NFD_LOG_TRACE("createFace cannot create multicast faces");
143  onFailure(406, "Cannot create multicast TCP faces");
144  return;
145  }
146 
147  if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
148  NFD_LOG_TRACE("Requested endpoint is prohibited "
149  "(reserved by NFD or disallowed by face management protocol)");
150  onFailure(406, "Requested endpoint is prohibited");
151  return;
152  }
153 
154  if (wantLocalFieldsEnabled && !endpoint.address().is_loopback()) {
155  NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
156  onFailure(406, "Local fields can only be enabled on faces with local scope");
157  return;
158  }
159 
160  // very simple logic for now
161  for (const auto& i : m_channels) {
162  if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
163  (i.first.address().is_v6() && endpoint.address().is_v6())) {
164  i.second->connect(endpoint, wantLocalFieldsEnabled, onCreated, onFailure);
165  return;
166  }
167  }
168 
169  NFD_LOG_TRACE("No channels available to connect to " + boost::lexical_cast<std::string>(endpoint));
170  onFailure(504, "No channels available to connect");
171 }
172 
173 void
174 TcpFactory::prohibitEndpoint(const tcp::Endpoint& endpoint)
175 {
176  if (endpoint.address().is_v4() &&
177  endpoint.address() == ip::address_v4::any()) {
178  prohibitAllIpv4Endpoints(endpoint.port());
179  }
180  else if (endpoint.address().is_v6() &&
181  endpoint.address() == ip::address_v6::any()) {
182  prohibitAllIpv6Endpoints(endpoint.port());
183  }
184 
185  NFD_LOG_TRACE("prohibiting TCP " << endpoint);
186  m_prohibitedEndpoints.insert(endpoint);
187 }
188 
189 void
190 TcpFactory::prohibitAllIpv4Endpoints(uint16_t port)
191 {
193  for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
194  for (const auto& addr : nic.ipv4Addresses) {
195  if (addr != ip::address_v4::any()) {
196  prohibitEndpoint(tcp::Endpoint(addr, port));
197  }
198  }
199  }
200 }
201 
202 void
203 TcpFactory::prohibitAllIpv6Endpoints(uint16_t port)
204 {
206  for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) {
207  for (const auto& addr : nic.ipv6Addresses) {
208  if (addr != ip::address_v6::any()) {
209  prohibitEndpoint(tcp::Endpoint(addr, port));
210  }
211  }
212  }
213 }
214 
215 shared_ptr<TcpChannel>
217 {
218  auto channel = findChannel(endpoint);
219  if (channel)
220  return channel;
221 
222  channel = make_shared<TcpChannel>(endpoint);
223  m_channels[endpoint] = channel;
224  prohibitEndpoint(endpoint);
225 
226  NFD_LOG_DEBUG("Channel [" << endpoint << "] created");
227  return channel;
228 }
229 
230 shared_ptr<TcpChannel>
231 TcpFactory::createChannel(const std::string& localIp, const std::string& localPort)
232 {
233  tcp::Endpoint endpoint(ip::address::from_string(localIp),
234  boost::lexical_cast<uint16_t>(localPort));
235  return createChannel(endpoint);
236 }
237 
238 std::vector<shared_ptr<const Channel>>
240 {
241  return getChannelsFromMap(m_channels);
242 }
243 
244 shared_ptr<TcpChannel>
245 TcpFactory::findChannel(const tcp::Endpoint& localEndpoint) const
246 {
247  auto i = m_channels.find(localEndpoint);
248  if (i != m_channels.end())
249  return i->second;
250  else
251  return nullptr;
252 }
253 
254 } // namespace face
255 } // namespace nfd
shared_ptr< TcpChannel > createChannel(const tcp::Endpoint &localEndpoint)
Create TCP-based channel using tcp::Endpoint.
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:161
static const std::string & getId()
Definition: tcp-factory.cpp:38
std::set< std::string > providedSchemes
FaceUri schemes provided by this ProtocolFactory.
std::vector< shared_ptr< const Channel > > getChannels() const override
static bool parseYesNo(const ConfigSection &node, const std::string &key, const std::string &sectionName)
parse a config option that can be either "yes" or "no"
Definition: config-file.cpp:62
void createFace(const FaceUri &uri, ndn::nfd::FacePersistency persistency, bool wantLocalFieldsEnabled, const FaceCreatedCallback &onCreated, const FaceCreationFailedCallback &onFailure) override
Try to create Face using the supplied FaceUri.
#define NFD_REGISTER_PROTOCOL_FACTORY(PF)
registers a protocol factory
std::vector< NetworkInterfaceInfo > listNetworkInterfaces()
List configured network interfaces on the system and their info.
#define NFD_LOG_WARN(expression)
Definition: logger.hpp:163
context for processing a config section in ProtocolFactory
Definition: face-system.hpp:77
static std::vector< shared_ptr< const Channel > > getChannelsFromMap(const ChannelMap &channelMap)
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
boost::asio::ip::tcp::endpoint Endpoint
Definition: tcp-channel.hpp:35
void processConfig(OptionalConfigSection configSection, FaceSystem::ConfigContext &context) override
process face_system.tcp config section
Definition: tcp-factory.cpp:45
boost::optional< const ConfigSection & > OptionalConfigSection
an optional config file section
Definition: config-file.hpp:41
function< void(uint32_t status, const std::string &reason)> FaceCreationFailedCallback
Prototype for the callback that is invoked when the face fails to be created.
Definition: channel.hpp:44
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:160
function< void(const shared_ptr< Face > &newFace)> FaceCreatedCallback
Prototype for the callback that is invoked when the face is created (as a response to incoming connec...
Definition: channel.hpp:38