OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sandesh_server.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 //
6 // sandesh_server.cc
7 //
8 // Sandesh server implementation
9 //
10 
11 #include <boost/bind.hpp>
12 #include <boost/assign.hpp>
13 
14 #include <base/address_util.h>
15 #include <sandesh/protocol/TXMLProtocol.h>
16 #include <sandesh/sandesh_types.h>
17 #include <sandesh/sandesh.h>
18 #include <sandesh/sandesh_ctrl_types.h>
19 #include "sandesh_connection.h"
20 #include "sandesh_session.h"
21 #include "sandesh_server.h"
22 
23 using namespace std;
24 using namespace boost::asio;
25 
26 const std::string SandeshServer::kStateMachineTask = "sandesh::SandeshStateMachine";
27 const std::string SandeshServer::kLifetimeMgrTask = "sandesh::LifetimeMgr";
28 const std::string SandeshServer::kSessionReaderTask = "io::ReaderTask";
29 
31 public:
33  LifetimeActor(server->lifetime_manager()), server_(server) { }
34  virtual bool MayDelete() const {
35  return true;
36  }
37  virtual void Shutdown() {
38  server_->SessionShutdown();
39  }
40  virtual void Destroy() {
41  }
42 private:
44 };
45 
47 
49  : SslServer(evm, boost::asio::ssl::context::tlsv12_server,
50  config.sandesh_ssl_enable),
51  sm_task_id_(TaskScheduler::GetInstance()->GetTaskId(kStateMachineTask)),
52  session_reader_task_id_(TaskScheduler::GetInstance()->GetTaskId(kSessionReaderTask)),
53  lifetime_mgr_task_id_(TaskScheduler::GetInstance()->GetTaskId(kLifetimeMgrTask)),
54  lifetime_manager_(new LifetimeManager(lifetime_mgr_task_id_)),
55  deleter_(new DeleteActor(this)) {
56  // Set task policy for exclusion between :
57  // 1. State machine and lifetime mgr since state machine delete happens
58  // in lifetime mgr task
59  if (!task_policy_set_) {
60  TaskPolicy lm_task_policy = boost::assign::list_of
64  task_policy_set_ = true;
65  }
66  if (config.sandesh_ssl_enable) {
67  boost::asio::ssl::context *ctx = context();
68  boost::system::error_code ec;
69  ctx->set_options(boost::asio::ssl::context::default_workarounds |
70  boost::asio::ssl::context::no_tlsv1 |
71  boost::asio::ssl::context::no_sslv3 |
72  boost::asio::ssl::context::no_sslv2 |
73  boost::asio::ssl::context::no_tlsv1_1, ec);
74  if (ec.value() != 0) {
75  SANDESH_LOG(ERROR, "Error setting ssl options: " << ec.message());
76  exit(EINVAL);
77  }
78  // CA certificate
79  if (!config.ca_cert.empty()) {
80  // Verify that the peer certificate is signed by a trusted CA
81  ctx->set_verify_mode(boost::asio::ssl::verify_peer |
82  boost::asio::ssl::verify_fail_if_no_peer_cert,
83  ec);
84  if (ec.value() != 0) {
85  SANDESH_LOG(ERROR, "Error setting verification mode: " <<
86  ec.message());
87  exit(EINVAL);
88  }
89  ctx->load_verify_file(config.ca_cert, ec);
90  if (ec.value() != 0) {
91  SANDESH_LOG(ERROR, "Error loading CA certificate: " <<
92  ec.message());
93  exit(EINVAL);
94  }
95  }
96  // Server certificate
97  ctx->use_certificate_chain_file(config.server_certfile, ec);
98  if (ec.value() != 0) {
99  SANDESH_LOG(ERROR, "Error using server certificate: " <<
100  ec.message());
101  exit(EINVAL);
102  }
103  // Server private key
104  ctx->use_private_key_file(config.server_keyfile,
105  boost::asio::ssl::context::pem, ec);
106  if (ec.value() != 0) {
107  SANDESH_LOG(ERROR, "Error using server private key file: " <<
108  ec.message());
109  exit(EINVAL);
110  }
111  }
112 }
113 
116 }
117 
119  return lifetime_mgr_task_id_;
120 }
121 
124 }
125 
126 bool SandeshServer::Initialize(short port, const std::string &ip) {
127  int count = 0;
128 
129  boost::system::error_code ec;
130  boost::asio::ip::address ip_addr = AddressFromString(ip, &ec);
131  if (ec) {
132  SANDESH_LOG(ERROR, __func__ << ": Invalid server address: " <<
133  ip << " Error: " << ec);
134  return false;
135  }
136  while (count++ < kMaxInitRetries) {
137  if (TcpServer::Initialize(port, ip_addr))
138  break;
139  sleep(1);
140  }
141  if (!(count < kMaxInitRetries)) {
142  SANDESH_LOG(ERROR, "Process EXITING: TCP Server initialization failed for port " << port);
143  exit(1);
144  }
145  return true;
146 }
147 
149  tbb::mutex::scoped_lock lock(mutex_);
150  size_t bit = conn_bmap_.find_first();
151  if (bit == conn_bmap_.npos) {
152  bit = conn_bmap_.size();
153  conn_bmap_.resize(bit + 1, true);
154  }
155  conn_bmap_.reset(bit);
156  return bit;
157 }
158 
160  tbb::mutex::scoped_lock lock(mutex_);
161  conn_bmap_.set(id);
162 
163  for (size_t i = conn_bmap_.size(); i != 0; i--) {
164  if (conn_bmap_[i-1] != true) {
165  if (i != conn_bmap_.size()) {
166  conn_bmap_.resize(i);
167  }
168  return;
169  }
170  }
171  conn_bmap_.clear();
172 }
173 
176  SOL_SOCKET, SO_REUSEADDR> reuse_addr_t;
178  Socket *socket = session->socket();
179 
180  boost::system::error_code err;
181  socket->open(ip::tcp::v4(), err);
182  if (err) {
183  SANDESH_LOG(ERROR, __func__ << " Server Open Fail " << err.message());
184  }
185 
186  socket->set_option(reuse_addr_t(true), err);
187  if (err) {
188  SANDESH_LOG(ERROR, __func__ << " SetSockOpt Fail " << err.message());
189  return session;
190  }
191 
192  socket->bind(LocalEndpoint(), err);
193  if (err) {
194  SANDESH_LOG(ERROR, __func__ << " Server Bind Failure " << err.message());
195  }
196 
197  return session;
198 }
199 
201  assert(deleter_.get());
202  deleter_->Delete();
203 }
204 
205 bool SandeshServer::Compare(const Endpoint &peer_addr,
206  const SandeshConnectionPair &p) const {
207  return (peer_addr == p.second->endpoint() ? false : true);
208 }
209 
211  tbb::mutex::scoped_lock lock(mutex_);
212  SandeshConnectionMap::iterator loc = find_if(connection_.begin(),
213  connection_.end(), boost::bind(&SandeshServer::Compare, this,
214  boost::ref(peer_addr), _1));
215  if (loc != connection_.end()) {
216  return loc->second;
217  }
218  return NULL;
219 }
220 
222  // Use the state machine task to run the session send queue since
223  // they need to be exclusive as session delete happens from state
224  // machine
225  SslSession *session = new SandeshSession(this, socket,
228  return session;
229 }
230 
232  tbb::mutex::scoped_lock lock(mutex_);
233  boost::asio::ip::tcp::endpoint endpoint = connection->endpoint();
234  connection_.erase(endpoint);
235 }
236 
238  tbb::mutex::scoped_lock lock(mutex_);
239  SandeshConnection *connection;
240  SandeshSession *ssession = dynamic_cast<SandeshSession *>(session);
241  assert(ssession);
242  ip::tcp::endpoint remote = session->remote_endpoint();
243  SandeshConnectionMap::iterator loc = connection_.find(remote);
244 
245  if (loc == connection_.end()) {
246  SANDESH_LOG(INFO, "Server: " << __func__ << " " << "Create Connection");
247  //create a connection_
248  connection = new SandeshServerConnection(this, remote,
249  ssession->GetSessionInstance(),
250  sm_task_id_);
251  connection->Initialize();
252  connection_.insert(remote, connection);
253  } else {
254  connection = loc->second;
255  if (connection->session() != NULL) {
256  return false;
257  }
258  }
259  connection->AcceptSession(ssession);
260  return true;
261 }
262 
264  SandeshSession *session, const Sandesh *sandesh) {
265  const SandeshCtrlClientToServer *snh =
266  dynamic_cast<const SandeshCtrlClientToServer *>(sandesh);
267  if (!snh) {
268  SANDESH_LOG(DEBUG, "Received Ctrl Message with wrong type " << sandesh->Name());
269  return false;
270  }
271  SANDESH_LOG(DEBUG, "Received Ctrl Message from " << snh->get_module_name());
272  std::vector<UVETypeInfo> vu;
273  SandeshCtrlServerToClient::Request(vu, true, "ctrl", session->connection());
274  return true;
275 }
276 
278  return deleter_.get();
279 }
280 
282  return lifetime_manager_.get();
283 }
virtual ~SandeshServer()
virtual bool MayDelete() const
void RemoveConnection(SandeshConnection *connection)
static bool task_policy_set_
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
boost::asio::ip::tcp::socket Socket
Definition: tcp_server.h:31
boost::scoped_ptr< LifetimeManager > lifetime_manager_
virtual TcpSession * CreateSession()
void SetPolicy(int task_id, TaskPolicy &policy)
Sets the task exclusion policy. Adds policy entries for the task Examples:
Definition: task.cc:610
SandeshServer(EventManager *evm, const SandeshConfig &config)
SandeshSession * session() const
virtual TcpSession * CreateSession()
Definition: tcp_server.cc:188
SandeshConnectionMap connection_
std::string server_certfile
boost::asio::ssl::context * context()
Definition: ssl_server.cc:41
int session_reader_task_id_
void AcceptSession(SandeshSession *session)
tbb::mutex mutex_
virtual int GetSessionInstance() const
virtual const char * Name() const
Definition: p/sandesh.h:277
virtual bool ReceiveSandeshCtrlMsg(SandeshStateMachine *state_machine, SandeshSession *session, const Sandesh *sandesh)
int AllocConnectionIndex()
#define SANDESH_LOG(_Level, _Msg)
Definition: p/sandesh.h:474
static const std::string kSessionReaderTask
unsigned int boolean
Definition: mcast_common.h:11
Endpoint LocalEndpoint() const
Definition: tcp_server.cc:306
virtual SslSession * AllocSession(SslSocket *socket)
static const int kMaxInitRetries
void Shutdown()
Definition: tcp_server.cc:143
boost::dynamic_bitset conn_bmap_
virtual bool AcceptSession(TcpSession *session)
static TaskScheduler * GetInstance()
Definition: task.cc:547
boost::asio::ssl::stream< boost::asio::ip::tcp::socket > SslSocket
Definition: ssl_server.h:16
boost::scoped_ptr< DeleteActor > deleter_
SandeshConnection * FindConnection(const Endpoint &peer_addr)
boost::ptr_container_detail::ref_pair< boost::asio::ip::basic_endpoint< boost::asio::ip::tcp >, SandeshConnection *const > SandeshConnectionPair
int session_writer_task_id() const
LifetimeActor * deleter()
int lifetime_mgr_task_id()
static const std::string kLifetimeMgrTask
std::vector< TaskExclusion > TaskPolicy
Definition: task.h:59
std::string server_keyfile
IpAddress AddressFromString(const std::string &ip_address_str, boost::system::error_code *ec)
Endpoint remote_endpoint() const
Definition: tcp_session.h:135
virtual bool Initialize(unsigned short port)
Definition: tcp_server.cc:59
SandeshConnection * connection()
void ClearSessions()
Definition: tcp_server.cc:159
int lifetime_mgr_task_id_
virtual bool Initialize(short port, const std::string &ip="0.0.0.0")
bool Compare(const Endpoint &peer_addr, const SandeshConnectionPair &) const
LifetimeManager * lifetime_manager()
virtual void SessionShutdown()
std::string ca_cert
DeleteActor(SandeshServer *server)
virtual Socket * socket() const
Definition: tcp_session.h:86
boost::asio::ip::tcp::endpoint Endpoint
Definition: tcp_server.h:30
void FreeConnectionIndex(int)
static EventManager evm
int session_reader_task_id() const
static const std::string kStateMachineTask