tcp-factory.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2019, 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 #include "tcp-factory.hpp"
27 
28 namespace nfd {
29 namespace face {
30 
31 namespace ip = boost::asio::ip;
32 
33 NFD_LOG_INIT(TcpFactory);
35 
36 const std::string&
38 {
39  static std::string id("tcp");
40  return id;
41 }
42 
43 void
44 TcpFactory::doProcessConfig(OptionalConfigSection configSection,
46 {
47  // tcp
48  // {
49  // listen yes
50  // port 6363
51  // enable_v4 yes
52  // enable_v6 yes
53  // }
54 
55  m_wantCongestionMarking = context.generalConfig.wantCongestionMarking;
56 
57  if (!configSection) {
58  if (!context.isDryRun && !m_channels.empty()) {
59  NFD_LOG_WARN("Cannot disable TCP channels after initialization");
60  }
61  return;
62  }
63 
64  bool wantListen = true;
65  uint16_t port = 6363;
66  bool enableV4 = true;
67  bool enableV6 = true;
68  IpAddressPredicate local;
69  bool isLocalConfigured = false;
70 
71  for (const auto& pair : *configSection) {
72  const std::string& key = pair.first;
73 
74  if (key == "listen") {
75  wantListen = ConfigFile::parseYesNo(pair, "face_system.tcp");
76  }
77  else if (key == "port") {
78  port = ConfigFile::parseNumber<uint16_t>(pair, "face_system.tcp");
79  }
80  else if (key == "enable_v4") {
81  enableV4 = ConfigFile::parseYesNo(pair, "face_system.tcp");
82  }
83  else if (key == "enable_v6") {
84  enableV6 = ConfigFile::parseYesNo(pair, "face_system.tcp");
85  }
86  else if (key == "local") {
87  isLocalConfigured = true;
88  for (const auto& localPair : pair.second) {
89  const std::string& localKey = localPair.first;
90  if (localKey == "whitelist") {
91  local.parseWhitelist(localPair.second);
92  }
93  else if (localKey == "blacklist") {
94  local.parseBlacklist(localPair.second);
95  }
96  else {
97  NDN_THROW(ConfigFile::Error("Unrecognized option face_system.tcp.local." + localKey));
98  }
99  }
100  }
101  else {
102  NDN_THROW(ConfigFile::Error("Unrecognized option face_system.tcp." + key));
103  }
104  }
105  if (!isLocalConfigured) {
106  local.assign({{"subnet", "127.0.0.0/8"}, {"subnet", "::1/128"}}, {});
107  }
108 
109  if (!enableV4 && !enableV6) {
110  NDN_THROW(ConfigFile::Error(
111  "IPv4 and IPv6 TCP channels have been disabled. Remove face_system.tcp section to disable "
112  "TCP channels or enable at least one channel type."));
113  }
114 
115  if (context.isDryRun) {
116  return;
117  }
118 
119  providedSchemes.insert("tcp");
120 
121  if (enableV4) {
122  tcp::Endpoint endpoint(ip::tcp::v4(), port);
123  auto v4Channel = this->createChannel(endpoint);
124  if (wantListen && !v4Channel->isListening()) {
125  v4Channel->listen(this->addFace, nullptr);
126  }
127  providedSchemes.insert("tcp4");
128  }
129  else if (providedSchemes.count("tcp4") > 0) {
130  NFD_LOG_WARN("Cannot close tcp4 channel after its creation");
131  }
132 
133  if (enableV6) {
134  tcp::Endpoint endpoint(ip::tcp::v6(), port);
135  auto v6Channel = this->createChannel(endpoint);
136  if (wantListen && !v6Channel->isListening()) {
137  v6Channel->listen(this->addFace, nullptr);
138  }
139  providedSchemes.insert("tcp6");
140  }
141  else if (providedSchemes.count("tcp6") > 0) {
142  NFD_LOG_WARN("Cannot close tcp6 channel after its creation");
143  }
144 
145  m_local = std::move(local);
146 }
147 
148 void
149 TcpFactory::doCreateFace(const CreateFaceRequest& req,
150  const FaceCreatedCallback& onCreated,
151  const FaceCreationFailedCallback& onFailure)
152 {
153  if (req.localUri) {
154  NFD_LOG_TRACE("Cannot create unicast TCP face with LocalUri");
155  onFailure(406, "Unicast TCP faces cannot be created with a LocalUri");
156  return;
157  }
158 
159  if (req.params.persistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
160  NFD_LOG_TRACE("createFace does not support FACE_PERSISTENCY_ON_DEMAND");
161  onFailure(406, "Outgoing TCP faces do not support on-demand persistency");
162  return;
163  }
164 
165  tcp::Endpoint endpoint(ip::address::from_string(req.remoteUri.getHost()),
166  boost::lexical_cast<uint16_t>(req.remoteUri.getPort()));
167 
168  // a canonical tcp4/tcp6 FaceUri cannot have a multicast address
169  BOOST_ASSERT(!endpoint.address().is_multicast());
170 
171  if (req.params.wantLocalFields && !endpoint.address().is_loopback()) {
172  NFD_LOG_TRACE("createFace cannot create non-local face with local fields enabled");
173  onFailure(406, "Local fields can only be enabled on faces with local scope");
174  return;
175  }
176 
177  if (req.params.mtu) {
178  NFD_LOG_TRACE("createFace cannot create a TCP face with an overridden MTU");
179  onFailure(406, "TCP faces do not support MTU overrides");
180  return;
181  }
182 
183  // very simple logic for now
184  for (const auto& i : m_channels) {
185  if ((i.first.address().is_v4() && endpoint.address().is_v4()) ||
186  (i.first.address().is_v6() && endpoint.address().is_v6())) {
187  i.second->connect(endpoint, req.params, onCreated, onFailure);
188  return;
189  }
190  }
191 
192  NFD_LOG_TRACE("No channels available to connect to " << endpoint);
193  onFailure(504, "No channels available to connect");
194 }
195 
196 shared_ptr<TcpChannel>
198 {
199  auto it = m_channels.find(endpoint);
200  if (it != m_channels.end())
201  return it->second;
202 
203  auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking,
204  bind(&TcpFactory::determineFaceScopeFromAddresses, this, _1, _2));
205  m_channels[endpoint] = channel;
206  return channel;
207 }
208 
209 std::vector<shared_ptr<const Channel>>
210 TcpFactory::doGetChannels() const
211 {
212  return getChannelsFromMap(m_channels);
213 }
214 
215 ndn::nfd::FaceScope
216 TcpFactory::determineFaceScopeFromAddresses(const boost::asio::ip::address& localAddress,
217  const boost::asio::ip::address& remoteAddress) const
218 {
219  if (m_local(localAddress) && m_local(remoteAddress)) {
220  return ndn::nfd::FACE_SCOPE_LOCAL;
221  }
222  return ndn::nfd::FACE_SCOPE_NON_LOCAL;
223 }
224 
225 } // namespace face
226 } // namespace nfd
FaceCreatedCallback addFace
callback when a new face is created
shared_ptr< TcpChannel > createChannel(const tcp::Endpoint &localEndpoint)
Create TCP-based channel using tcp::Endpoint.
void parseWhitelist(const boost::property_tree::ptree &list)
void parseBlacklist(const boost::property_tree::ptree &list)
Represents a predicate to accept or reject an IP address.
std::set< std::string > providedSchemes
FaceUri schemes provided by this protocol factory.
#define NFD_LOG_TRACE
Definition: logger.hpp:37
std::function< void(uint32_t status, const std::string &reason)> FaceCreationFailedCallback
Prototype for the callback that is invoked when a face fails to be created.
Definition: channel.hpp:78
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:60
boost::optional< const ConfigSection & > OptionalConfigSection
an optional config file section
Definition: config-file.hpp:41
#define NFD_REGISTER_PROTOCOL_FACTORY(PF)
Registers a protocol factory.
context for processing a config section in ProtocolFactory
Definition: face-system.hpp:96
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...
Definition: algorithm.hpp:32
boost::asio::ip::tcp::endpoint Endpoint
Definition: tcp-channel.hpp:34
#define NFD_LOG_WARN
Definition: logger.hpp:40
optional< ssize_t > mtu
Definition: face-common.hpp:83
static const std::string & getId() noexcept
Definition: tcp-factory.cpp:37
ndn::nfd::FacePersistency persistency
Definition: face-common.hpp:80
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31
void assign(std::initializer_list< std::pair< std::string, std::string >> whitelist, std::initializer_list< std::pair< std::string, std::string >> blacklist)
std::function< void(const shared_ptr< Face > &)> FaceCreatedCallback
Prototype for the callback that is invoked when a face is created (in response to an incoming connect...
Definition: channel.hpp:74
Encapsulates a face creation request and all its parameters.