OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ssl_session.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "io/ssl_session.h"
6 
7 #include <string>
8 
9 #include <boost/asio.hpp>
10 #include <boost/bind.hpp>
11 
12 #include "io/event_manager.h"
13 #include "io/io_log.h"
14 #include "io/io_utils.h"
15 
16 using boost::asio::async_write;
17 using boost::asio::buffer;
18 using boost::asio::buffer_cast;
19 using boost::asio::mutable_buffer;
20 using boost::asio::mutable_buffers_1;
21 using boost::asio::null_buffers;
22 using boost::asio::placeholders::error;
23 using boost::asio::placeholders::bytes_transferred;
24 using boost::asio::ssl::stream_base;
25 using boost::bind;
26 using boost::function;
27 using boost::system::error_code;
28 using std::size_t;
29 using std::srand;
30 using std::string;
31 using std::time;
32 
33 class SslSession::SslReader : public Task {
34 public:
35  typedef function<void(Buffer)> ReadHandler;
36 
37  SslReader(int task_id, SslSessionPtr session, ReadHandler read_fn,
38  Buffer buffer)
39  : Task(task_id, session->GetSessionInstance()),
40  session_(session), read_fn_(read_fn), buffer_(buffer) {
41  }
42  virtual bool Run() {
43  if (session_->IsEstablished()) {
44  session_->ssl_last_read_len_ = BufferSize(buffer_);
46  if (session_->IsReaderDeferred()) {
47  // Update socket read block count.
48  session_->stats_.read_block_start_time = UTCTimestampUsec();
49  session_->stats_.read_blocked++;
50  session_->server()->stats_.read_blocked++;
51  } else {
52  if (session_->IsSslDisabled()) {
53  session_->AsyncReadStart();
54  } else if (!session_->IsSslHandShakeInProgress()) {
55  session_->AsyncReadStart();
56  }
57  }
58  }
59  return true;
60  }
61  string Description() const { return "SslSession::SslReader"; }
62 
63 private:
67 };
68 
70  bool async_read_ready)
71  : TcpSession(server, NULL, async_read_ready),
72  ssl_socket_(ssl_socket),
73  ssl_handshake_in_progress_(false),
74  ssl_handshake_success_(false),
75  ssl_enabled_(true),
76  ssl_handshake_delayed_(false),
77  ssl_last_read_len_(0) {
78 
79  if (server) {
80  ssl_enabled_ = server->ssl_enabled_;
82  }
83 }
84 
86 }
87 
88 Task* SslSession::CreateReaderTask(mutable_buffer buffer,
89  size_t bytes_transferred) {
90  Buffer rdbuf(buffer_cast<const uint8_t *>(buffer), bytes_transferred);
91  SslReader *task = new SslReader(this->reader_task_id(),
92  SslSessionPtr(this), bind(&SslSession::OnRead, this, _1), rdbuf);
93  return (task);
94 }
95 
96 
98  if (ssl_socket_) {
99  // return tcp socket
100  return &ssl_socket_->next_layer();
101  }
102  return NULL;
103 }
104 
105 // Register for data read notification from the tcp socket or from the ssl
106 // socket, as appropriate.
108  if (established()) {
109  if (ssl_last_read_len_ == 0) {
110  // we have drained the read buffer of the socket
111  // register for a read notification from the tcp socket
113  } else {
114  // trigger Async Read Handler for immediate read
116  }
117  }
118 }
119 
120 // Tests with large data have consistently shown 16K as the maximum read data
121 // size even though when a lot more data was available in the underlying socket.
122 // Also, there is no available() api for the ssl socket.
124  return kDefaultBufferSize;
125 }
126 
127 //
128 // Check if a socker error is hard and fatal. Only then should we close the
129 // socket. Soft errors like EINTR and EAGAIN should be ignored or properly
130 // handled with retries
131 //
132 bool SslSession::IsSocketErrorHard(const error_code &ec) {
133 
134  bool error;
135  error = TcpSession::IsSocketErrorHard(ec);
136  if (ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)) {
137  error = false;
138  }
139 
140  return error;
141 }
142 
143 size_t SslSession::ReadSome(mutable_buffer buffer, error_code *error) {
144  // Read data from the tcp socket or from the ssl socket, as appropriate.
147  return TcpSession::ReadSome(buffer, error);
148 
149  return ssl_socket_->read_some(mutable_buffers_1(buffer), *error);
150 }
151 
152 void SslSession::AsyncWrite(const uint8_t *data, size_t size) {
154  async_write(*ssl_socket_.get(), buffer(data, size),
156  TcpSessionPtr(this), error, bytes_transferred));
157  } else {
158  return (TcpSession::AsyncWrite(data, size));
159  }
160 }
161 
163  SslSessionPtr session,
164  const error_code &error) {
165  session->ssl_handshake_in_progress_ = false;
166  if (!error) {
167  session->SetSslHandShakeSuccess();
168  } else {
169  session->SetSslHandShakeFailure();
170  }
171 
172  if (session->socket() != NULL && !(session->IsClosed())) {
173  cb(session, error);
174  }
175 }
176 
179  srand(static_cast<unsigned>(time(0)));
180  error_code ec;
181  session->ssl_handshake_in_progress_ = true;
182  if (session->IsServerSession()) {
183  session->ssl_socket_->async_handshake(stream_base::server,
184  bind(&SslSession::SslHandShakeCallback, cb, session,
185  error));
186  } else {
187  session->ssl_socket_->async_handshake(stream_base::client,
188  bind(&SslSession::SslHandShakeCallback, cb, session,
189  error));
190  }
191 }
192 
194  server()->event_manager()->io_service()->post(
195  bind(&TriggerSslHandShakeInternal, SslSessionPtr(this), cb));
196 }
boost::asio::const_buffer Buffer
Definition: tcp_session.h:64
SslSession(SslServer *server, SslSocket *socket, bool async_read_ready=true)
Definition: ssl_session.cc:69
boost::intrusive_ptr< TcpSession > TcpSessionPtr
Definition: tcp_session.h:184
static const int kDefaultBufferSize
Definition: tcp_session.h:44
static void AsyncWriteHandler(TcpSessionPtr session, const boost::system::error_code &error, std::size_t bytes_transferred)
Definition: tcp_session.cc:378
virtual size_t ReadSome(boost::asio::mutable_buffer buffer, boost::system::error_code *error)
Definition: tcp_session.cc:468
static size_t BufferSize(const Buffer &buffer)
Definition: tcp_session.h:116
virtual ~SslSession()
Definition: ssl_session.cc:85
boost::intrusive_ptr< SslSession > SslSessionPtr
Definition: ssl_session.h:11
virtual Task * CreateReaderTask(boost::asio::mutable_buffer, size_t)
Definition: ssl_session.cc:88
boost::asio::io_context * io_service()
Definition: event_manager.h:42
size_t ReadSome(boost::asio::mutable_buffer buffer, boost::system::error_code *error)
Definition: ssl_session.cc:143
bool IsSslHandShakeSuccessLocked()
Definition: ssl_session.h:43
Definition: task_int.h:10
EventManager * event_manager()
Definition: tcp_server.h:76
size_t ssl_last_read_len_
Definition: ssl_session.h:104
bool ssl_enabled_
Definition: ssl_session.h:100
void TriggerAsyncReadHandler()
Definition: tcp_session.cc:346
boost::asio::ssl::stream< boost::asio::ip::tcp::socket > SslSocket
Definition: ssl_session.h:18
boost::scoped_ptr< SslSocket > ssl_socket_
Definition: ssl_session.h:92
bool ssl_handshake_in_progress_
Definition: ssl_session.h:95
boost::asio::ip::tcp::socket Socket
Definition: tcp_session.h:60
string Description() const
Definition: ssl_session.cc:61
ReadHandler read_fn_
Definition: ssl_session.cc:65
bool ssl_enabled_
Definition: ssl_server.h:57
bool ssl_handshake_delayed_
Definition: ssl_session.h:101
virtual void OnRead(Buffer buffer)=0
static bool IsSocketErrorHard(const boost::system::error_code &ec)
Definition: tcp_session.cc:742
virtual void AsyncWrite(const uint8_t *data, std::size_t size)
Definition: tcp_session.cc:199
virtual int reader_task_id() const
Definition: tcp_session.h:208
virtual void AsyncReadSome()
Definition: tcp_session.cc:192
virtual size_t GetReadBufferSize() const
Definition: ssl_session.cc:123
static bool IsSocketErrorHard(const boost::system::error_code &ec)
Definition: ssl_session.cc:132
virtual bool Run()
Code to execute. Returns true if task is completed. Return false to reschedule the task...
Definition: ssl_session.cc:42
void TriggerSslHandShake(SslHandShakeCallbackHandler)
Definition: ssl_session.cc:193
bool ssl_handshake_delayed_
Definition: ssl_server.h:58
bool established() const
Definition: tcp_session.h:212
virtual void AsyncReadSome()
Definition: ssl_session.cc:107
static uint64_t UTCTimestampUsec()
Definition: time_util.h:13
static void TriggerSslHandShakeInternal(SslSessionPtr ptr, SslHandShakeCallbackHandler cb)
Definition: ssl_session.cc:177
TcpServer * server()
Definition: tcp_session.h:88
SslReader(int task_id, SslSessionPtr session, ReadHandler read_fn, Buffer buffer)
Definition: ssl_session.cc:37
virtual int GetSessionInstance() const
Definition: tcp_session.cc:530
void AsyncWrite(const uint8_t *data, std::size_t size)
Definition: ssl_session.cc:152
static void SslHandShakeCallback(SslHandShakeCallbackHandler cb, SslSessionPtr, const boost::system::error_code &error)
Definition: ssl_session.cc:162
Task is a wrapper over tbb::task to support policies.
Definition: task.h:86
SslSessionPtr session_
Definition: ssl_session.cc:64
boost::function< void(SslSessionPtr, const boost::system::error_code &error)> SslHandShakeCallbackHandler
Definition: ssl_session.h:14
virtual Socket * socket() const
Definition: ssl_session.cc:97
function< void(Buffer)> ReadHandler
Definition: ssl_session.cc:35