ndn-fch-discovery.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 "ndn-fch-discovery.hpp"
27 
28 #include <boost/algorithm/string.hpp>
29 #include <boost/asio/ip/tcp.hpp>
30 
31 #include <regex>
32 #include <sstream>
33 
34 namespace ndn {
35 namespace tools {
36 namespace autoconfig {
37 
44 class Url
45 {
46 public:
47  Url(const std::string& url)
48  : m_isValid(false)
49  {
50  static const std::regex protocolExp("(\\w+\\d?(\\+\\w+)?)://([^/]*)(\\/[^?]*)?");
51  std::smatch protocolMatch;
52  if (!std::regex_match(url, protocolMatch, protocolExp)) {
53  return;
54  }
55  m_scheme = protocolMatch[1];
56  std::string authority = protocolMatch[3];
57  m_path = protocolMatch[4];
58 
59  // pattern for IPv6 address enclosed in [ ], with optional port number
60  static const std::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
61  // pattern for IPv4-mapped IPv6 address, with optional port number
62  static const std::regex v4MappedV6Exp("^\\[::ffff:(\\d+(?:\\.\\d+){3})\\](?:\\:(\\d+))?$");
63  // pattern for IPv4/hostname/fd/ifname, with optional port number
64  static const std::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$");
65 
66  if (authority.empty()) {
67  // UNIX, internal
68  }
69  else {
70  std::smatch match;
71  bool isV6 = std::regex_match(authority, match, v6Exp);
72  if (isV6 ||
73  std::regex_match(authority, match, v4MappedV6Exp) ||
74  std::regex_match(authority, match, v4HostExp)) {
75  m_host = match[1];
76  m_port = match[2];
77  }
78  else {
79  return;
80  }
81  }
82  if (m_port.empty()) {
83  m_port = "80";
84  }
85  if (m_path.empty()) {
86  m_path = "/";
87  }
88  m_isValid = true;
89  }
90 
91  bool
92  isValid() const
93  {
94  return m_isValid;
95  }
96 
97  const std::string&
98  getScheme() const
99  {
100  return m_scheme;
101  }
102 
103  const std::string&
104  getHost() const
105  {
106  return m_host;
107  }
108 
109  const std::string&
110  getPort() const
111  {
112  return m_port;
113  }
114 
115  const std::string&
116  getPath() const
117  {
118  return m_path;
119  }
120 
121 private:
122  bool m_isValid;
123  std::string m_scheme;
124  std::string m_host;
125  std::string m_port;
126  std::string m_path;
127 };
128 
129 class HttpException : public std::runtime_error
130 {
131 public:
132  explicit
133  HttpException(const std::string& what)
134  : std::runtime_error(what)
135  {
136  }
137 };
138 
139 NdnFchDiscovery::NdnFchDiscovery(const std::string& url)
140  : m_url(url)
141 {
142 }
143 
144 void
145 NdnFchDiscovery::doStart()
146 {
147  try {
148  boost::asio::ip::tcp::iostream requestStream;
149 #if BOOST_VERSION >= 106700
150  requestStream.expires_after(std::chrono::seconds(3));
151 #else
152  requestStream.expires_from_now(boost::posix_time::seconds(3));
153 #endif // BOOST_VERSION >= 106700
154 
155  Url url(m_url);
156  if (!url.isValid()) {
157  NDN_THROW(HttpException("Invalid NDN-FCH URL: " + m_url));
158  }
159  if (!boost::iequals(url.getScheme(), "http")) {
160  NDN_THROW(HttpException("Only http:// NDN-FCH URLs are supported"));
161  }
162 
163  requestStream.connect(url.getHost(), url.getPort());
164  if (!requestStream) {
165  NDN_THROW(HttpException("HTTP connection error to " + m_url));
166  }
167 
168  requestStream << "GET " << url.getPath() << " HTTP/1.0\r\n";
169  requestStream << "Host: " << url.getHost() << ":" << url.getPort() << "\r\n";
170  requestStream << "Accept: */*\r\n";
171  requestStream << "Cache-Control: no-cache\r\n";
172  requestStream << "Connection: close\r\n\r\n";
173  requestStream.flush();
174 
175  std::string statusLine;
176  std::getline(requestStream, statusLine);
177  if (!requestStream) {
178  NDN_THROW(HttpException("HTTP communication error"));
179  }
180 
181  std::stringstream responseStream(statusLine);
182  std::string httpVersion;
183  responseStream >> httpVersion;
184  unsigned int statusCode;
185  responseStream >> statusCode;
186  std::string statusMessage;
187 
188  std::getline(responseStream, statusMessage);
189  if (!static_cast<bool>(requestStream) || httpVersion.substr(0, 5) != "HTTP/") {
190  NDN_THROW(HttpException("HTTP communication error"));
191  }
192  if (statusCode != 200) {
193  boost::trim(statusMessage);
194  NDN_THROW(HttpException("HTTP request failed: " + to_string(statusCode) + " " + statusMessage));
195  }
196  std::string header;
197  while (std::getline(requestStream, header) && header != "\r")
198  ;
199 
200  std::string hubHost;
201  requestStream >> hubHost;
202  if (hubHost.empty()) {
203  NDN_THROW(HttpException("NDN-FCH did not return hub host"));
204  }
205 
206  this->provideHubFaceUri("udp://" + hubHost);
207  }
208  catch (const std::runtime_error& e) {
209  this->fail(e.what());
210  }
211 }
212 
213 } // namespace autoconfig
214 } // namespace tools
215 } // namespace ndn
Copyright (c) 2014-2017, Regents of the University of California, Arizona Board of Regents...
Definition: dns-srv.cpp:41
STL namespace.
NdnFchDiscovery(const std::string &url)
Create stage to discover NDN hub using NDN-FCH protocol.
void fail(const std::string &msg)
Definition: stage.cpp:65
void provideHubFaceUri(const std::string &s)
parse HUB FaceUri from string and declare success
Definition: stage.cpp:45