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