OpenSDN source code
bfd_rest_server.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 CodiLime, Inc. All rights reserved.
3  */
4 
6 
7 #include <vector>
8 #include <string>
9 
10 #include <boost/assign.hpp>
11 #include <boost/bind/bind.hpp>
12 #include <boost/foreach.hpp>
13 #include <boost/random.hpp>
14 
15 #include <rapidjson/document.h>
16 #include <rapidjson/writer.h>
17 #include <rapidjson/stringbuffer.h>
18 
19 #include "base/logging.h"
20 #include "base/regex.h"
21 #include "base/address_util.h"
22 #include "bfd/bfd_common.h"
23 #include "bfd/bfd_session.h"
26 
27 using namespace boost::placeholders;
28 
29 using contrail::regex;
32 
33 namespace BFD {
34 
35 void RESTServer::SessionHandler(const struct RESTData& data) {
36  CreateRESTClientSession(data.session, data.request);
37 }
38 
39 void RESTServer::ClientHandler(const struct RESTData& data) {
40  const std::string& client_id = (*data.match)[1];
41  DeleteRESTClientSession(atoi(client_id.c_str()), data.session,
42  data.request);
43 }
44 
45 void RESTServer::ClientIPConnectionHandler(const struct RESTData& data) {
46  const std::string& client_id = (*data.match)[1];
47  CreateBFDConnection(atoi(client_id.c_str()), data.session,
48  data.request);
49 }
50 
51 void RESTServer::ClientIPAddressHandlerGet(const struct RESTData& data) {
52  const std::string& client_id = (*data.match)[1];
53  boost::system::error_code ec;
54  boost::asio::ip::address ip =
55  AddressFromString((*data.match)[2], &ec);
56  GetBFDConnection(atoi(client_id.c_str()), ip, data.session, data.request);
57 }
58 
59 void RESTServer::ClientIPAddressHandlerDelete(const struct RESTData& data) {
60  const std::string& client_id = (*data.match)[1];
61  boost::system::error_code ec;
62  boost::asio::ip::address ip =
63  AddressFromString((*data.match)[2], &ec);
64  DeleteBFDConnection(atoi(client_id.c_str()), ip,
65  data.session, data.request);
66 }
67 
68 void RESTServer::ClientMonitorHandler(const struct RESTData& data) {
69  const std::string& client_id = (*data.match)[1];
70  MonitorRESTClientSession(atoi(client_id.c_str()), data.session,
71  data.request);
72 }
73 
74 const std::vector<RESTServer::HandlerSpecifier> RESTServer::RESTHandlers_ =
75  boost::assign::list_of
76  (HandlerSpecifier(
77  regex("/Session"),
78  HTTP_PUT,
79  &RESTServer::SessionHandler))
80  (HandlerSpecifier(
81  regex("/Session/([[:digit:]]{1,9})"),
82  HTTP_DELETE,
83  &RESTServer::ClientHandler))
84  (HandlerSpecifier(
85  regex("/Session/([[:digit:]]{1,9})/IpConnection"),
86  HTTP_PUT,
87  &RESTServer::ClientIPConnectionHandler))
88  (HandlerSpecifier(
89  regex("/Session/([[:digit:]]{1,9})/IpConnection/"
90  "([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\."
91  "[[:digit:]]{1,3}\\.[[:digit:]]{1,3})"),
92  HTTP_GET,
93  &RESTServer::ClientIPAddressHandlerGet))
94  (HandlerSpecifier(
95  regex("/Session/([[:digit:]]{1,9})/IpConnection/"
96  "([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\."
97  "[[:digit:]]{1,3}\\.[[:digit:]]{1,3})"),
98  HTTP_DELETE,
99  &RESTServer::ClientIPAddressHandlerDelete))
100  (HandlerSpecifier(
101  regex("/Session/([[:digit:]]{1,9})/Monitor"),
102  HTTP_GET,
103  &RESTServer::ClientMonitorHandler));
104 
105 RESTServer::RESTServer(Server* bfd_server) :
106  bfd_server_(bfd_server) {
107 }
108 
110  HttpSession* session) {
111  ClientMap::iterator it = client_sessions_.find(client_id);
112  if (it != client_sessions_.end())
113  return it->second;
114 
115  REST::SendErrorResponse(session, "Unknown client-id: " +
116  boost::lexical_cast<std::string>(client_id), 404);
117  return NULL;
118 }
119 
121  const HttpRequest* request) {
122  ClientId client_id = UniqClientId();
123  RESTClientSession* client_session =
124  new RESTClientSession(bfd_server_, client_id);
125  client_sessions_[client_id] = client_session;
126 
127  contrail_rapidjson::Document document;
128  document.SetObject();
129  document.AddMember("client-id", client_id, document.GetAllocator());
130  contrail_rapidjson::StringBuffer strbuf;
131  contrail_rapidjson::Writer<contrail_rapidjson::StringBuffer> writer(strbuf);
132  document.Accept(writer);
133  REST::SendResponse(session, strbuf.GetString());
134 }
135 
137  HttpSession* session,
138  const HttpRequest* request) {
139  RESTClientSession* client_session = GetClientSession(client_id, session);
140  if (client_session == NULL) {
141  LOG(DEBUG, __PRETTY_FUNCTION__ << ": Couldn't get session.");
142  return;
143  }
144 
145  delete client_session;
146  client_sessions_.erase(client_id);
147  REST::SendResponse(session, "{}");
148 }
149 
151  HttpSession* session, const HttpRequest* request) {
152  RESTClientSession* client_session = GetClientSession(client_id, session);
153  if (client_session == NULL) {
154  LOG(DEBUG, __PRETTY_FUNCTION__ << ": Couldn't get session.");
155  return;
156  }
157 
158  REST::JsonConfig bfd_session_data;
159  if (bfd_session_data.ParseFromJsonString(request->Body())) {
160  SessionConfig config;
161  config.desiredMinTxInterval =
162  bfd_session_data.desired_min_tx_interval;
163  config.requiredMinRxInterval =
164  bfd_session_data.required_min_rx_interval;
165  config.detectionTimeMultiplier =
166  bfd_session_data.detection_time_multiplier;
167  ResultCode result = client_session->AddBFDConnection(
168  SessionKey(bfd_session_data.address), config);
169  if (kResultCode_Ok != result) {
170  REST::SendErrorResponse(session, "Unable to create session", 500);
171  } else {
172  REST::SendResponse(session, "{}");
173  }
174  } else {
175  REST::SendErrorResponse(session, "Invalid arguments", 400);
176  }
177 }
178 
180  const boost::asio::ip::address& ip, HttpSession* session,
181  const HttpRequest* request) {
182  RESTClientSession* client_session = GetClientSession(client_id, session);
183  if (client_session == NULL) {
184  LOG(DEBUG, __PRETTY_FUNCTION__ << ": Couldn't get session.");
185  REST::SendErrorResponse(session, "Unknown client session", 404);
186  return;
187  }
188  Session* bfd_session = client_session->GetSession(ip);
189  if (bfd_session == NULL) {
190  LOG(DEBUG, __PRETTY_FUNCTION__ << ": Couldn't get session.");
191  REST::SendErrorResponse(session, "Unknown bfd session", 404);
192  return;
193  }
194 
195  BFDRemoteSessionState remote_state = bfd_session->remote_state();
196  SessionConfig config = bfd_session->config();
197  REST::JsonState session_state;
198  session_state.local_discriminator = bfd_session->local_discriminator();
199  session_state.remote_discriminator = remote_state.discriminator;
200  session_state.bfd_local_state = bfd_session->local_state();
201  session_state.bfd_remote_state = remote_state.state;
202  session_state.remote_min_rx_interval = remote_state.minRxInterval;
203  REST::JsonConfig& session_data = session_state.session_config;
204  session_data.address = bfd_session->key().remote_address;
205  session_data.desired_min_tx_interval = config.desiredMinTxInterval;
206  session_data.required_min_rx_interval = config.requiredMinRxInterval;
208  std::string json;
209  session_state.EncodeJsonString(&json);
210  REST::SendResponse(session, json);
211 }
212 
214  const boost::asio::ip::address& ip, HttpSession* session,
215  const HttpRequest* request) {
216  RESTClientSession* client_session = GetClientSession(client_id, session);
217  if (client_session == NULL) {
218  LOG(DEBUG, __PRETTY_FUNCTION__ << ": Couldn't get session.");
219  REST::SendErrorResponse(session, "Unknown client session", 404);
220  return;
221  }
222  ResultCode result = client_session->DeleteBFDConnection(SessionKey(ip));
223  if (result != kResultCode_Ok) {
224  REST::SendErrorResponse(session, "Unable to delete session");
225  } else {
226  REST::SendResponse(session, "{}");
227  }
228 }
229 
231  HttpSession* session, const HttpRequest* request) {
232  RESTClientSession* client_session = GetClientSession(client_id, session);
233  if (client_session == NULL) {
234  LOG(DEBUG, __PRETTY_FUNCTION__ << ": Couldn't get session.");
235  REST::SendErrorResponse(session, "Unknown client session", 404);
236  return;
237  }
238  client_session->AddMonitoringHttpSession(session);
239 }
240 
242  const HttpRequest* request) {
243  std::scoped_lock lock(mutex_);
244 
245  std::string path = request->UrlPath();
246  BOOST_FOREACH(const RESTServer::HandlerSpecifier& hs, RESTHandlers_) {
247  boost::smatch match;
248  if (regex_match(path, match, hs.request_regex) &&
249  request->GetMethod() == hs.method) {
250  struct RESTData data = {
251  &match,
252  request->GetMethod(),
253  session,
254  request
255  };
256  LOG(INFO, "Handling request: " << path);
257  (this->*hs.handler_func)(data);
258  // Though IMHO it contradicts most programmers' intuition,
259  // currently handlers are responsible for freeing handled
260  // requests.
261  delete request;
262  return;
263  }
264  }
265  LOG(ERROR, "Couldn't handle request: " << path);
266  REST::SendErrorResponse(session, "Unknown Request", 404);
267 }
268 
270  ClientId client_id;
271  boost::random::uniform_int_distribution<> dist(0, 1e9);
272  do {
273  client_id = dist(randomGen);
274  } while (client_sessions_.find(client_id) != client_sessions_.end());
275  return client_id;
276 }
277 
279  for (ClientMap::iterator it = client_sessions_.begin();
280  it != client_sessions_.end(); ++it) {
281  delete it->second;
282  }
283 }
284 
285 } // namespace BFD
IpAddress AddressFromString(const std::string &ip_address_str, boost::system::error_code *ec)
ResultCode AddBFDConnection(const SessionKey &key, const SessionConfig &config)
ResultCode DeleteBFDConnection(const SessionKey &key)
void AddMonitoringHttpSession(HttpSession *session)
Session * GetSession(const boost::asio::ip::address &ip, const SessionIndex &index=SessionIndex()) const
void DeleteRESTClientSession(ClientId client_id, HttpSession *session, const HttpRequest *request)
void HandleRequest(HttpSession *session, const HttpRequest *request)
static const std::vector< HandlerSpecifier > RESTHandlers_
void DeleteBFDConnection(ClientId client_id, const boost::asio::ip::address &ip, HttpSession *session, const HttpRequest *request)
void MonitorRESTClientSession(ClientId client_id, HttpSession *session, const HttpRequest *request)
RESTClientSession * GetClientSession(ClientId client_id, HttpSession *session)
void CreateBFDConnection(ClientId client_id, HttpSession *session, const HttpRequest *request)
ClientId UniqClientId()
std::mutex mutex_
void CreateRESTClientSession(HttpSession *session, const HttpRequest *request)
ClientMap client_sessions_
void GetBFDConnection(ClientId client_id, const boost::asio::ip::address &ip, HttpSession *session, const HttpRequest *request)
Server * bfd_server_
BFDState local_state() const
Definition: bfd_session.cc:143
SessionConfig config() const
Definition: bfd_session.cc:285
Discriminator local_discriminator() const
Definition: bfd_session.cc:293
const SessionKey & key() const
Definition: bfd_session.cc:271
BFDRemoteSessionState remote_state() const
Definition: bfd_session.cc:289
const std::string & Body() const
Definition: http_request.h:39
http_method GetMethod() const
Definition: http_request.h:21
std::string UrlPath() const
Definition: http_request.cc:25
#define LOG(_Level, _Msg)
Definition: logging.h:34
void SendErrorResponse(HttpSession *session, const std::string &error_msg, int status_code)
void SendResponse(HttpSession *session, const std::string &msg, int status_code)
Definition: bfd_client.h:9
uint32_t ClientId
Definition: bfd_common.h:19
ResultCode
Definition: bfd_common.h:41
@ kResultCode_Ok
Definition: bfd_common.h:42
boost::random::taus88 randomGen
Definition: bfd_common.cc:43
static bool regex_search(const std::string &input, const regex &regex)
Definition: regex.h:25
static bool regex_match(const std::string &input, const regex &regex)
Definition: regex.h:34
Discriminator discriminator
Definition: bfd_session.h:31
TimeInterval minRxInterval
Definition: bfd_session.h:32
const HttpRequest * request
const boost::smatch * match
TimeInterval desired_min_tx_interval
TimeInterval required_min_rx_interval
boost::asio::ip::address address
bool ParseFromJsonString(const std::string &json)
void EncodeJsonString(std::string *json)
Discriminator remote_discriminator
Discriminator local_discriminator
TimeInterval remote_min_rx_interval
TimeInterval desiredMinTxInterval
Definition: bfd_common.h:125
TimeInterval requiredMinRxInterval
Definition: bfd_common.h:126
boost::asio::ip::address remote_address
Definition: bfd_common.h:115