LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/io - tcp_session.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 467 529 88.3 %
Date: 2026-11-09 02:10:49 Functions: 50 57 87.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "io/tcp_session.h"
       7             : 
       8             : #include <algorithm>
       9             : #include <string>
      10             : 
      11             : #include <boost/asio.hpp>
      12             : #include <boost/asio/detail/socket_option.hpp>
      13             : #include <boost/bind/bind.hpp>
      14             : #include <boost/scoped_array.hpp>
      15             : #include <boost/asio/detail/recycling_allocator.hpp>
      16             : 
      17             : #include "base/logging.h"
      18             : #include "base/address_util.h"
      19             : #include "io/event_manager.h"
      20             : #include "io/io_log.h"
      21             : #include "io/io_utils.h"
      22             : #include "io/tcp_message_write.h"
      23             : #include "io/tcp_server.h"
      24             : #include "base/address_util.h"
      25             : 
      26             : using boost::asio::async_write;
      27             : using boost::asio::buffer;
      28             : using boost::asio::buffer_cast;
      29             : using boost::asio::detail::socket_option::integer;
      30             : using boost::asio::const_buffer;
      31             : using boost::asio::mutable_buffer;
      32             : using boost::asio::mutable_buffers_1;
      33             : using boost::asio::null_buffers;
      34             : using boost::asio::socket_base;
      35             : using boost::bind;
      36             : using boost::function;
      37             : using boost::scoped_array;
      38             : using boost::system::error_code;
      39             : using std::min;
      40             : using std::ostringstream;
      41             : using std::string;
      42             : using namespace boost::placeholders;
      43             : 
      44             : using boost::asio::error::try_again;
      45             : using boost::asio::error::would_block;
      46             : using boost::asio::error::in_progress;
      47             : using boost::asio::error::interrupted;
      48             : using boost::asio::error::network_down;
      49             : using boost::asio::error::network_reset;
      50             : using boost::asio::error::network_unreachable;
      51             : using boost::asio::error::no_buffer_space;
      52             : using boost::asio::placeholders::error;
      53             : using boost::asio::placeholders::bytes_transferred;
      54             : using boost::asio::ip::tcp;
      55             : 
      56             : int TcpSession::reader_task_id_ = -1;
      57             : 
      58             : class TcpSession::Reader : public Task {
      59             : public:
      60             :     typedef function<void(Buffer)> ReadHandler;
      61             : 
      62      102428 :     Reader(TcpSessionPtr session, ReadHandler read_fn, Buffer buffer)
      63      409712 :         : Task(session->reader_task_id(), session->GetSessionInstance()),
      64      102428 :           session_(session), read_fn_(read_fn), buffer_(buffer) {
      65      102428 :     }
      66      102426 :     virtual bool Run() {
      67      102426 :         if (session_->IsEstablished()) {
      68      101189 :             read_fn_(buffer_);
      69      101188 :             if (session_->IsReaderDeferred()) {
      70             :                 // Update socket read block count.
      71           1 :                 session_->stats_.read_block_start_time = UTCTimestampUsec();
      72           1 :                 session_->stats_.read_blocked++;
      73           1 :                 session_->server_->stats_.read_blocked++;
      74             :             } else {
      75      101187 :                 session_->AsyncReadStart();
      76             :             }
      77             :         }
      78      102428 :         return true;
      79             :     }
      80           0 :     string Description() const { return "TcpSession::Reader"; }
      81             : 
      82             : private:
      83             :     TcpSessionPtr session_;
      84             :     ReadHandler read_fn_;
      85             :     Buffer buffer_;
      86             : };
      87             : 
      88       29598 : TcpSession::TcpSession(
      89             :     TcpServer *server, Socket *socket, bool async_read_ready,
      90       29598 :     size_t buffer_send_size)
      91       29599 :     : server_(server),
      92       29606 :       socket_(socket),
      93       29603 :       read_on_connect_(async_read_ready),
      94       29603 :       established_(false),
      95       29603 :       closed_(false),
      96       29600 :       direction_(ACTIVE),
      97       29590 :       writer_(new TcpMessageWriter(this, buffer_send_size)),
      98       88786 :       name_("-") {
      99       29578 :     refcount_ = 0;
     100       29607 :     if (reader_task_id_ == -1) {
     101         140 :         TaskScheduler *scheduler = TaskScheduler::GetInstance();
     102         140 :         reader_task_id_ = scheduler->GetTaskId("io::ReaderTask");
     103             :     }
     104       29607 :     if (server_) {
     105       29591 :         io_strand_.reset(new Strand(server->event_manager()->io_service()->get_executor()));
     106             :     }
     107       29608 :     defer_reader_ = false;
     108       29609 :     write_blocked_ = false;
     109       29609 :     tcp_close_in_progress_ = false;
     110       29609 : }
     111             : 
     112       29603 : TcpSession::~TcpSession() {
     113       29603 :     assert(!established_);
     114       29603 :     for (BufferQueue::iterator iter = buffer_queue_.begin();
     115       36174 :          iter != buffer_queue_.end(); ++iter) {
     116        6573 :         DeleteBuffer(*iter);
     117             :     }
     118       29598 :     buffer_queue_.clear();
     119       29595 : }
     120             : 
     121     1288920 : mutable_buffer TcpSession::AllocateBuffer(size_t buffer_size) {
     122     1288920 :     uint8_t *data = new uint8_t[buffer_size];
     123     1288920 :     mutable_buffer buffer = mutable_buffer(data, buffer_size);
     124     1288920 :     buffer_queue_.push_back(buffer);
     125     1288920 :     return buffer;
     126             : }
     127             : 
     128     1288881 : void TcpSession::DeleteBuffer(mutable_buffer buffer) {
     129     1288881 :     uint8_t *data = buffer_cast<uint8_t *>(buffer);
     130     1288877 :     delete[] data;
     131     1288919 : }
     132             : 
     133     1284619 : static int BufferCmp(const mutable_buffer &lhs, const const_buffer &rhs) {
     134     1284619 :     const uint8_t *lp = buffer_cast<uint8_t *>(lhs);
     135     1284615 :     const uint8_t *rp = buffer_cast<const uint8_t *>(rhs);
     136     1284612 :     if (lp < rp) {
     137        2249 :         return -1;
     138             :     }
     139     1282363 :     if (lp > rp) {
     140          39 :         return 1;
     141             :     }
     142     1282324 :     return 0;
     143             : }
     144             : 
     145     1270821 : void TcpSession::ReleaseBuffer(Buffer buffer) {
     146     1270821 :     std::scoped_lock lock(mutex_);
     147     1270826 :     ReleaseBufferLocked(buffer);
     148     1270822 : }
     149             : 
     150     1282339 : void TcpSession::ReleaseBufferLocked(Buffer buffer) {
     151     1282339 :     for (BufferQueue::iterator iter = buffer_queue_.begin();
     152     1284627 :          iter != buffer_queue_.end(); ++iter) {
     153     1284623 :         if (BufferCmp(*iter, buffer) == 0) {
     154     1282324 :             DeleteBuffer(*iter);
     155     1282347 :             buffer_queue_.erase(iter);
     156     1282339 :             return;
     157             :         }
     158             :     }
     159           0 :     assert(false);
     160             : }
     161             : 
     162     1300019 : void TcpSession::AsyncReadStartInternal(TcpSessionPtr session) {
     163             :     // Update socket read block time.
     164     1300019 :     if (stats_.read_block_start_time) {
     165           1 :         uint64_t blocked_usecs = UTCTimestampUsec() -
     166           1 :             stats_.read_block_start_time;
     167           1 :         stats_.read_block_start_time = 0;
     168           1 :         stats_.read_blocked_duration_usecs += blocked_usecs;
     169           1 :         server_->stats_.read_blocked_duration_usecs += blocked_usecs;
     170             :     }
     171             : 
     172     1300019 :     std::scoped_lock lock(mutex_);
     173     1300019 :     AsyncReadSome();
     174     1300019 : }
     175             : 
     176     1300010 : void TcpSession::AsyncReadStart() {
     177     1300010 :     if (io_strand_) {
     178     1300008 :         boost::asio::detail::recycling_allocator<void> allocator;
     179     2600027 :         io_strand_->post(bind(&TcpSession::AsyncReadStartInternal, this,
     180     2600001 :                          TcpSessionPtr(this)), allocator);
     181             :     }
     182     1300019 : }
     183             : 
     184           2 : void TcpSession::SetDeferReader(bool defer_reader) {
     185           2 :     if (defer_reader_ != defer_reader) {
     186           2 :         defer_reader_ = defer_reader;
     187             :         // Call AsyncReadStart if reader was previously deferred
     188           2 :         if (!defer_reader_) {
     189           1 :             AsyncReadStart();
     190             :         }
     191             :     }
     192           2 : }
     193             : 
     194      269925 : void TcpSession::AsyncReadSome() {
     195      269925 :     if (IsEstablishedLocked()) {
     196      537214 :         socket()->async_read_some(null_buffers(),
     197      537214 :             bind(&TcpSession::AsyncReadHandler, TcpSessionPtr(this)));
     198             :     }
     199      269925 : }
     200             : 
     201     1021038 : void TcpSession::AsyncWrite(const uint8_t *data, std::size_t size) {
     202     1021038 :     async_write(*socket(), buffer(data, size),
     203     2042076 :         bind(&TcpSession::AsyncWriteHandler, TcpSessionPtr(this),
     204             :              error, bytes_transferred));
     205     1021038 : }
     206             : 
     207      123707 : TcpSession::Endpoint TcpSession::local_endpoint() const {
     208      123707 :     std::scoped_lock lock(mutex_);
     209      123707 :     if (!established_)
     210           0 :         return Endpoint();
     211             : 
     212      123707 :     error_code error;
     213      123707 :     Endpoint local = socket()->local_endpoint(error);
     214      123707 :     if (error) {
     215           0 :         return Endpoint();
     216             :     }
     217      123707 :     return local;
     218      123707 : }
     219             : 
     220       79339 : void TcpSession::set_observer(EventObserver observer) {
     221       79339 :     std::scoped_lock lock(obs_mutex_);
     222       79342 :     observer_ = observer;
     223       79290 : }
     224             : 
     225       27028 : void TcpSession::SetName() {
     226       27028 :     ostringstream out;
     227       27028 :     error_code error;
     228       27028 :     Endpoint local;
     229             : 
     230       27028 :     local = socket()->local_endpoint(error);
     231       27028 :     out << local.address().to_string() << ":" << local.port() << "::";
     232       27028 :     out << remote_.address().to_string() << ":" << remote_.port();
     233             : 
     234       27028 :     name_ = out.str();
     235             : 
     236       27028 :     out.str("");
     237       27028 :     std::string hostname = "";
     238       27028 :     if (local.address().is_v4()) {
     239       27025 :         hostname = ResolveCanonicalName(local.address().to_string());
     240             :     } else {
     241           3 :         hostname = ResolveCanonicalNameIPv6(local.address().to_string());
     242             :     }
     243       27028 :     out << hostname << ":" << remote_.address().to_string();
     244       27028 :     uve_key_str_ = out.str();
     245       27028 : }
     246             : 
     247       27028 : void TcpSession::SessionEstablished(Endpoint remote,
     248             :                                     Direction direction) {
     249       27028 :     established_ = true;
     250       27028 :     remote_ = remote;
     251       27028 :     remote_addr_str_ = remote.address().to_string();
     252       27028 :     direction_ = direction;
     253       27028 :     SetName();
     254       27028 : }
     255             : 
     256       13460 : void TcpSession::Accepted() {
     257       13496 :     TCP_SESSION_LOG_DEBUG(this, TCP_DIR_OUT,
     258             :                           "Passive session Accept complete");
     259             :     {
     260       13460 :         std::scoped_lock obs_lock(obs_mutex_);
     261       13460 :         if (observer_) {
     262        6622 :             observer_(this, ACCEPT);
     263             :         }
     264       13460 :     }
     265             : 
     266       13460 :     if (read_on_connect_) {
     267         251 :         AsyncReadStart();
     268             :     }
     269       13460 : }
     270             : 
     271       13535 : bool TcpSession::Connected(Endpoint remote) {
     272       13535 :     assert(refcount_);
     273             : 
     274             :     {
     275       13535 :         std::scoped_lock lock(mutex_);
     276       13535 :         if (closed_) {
     277           0 :             return false;
     278             :         }
     279       13535 :         SessionEstablished(remote, TcpSession::ACTIVE);
     280       13535 :     }
     281       13535 :     SetSocketOptions();
     282             : 
     283       13535 :     TCP_SESSION_LOG_DEBUG(this, TCP_DIR_IN,
     284             :                           "Active session connection complete");
     285             : 
     286             :     {
     287       13535 :         std::scoped_lock obs_lock(obs_mutex_);
     288       13535 :         if (observer_) {
     289       13535 :             observer_(this, CONNECT_COMPLETE);
     290             :         }
     291       13535 :     }
     292             : 
     293       13535 :     if (read_on_connect_) {
     294       13535 :         AsyncReadStart();
     295             :     }
     296       13535 :     return true;
     297             : }
     298             : 
     299        1372 : void TcpSession::ConnectFailed() {
     300        1372 :     std::scoped_lock obs_lock(obs_mutex_);
     301        1372 :     if (observer_) {
     302        1274 :         observer_(this, CONNECT_FAILED);
     303             :     }
     304        1372 : }
     305             : 
     306             : // Requires: lock must not be held
     307       29624 : void TcpSession::CloseInternal(const error_code &ec,
     308             :                                bool call_observer, bool notify_server) {
     309       29624 :     std::unique_lock<std::mutex> lock(mutex_);
     310             : 
     311       29626 :     if (socket() != NULL && !closed_) {
     312       28501 :         error_code error;
     313       28501 :         socket()->shutdown(tcp::socket::shutdown_both, error);
     314       28509 :         if (error) {
     315        6021 :             TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     316             :                 "Shutdown failed due to error: " << error.message());
     317             :         }
     318       28509 :         socket()->close(error);
     319             :     }
     320       29629 :     closed_ = true;
     321       29629 :     tcp_close_in_progress_ = false;
     322             : 
     323       29628 :     if (!established_) {
     324        2601 :         return;
     325             :     }
     326       27027 :     established_ = false;
     327             : 
     328             :     // copy the ec to close reason
     329       27027 :     close_reason_ = ec;
     330             : 
     331             :     // Take a reference through intrusive pointer to protect session from
     332             :     // possibly getting deleted from another thread.
     333       27027 :     TcpSessionPtr session = TcpSessionPtr(this);
     334       27028 :     lock.unlock();
     335             : 
     336       27028 :     if (call_observer) {
     337       16373 :         std::scoped_lock obs_lock(obs_mutex_);
     338       16373 :         if (observer_) {
     339       11044 :             observer_(this, CLOSE);
     340             :         }
     341       16373 :     }
     342             : 
     343       27028 :     if (notify_server) {
     344       26995 :         server_->OnSessionClose(this);
     345             :     }
     346       29627 : }
     347             : 
     348     1029876 : void TcpSession::TriggerAsyncReadHandler() {
     349     1029876 :     if (io_strand_) {
     350     1029876 :         boost::asio::detail::recycling_allocator<void> allocator;
     351     2059752 :         io_strand_->post(bind(&TcpSession::AsyncReadHandler,
     352     2059752 :                               TcpSessionPtr(this)), allocator);
     353             :     }
     354     1029876 : }
     355             : 
     356       60808 : void TcpSession::Close() {
     357       60808 :     std::unique_lock<std::mutex> lock(mutex_);
     358             : 
     359             :     // Close can be called by application during cleanup. At this time
     360             :     // session may be already closed due to error and there may be write
     361             :     // data in the buffer, ignore if socket is closed.
     362       60814 :     if (closed_) {
     363       39007 :         return;
     364             :     }
     365             : 
     366       21807 :     if (server_ && writer_->IsWritePending()) {
     367        8594 :         tcp_close_in_progress_ = true;
     368        8599 :         return;
     369             :     }
     370       13210 :     lock.unlock();
     371             : 
     372       13211 :     error_code ec;
     373       13211 :     CloseInternal(ec, false);
     374       60820 : }
     375             : 
     376             : // virtual method overriden in derrived classes.
     377           2 : void TcpSession::WriteReady(const error_code &error) {
     378           2 : }
     379             : 
     380     1828375 : void TcpSession::AsyncWriteHandler(TcpSessionPtr session,
     381             :                                    const error_code &error,
     382             :                                    std::size_t wrote) {
     383     1828375 :     std::unique_lock<std::mutex> lock(session->mutex_);
     384     1828375 :     if (session->IsSocketErrorHard(error)) {
     385          54 :         lock.unlock();
     386          54 :         TCP_SESSION_LOG_ERROR(session, TCP_DIR_OUT,
     387             :                               "Write failed due to error: " << error.message());
     388          54 :         session->CloseInternal(error, true);
     389          54 :         return;
     390             :     }
     391             : 
     392             :     //
     393             :     // Ignore if connection is already closed.
     394             :     //
     395     1828321 :     if (session->IsClosedLocked()) return;
     396             : 
     397             :     // Update socket write bytes statistics.
     398     1827675 :     session->stats_.write_bytes += wrote;
     399     1827675 :     session->server_->stats_.write_bytes += wrote;
     400             : 
     401     1827675 :     bool send_ready = false;
     402     1827675 :     bool more_write = session->writer_->UpdateBufferQueue(wrote, &send_ready);
     403             : 
     404             :     // Subsequent write
     405     1827675 :     if (more_write) {
     406      287397 :         session->writer_->TriggerAsyncWrite();
     407     1540278 :     } else if (session->tcp_close_in_progress_) {
     408        4809 :         lock.unlock();
     409        4809 :         session->CloseInternal(error, true);
     410        4809 :         return;
     411             :     }
     412             : 
     413     1822866 :     lock.unlock();
     414     1822866 :     if (send_ready)
     415           5 :         session->WriteReady(error);
     416     1822866 :     return;
     417     1828375 : }
     418             : 
     419     1540995 : void TcpSession::AsyncWriteInternal(TcpSessionPtr session) {
     420             : 
     421     1540995 :     std::scoped_lock lock(session->mutex_);
     422             : 
     423             :     //
     424             :     // Ignore if connection is already closed.
     425             :     //
     426     1540995 :     if (session->IsClosedLocked()) return;
     427     1540978 :     session->writer_->TriggerAsyncWrite();
     428     1540995 : }
     429             : 
     430     1826236 : bool TcpSession::Send(const uint8_t *data, size_t size, size_t *sent) {
     431     1826236 :     bool ret = true;
     432     1826236 :     std::unique_lock<std::mutex> lock(mutex_);
     433             : 
     434             :     // Reset sent, if provided.
     435     1826263 :     if (sent) *sent = 0;
     436             : 
     437             :     //
     438             :     // If the session closed in the mean while, bail out
     439             :     // If session close is triggered, but close in progress, bail out
     440             :     //
     441     1826263 :     if (!IsEstablishedLocked()) return false;
     442             : 
     443     1825619 :     if (socket()->non_blocking()) {
     444     1825544 :         error_code error;
     445     1825544 :         int len = writer_->AsyncSend(data, size, &error);
     446     1824975 :         lock.unlock();
     447     1825638 :         if (len < 0) {
     448           0 :             TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     449             :                                   "Write failed due to error: "
     450             :                                   << error.category().name() << " "
     451             :                                   << error.message());
     452           0 :             CloseInternal(error, true);
     453           0 :             return false;
     454             :         }
     455     1825638 :         if ((size_t) len != size)
     456          15 :             ret = false;
     457     1825638 :         if (sent) *sent = (len > 0) ? len : 0;
     458             :     }
     459     1825638 :     return ret;
     460     1826234 : }
     461             : 
     462      102428 : Task* TcpSession::CreateReaderTask(mutable_buffer buffer,
     463             :                                   size_t bytes_transferred) {
     464      102428 :     Buffer rdbuf(buffer_cast<const uint8_t *>(buffer), bytes_transferred);
     465      102428 :     Reader *task = new Reader(TcpSessionPtr(this),
     466      102428 :                               bind(&TcpSession::OnRead, this, _1), rdbuf);
     467      102428 :     return (task);
     468             : }
     469             : 
     470      437702 : size_t TcpSession::ReadSome(mutable_buffer buffer, error_code *error) {
     471      437702 :     return socket()->read_some(mutable_buffers_1(buffer), *error);
     472             : }
     473             : 
     474             : // Tests with large data have shown large amounts of data being read in one
     475             : // read_some() call, if available. Hence, allocate memory for all the bytes
     476             : // available in the socket, but no less t han kDefaultBufferSize.
     477      107397 : size_t TcpSession::GetReadBufferSize() const {
     478      107397 :     error_code error;
     479      107397 :     size_t size = socket_->available(error);
     480      107397 :     if (size < kDefaultBufferSize)
     481      107042 :         size = kDefaultBufferSize;
     482      107397 :     return size;
     483             : }
     484             : 
     485     1298434 : void TcpSession::AsyncReadHandler(TcpSessionPtr session) {
     486     1298434 :     std::unique_lock<std::mutex> lock(session->mutex_);
     487     1298434 :     if (session->closed_) {
     488        9514 :         return;
     489             :     }
     490             : 
     491             :     mutable_buffer buffer =
     492     1288920 :         session->AllocateBuffer(session->GetReadBufferSize());
     493             : 
     494     1288920 :     error_code error;
     495     1288920 :     size_t bytes_transferred = session->ReadSome(buffer, &error);
     496     1288920 :     if (session->IsSocketErrorHard(error)) {
     497       11517 :         session->ReleaseBufferLocked(buffer);
     498             :         // eof is returned when the peer closed the socket, no need to log error
     499       11517 :         if (error != boost::asio::error::eof) {
     500        1451 :             if (strcmp(error.category().name(), "asio.ssl") == 0  &&
     501           0 :                 error.value() == SSL_SHORT_READ_ERROR) {
     502           0 :             TCP_SESSION_LOG_DEBUG(session, TCP_DIR_IN,
     503             :                     "Read failed due to error "
     504             :                     << error.category().name() << " "
     505             :                     << error.value()
     506             :                     << " : " << error.message());
     507             :             } else {
     508        1451 :             TCP_SESSION_LOG_ERROR(session, TCP_DIR_IN,
     509             :                     "Read failed due to error "
     510             :                     << error.category().name() << " "
     511             :                     << error.value()
     512             :                     << " : " << error.message());
     513             :             }
     514             :         }
     515       11517 :         lock.unlock();
     516       11517 :         session->CloseInternal(error, true);
     517       11517 :         return;
     518             :     }
     519             : 
     520             :     // Update read statistics.
     521     1277403 :     session->stats_.read_calls++;
     522     1277403 :     session->stats_.read_bytes += bytes_transferred;
     523     1277403 :     session->server_->stats_.read_calls++;
     524     1277403 :     session->server_->stats_.read_bytes += bytes_transferred;
     525             : 
     526     1277403 :     Task *task = session->CreateReaderTask(buffer, bytes_transferred);
     527             :     // Starting a new task for the session
     528     1277403 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
     529     1277403 :     scheduler->Enqueue(task);
     530     1298434 : }
     531             : 
     532        4610 : int TcpSession::GetSessionInstance() const {
     533        4610 :     return Task::kTaskInstanceAny;
     534             : }
     535             : 
     536             : 
     537       20850 : int32_t TcpSession::local_port() const {
     538       20850 :     if (socket() == NULL) {
     539           0 :         return -1;
     540             :     }
     541       20850 :     error_code error;
     542       20850 :     Endpoint local = socket()->local_endpoint(error);
     543       20848 :     if (IsSocketErrorHard(error)) {
     544           0 :         return -1;
     545             :     }
     546       20847 :     return local.port();
     547             : }
     548             : 
     549       20847 : int32_t TcpSession::remote_port() const {
     550       20847 :     if (socket() == NULL) {
     551           0 :         return -1;
     552             :     }
     553       20848 :     error_code error;
     554       20848 :     Endpoint remote = socket()->remote_endpoint(error);
     555       20849 :     if (IsSocketErrorHard(error)) {
     556        1242 :         return -1;
     557             :     }
     558       19607 :     return remote.port();
     559             : }
     560             : 
     561        1405 : int TcpSession::SetMd5SocketOption(uint32_t peer_ip,
     562             :                                    const string &md5_password) {
     563        1405 :     return server()->SetMd5SocketOption(socket_->native_handle(), peer_ip,
     564        1405 :                                         md5_password);
     565             : }
     566             : 
     567           0 : int TcpSession::ClearMd5SocketOption(uint32_t peer_ip) {
     568           0 :     return server()->SetMd5SocketOption(socket_->native_handle(), peer_ip, "");
     569             : }
     570             : 
     571        4294 : int TcpSession::SetDscpSocketOption(uint8_t value) {
     572        4294 :     return server()->SetDscpSocketOption(socket()->native_handle(), value);
     573             : }
     574             : 
     575         968 : uint8_t TcpSession::GetDscpValue() const {
     576         968 :     return server_->GetDscpValue(socket()->native_handle());
     577             : }
     578             : 
     579       14660 : TcpMessageReader::TcpMessageReader(TcpSession *session,
     580       14660 :                                    ReceiveCallback callback)
     581       14660 :     : session_(session), callback_(callback), offset_(0), remain_(-1) {
     582       14653 : }
     583             : 
     584       14669 : TcpMessageReader::~TcpMessageReader() {
     585       14669 : }
     586             : 
     587             : // Returns a buffer allocation size that is larger than the message.
     588           4 : int TcpMessageReader::AllocBufferSize(int length) {
     589           4 :     const int kMaxMessageSize = GetMaxMessageSize();
     590           4 :     if (length == -1) {
     591           0 :         return kMaxMessageSize;
     592             :     }
     593           4 :     int bufsize = 1 << 8;
     594           6 :     for (; bufsize < kMaxMessageSize && bufsize < length; bufsize <<= 1) {
     595             :     }
     596           4 :     return bufsize;
     597             : }
     598             : 
     599           4 : uint8_t *TcpMessageReader::BufferConcat(uint8_t *data, Buffer buffer,
     600             :                                         int msglength) {
     601           4 :     uint8_t *dst = data;
     602             : 
     603          14 :     while (!queue_.empty()) {
     604          10 :         Buffer head = queue_.front();
     605          10 :         const uint8_t *cp = TcpSession::BufferData(head) + offset_;
     606          10 :         int bytes = TcpSession::BufferSize(head) - offset_;
     607          10 :         assert((dst - data) + bytes < msglength);
     608          10 :         memcpy(dst, cp, bytes);
     609          10 :         dst += bytes;
     610          10 :         queue_.pop_front();
     611          10 :         session_->ReleaseBuffer(head);
     612          10 :         offset_ = 0;
     613          10 :         remain_ = -1;
     614             :     }
     615             : 
     616           4 :     int count = msglength - (dst - data);
     617           4 :     assert((dst - data) + count <= msglength);
     618           4 :     memcpy(dst, TcpSession::BufferData(buffer), count);
     619           4 :     offset_ = count;
     620             : 
     621           4 :     return data;
     622             : }
     623             : 
     624           6 : int TcpMessageReader::QueueByteLength() const {
     625           6 :     int total = 0;
     626           6 :     for (BufferQueue::const_iterator iter = queue_.begin();
     627          18 :          iter != queue_.end(); ++iter) {
     628          12 :         if (total == 0) {
     629           6 :             total = TcpSession::BufferSize(*iter) - offset_;
     630             :         } else {
     631           6 :             total += TcpSession::BufferSize(*iter);
     632             :         }
     633             :     }
     634           6 :     return total;
     635             : }
     636             : 
     637           4 : TcpMessageReader::Buffer TcpMessageReader::PullUp(
     638             :                uint8_t *data, Buffer buffer, size_t size) const {
     639           4 :     size_t offset = 0;
     640             : 
     641           4 :     for (BufferQueue::const_iterator iter = queue_.begin();
     642          14 :          iter != queue_.end(); ++iter) {
     643             :         const uint8_t *cp;
     644             :         int avail;
     645          10 :         if (offset == 0) {
     646           4 :             cp = TcpSession::BufferData(*iter) + offset_;
     647           4 :             avail = TcpSession::BufferSize(*iter) - offset_;
     648             :         } else {
     649           6 :             cp = TcpSession::BufferData(*iter);
     650           6 :             avail = TcpSession::BufferSize(*iter);
     651             :         }
     652          10 :         int remain = size - offset;
     653          10 :         avail = min(avail, remain);
     654          10 :         assert(offset + avail <= size);
     655          10 :         memcpy(data + offset, cp, avail);
     656          10 :         offset += avail;
     657             :     }
     658             : 
     659           4 :     int avail = TcpSession::BufferSize(buffer);
     660           4 :     int remain = size - offset;
     661           4 :     avail = min(avail, remain);
     662           4 :     assert(offset + avail <= size);
     663           4 :     memcpy(data + offset, TcpSession::BufferData(buffer), avail);
     664           4 :     offset += avail;
     665             : 
     666           4 :     if (offset < size) {
     667           0 :         return Buffer();
     668             :     }
     669           4 :     return Buffer(data, size);
     670             : }
     671             : 
     672             : // Read the socket stream and send messages to the peer object.
     673      100595 : void TcpMessageReader::OnRead(Buffer buffer) {
     674      100595 :     const int kHeaderLenSize = GetHeaderLenSize();
     675      100594 :     size_t size = TcpSession::BufferSize(buffer);
     676      100591 :     TCP_SESSION_LOG_UT_DEBUG(session_, TCP_DIR_IN, "Read " << size << " bytes");
     677             : 
     678      100594 :     if (!queue_.empty()) {
     679          10 :         int msglength = MsgLength(queue_.front(), offset_);
     680          10 :         if (msglength < 0) {
     681           6 :             int queuelen = QueueByteLength();
     682           6 :             if (queuelen + static_cast<int>(size) < kHeaderLenSize) {
     683           2 :                 queue_.push_back(buffer);
     684           2 :                 return;
     685             :             }
     686           4 :             scoped_array<uint8_t> data(new uint8_t[kHeaderLenSize]);
     687           4 :             Buffer header = PullUp(data.get(), buffer, kHeaderLenSize);
     688           4 :             assert(TcpSession::BufferSize(header) == (size_t) kHeaderLenSize);
     689             : 
     690           4 :             msglength = MsgLength(header, 0);
     691           4 :             remain_ = msglength - queuelen;
     692           4 :         }
     693             : 
     694           8 :         assert(remain_ > 0);
     695           8 :         if (size < (size_t) remain_) {
     696           4 :             queue_.push_back(buffer);
     697           4 :             remain_ -= size;
     698           4 :             return;
     699             :         }
     700             : 
     701             :         // concat the buffers into a contiguous message.
     702           4 :         scoped_array<uint8_t> data(new uint8_t[AllocBufferSize(msglength)]);
     703           4 :         BufferConcat(data.get(), buffer, msglength);
     704           4 :         assert(remain_ == -1);
     705             :         // Receive the message
     706           4 :         bool success = callback_(data.get(), msglength);
     707           4 :         if (!success)
     708           0 :             return;
     709           4 :     }
     710             : 
     711      100588 :     int avail = size - offset_;
     712      276961 :     while (avail > 0) {
     713      176403 :         int msglength = MsgLength(buffer, offset_);
     714      176399 :         if (msglength < 0) {
     715           2 :             break;
     716             :         }
     717      176397 :         if (msglength > avail) {
     718           2 :             remain_ = msglength - avail;
     719           2 :             break;
     720             :         }
     721             :         // Receive the message
     722             :         bool success =
     723      176395 :             callback_(TcpSession::BufferData(buffer) + offset_, msglength);
     724      176402 :         offset_ += msglength;
     725      176402 :         avail -= msglength;
     726      176402 :         if (!success)
     727          29 :             return;
     728             :     }
     729             : 
     730      100562 :     if (avail > 0) {
     731           4 :         queue_.push_back(buffer);
     732             :     } else {
     733      100558 :         session_->ReleaseBuffer(buffer);
     734      100559 :         offset_ = 0;
     735      100559 :         assert(remain_ == -1);
     736             :     }
     737             : }
     738             : 
     739             : //
     740             : // Check if a socker error is hard and fatal. Only then should we close the
     741             : // socket. Soft errors like EINTR and EAGAIN should be ignored or properly
     742             : // handled with retries
     743             : //
     744     3158987 : bool TcpSession::IsSocketErrorHard(const error_code &ec) {
     745     3158987 :     if (!ec)
     746     3001425 :         return false;
     747      157561 :     if (ec == try_again)
     748      144750 :         return false;
     749       12813 :     if (ec == would_block)
     750           0 :         return false;
     751       12813 :     if (ec == in_progress)
     752           0 :         return false;
     753       12813 :     if (ec == interrupted)
     754           0 :         return false;
     755       12813 :     if (ec == network_down)
     756           0 :         return false;
     757       12813 :     if (ec == network_reset)
     758           0 :         return false;
     759       12813 :     if (ec == network_unreachable)
     760           0 :         return false;
     761       12813 :     if (ec == no_buffer_space)
     762           0 :         return false;
     763             : 
     764       12813 :     return true;
     765             : }
     766             : 
     767           0 : error_code TcpSession::SetTcpNoDelay() {
     768           0 :     error_code ec;
     769           0 :     boost::asio::ip::tcp::no_delay no_delay_option(true);
     770           0 :     socket()->set_option(no_delay_option, ec);
     771           0 :     if (ec) {
     772           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     773             :                 "tcp_no_delay set error: " << ec);
     774             :     }
     775           0 :     return ec;
     776             : }
     777             : 
     778           0 : error_code TcpSession::SetTcpSendBufSize(uint32_t size) {
     779           0 :     error_code ec;
     780           0 :     socket_base::send_buffer_size send_buffer_size_option(size);
     781           0 :     socket()->set_option(send_buffer_size_option, ec);
     782           0 :     if (ec) {
     783           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     784             :                               "send_buffer_size set error: " << ec);
     785           0 :         return ec;
     786             :     }
     787             : 
     788           0 :     return ec;
     789             : }
     790             : 
     791           0 : error_code TcpSession::SetTcpRecvBufSize(uint32_t size) {
     792           0 :     error_code ec;
     793           0 :     socket_base::receive_buffer_size receive_buffer_size_option(size);
     794           0 :     socket()->set_option(receive_buffer_size_option, ec);
     795           0 :     if (ec) {
     796           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_IN,
     797             :                               "receive_buffer_size set error: " << ec);
     798           0 :         return ec;
     799             :     }
     800             : 
     801           0 :     return ec;
     802             : }
     803             : 
     804        6826 : error_code TcpSession::SetSocketKeepaliveOptions(int keepalive_time,
     805             :         int keepalive_intvl, int keepalive_probes, int tcp_user_timeout_val) {
     806        6826 :     error_code ec;
     807        6826 :     socket_base::keep_alive keep_alive_option(true);
     808        6826 :     socket()->set_option(keep_alive_option, ec);
     809        6826 :     if (ec) {
     810          22 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     811             :                 "keep_alive set error: " << ec);
     812          22 :         return ec;
     813             :     }
     814             : #ifdef TCP_KEEPIDLE
     815             :     typedef integer< IPPROTO_TCP, TCP_KEEPIDLE > keepalive_idle_time;
     816        6804 :     keepalive_idle_time keepalive_idle_time_option(keepalive_time);
     817        6804 :     socket()->set_option(keepalive_idle_time_option, ec);
     818        6804 :     if (ec) {
     819           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     820             :             "keepalive_idle_time: " << keepalive_time << " set error: " << ec);
     821           0 :         return ec;
     822             :     }
     823             : #elif TCP_KEEPALIVE
     824             :     typedef integer< IPPROTO_TCP, TCP_KEEPALIVE > keepalive_idle_time;
     825             :     keepalive_idle_time keepalive_idle_time_option(keepalive_time);
     826             :     socket()->set_option(keepalive_idle_time_option, ec);
     827             :     if (ec) {
     828             :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     829             :             "keepalive_idle_time: " << keepalive_time << " set error: " << ec);
     830             :         return ec;
     831             :     }
     832             : #else
     833             : #error No TCP keepalive option defined.
     834             : #endif
     835             : #ifdef TCP_KEEPINTVL
     836             :     typedef integer< IPPROTO_TCP, TCP_KEEPINTVL > keepalive_interval;
     837        6804 :     keepalive_interval keepalive_interval_option(keepalive_intvl);
     838        6804 :     socket()->set_option(keepalive_interval_option, ec);
     839        6804 :     if (ec) {
     840           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     841             :             "keepalive_interval: " << keepalive_intvl << " set error: " << ec);
     842           0 :         return ec;
     843             :     }
     844             : #endif
     845             : #ifdef TCP_KEEPCNT
     846             :     typedef integer< IPPROTO_TCP, TCP_KEEPCNT > keepalive_count;
     847        6804 :     keepalive_count keepalive_count_option(keepalive_probes);
     848        6804 :     socket()->set_option(keepalive_count_option, ec);
     849        6804 :     if (ec) {
     850           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     851             :             "keepalive_probes: " << keepalive_probes << " set error: " << ec);
     852           0 :         return ec;
     853             :     }
     854             : #endif
     855             : #ifdef TCP_USER_TIMEOUT
     856             :     typedef integer< IPPROTO_TCP, TCP_USER_TIMEOUT > tcp_user_timeout;
     857        6804 :     tcp_user_timeout tcp_user_timeout_option(tcp_user_timeout_val);
     858        6804 :     socket()->set_option(tcp_user_timeout_option, ec);
     859        6804 :     if (ec) {
     860           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     861             :             "tcp_user_timeout: " << tcp_user_timeout_val << " set error: "
     862             :             << ec);
     863           0 :         return ec;
     864             :     }
     865             : #endif
     866             : 
     867        6804 :     return ec;
     868             : }
     869             : 
     870       42032 : error_code TcpSession::SetSocketOptions() {
     871       42032 :     error_code ec;
     872             : 
     873             :     //
     874             :     // Make socket write non-blocking
     875             :     //
     876       42032 :     socket()->non_blocking(true, ec);
     877       42032 :     if (ec) {
     878           0 :         TCP_SESSION_LOG_ERROR(this, TCP_DIR_NA,
     879             :                               "Cannot set socket non blocking: " << ec);
     880           0 :         return ec;
     881             :     }
     882             : 
     883       42032 :     char *buffer_size_str = getenv("TCP_SESSION_SOCKET_BUFFER_SIZE");
     884       42026 :     if (!buffer_size_str) return ec;
     885             : 
     886          12 :     uint32_t sz = static_cast<uint32_t>(strtoul(buffer_size_str, NULL, 0));
     887          18 :     if (sz) {
     888             :         //
     889             :         // Set socket send and receive buffer size
     890             :         //
     891             :         // Currently used only under test environments to trigger partial
     892             :         // sends more deterministically
     893             :         //
     894          18 :         socket_base::send_buffer_size send_buffer_size_option(sz);
     895          18 :         socket()->set_option(send_buffer_size_option, ec);
     896          18 :         if (ec) {
     897           0 :             TCP_SESSION_LOG_ERROR(this, TCP_DIR_OUT,
     898             :                                   "send_buffer_size set error: " << ec);
     899           0 :             return ec;
     900             :         }
     901             : 
     902          18 :         socket_base::receive_buffer_size receive_buffer_size_option(sz);
     903          18 :         socket()->set_option(receive_buffer_size_option, ec);
     904          18 :         if (ec) {
     905           0 :             TCP_SESSION_LOG_ERROR(this, TCP_DIR_IN,
     906             :                                   "receive_buffer_size set error: " << ec);
     907           0 :             return ec;
     908             :         }
     909             :     }
     910             : 
     911          18 :     return ec;
     912             : }
     913             : 
     914           8 : void TcpSession::GetRxSocketStats(SocketIOStats *socket_stats) const {
     915           8 :     stats_.GetRxStats(socket_stats);
     916           8 : }
     917             : 
     918           6 : void TcpSession::GetTxSocketStats(SocketIOStats *socket_stats) const {
     919           6 :     stats_.GetTxStats(socket_stats);
     920           6 : }

Generated by: LCOV version 1.14