LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/sandesh/library/cpp - sandesh_session.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 268 370 72.4 %
Date: 2026-11-09 02:10:49 Functions: 30 35 85.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             : //
       7             : // sandesh_session.cc
       8             : //
       9             : // Sandesh session
      10             : //
      11             : 
      12             : #include <boost/bind/bind.hpp>
      13             : #include <boost/assign.hpp>
      14             : #include <boost/algorithm/string.hpp>
      15             : 
      16             : #include <base/parse_object.h>
      17             : 
      18             : #include <sandesh/common/vns_types.h>
      19             : #include <sandesh/common/vns_constants.h>
      20             : #include <sandesh/transport/TBufferTransports.h>
      21             : #include <sandesh/protocol/TXMLProtocol.h>
      22             : #include <sandesh/protocol/TJSONProtocol.h>
      23             : #include "sandesh/sandesh_types.h"
      24             : #include "sandesh/sandesh.h"
      25             : 
      26             : #include "sandesh_connection.h"
      27             : #include "sandesh_session.h"
      28             : 
      29             : 
      30             : using namespace std;
      31             : using namespace contrail::sandesh::protocol;
      32             : using namespace contrail::sandesh::transport;
      33             : using namespace boost::placeholders;
      34             : 
      35             : using boost::asio::mutable_buffer;
      36             : using boost::asio::buffer_cast;
      37             : 
      38             : const std::string SandeshWriter::sandesh_open_ = sXML_SANDESH_OPEN;
      39             : const std::string SandeshWriter::sandesh_open_attr_length_ =
      40             :         sXML_SANDESH_OPEN_ATTR_LENGTH;
      41             : const std::string SandeshWriter::sandesh_close_ = sXML_SANDESH_CLOSE;
      42             : 
      43             : //
      44             : // SandeshWriter
      45             : //
      46         142 : SandeshWriter::SandeshWriter(SandeshSession *session)
      47         142 :     : session_(session),
      48         142 :     ready_to_send_(true),
      49         142 :     send_buf_(new uint8_t[kDefaultSendSize]),
      50         142 :     send_buf_offset_(0) {
      51         142 : }
      52             : 
      53         142 : SandeshWriter::~SandeshWriter() {
      54         142 :     delete [] send_buf_;
      55         142 : }
      56             : 
      57           0 : void SandeshWriter::WriteReady(const boost::system::error_code &ec) {
      58           0 :     if (ec) {
      59           0 :         SANDESH_LOG(ERROR, "SandeshSession Write error value: " << ec.value()
      60             :             << " category: " << ec.category().name()
      61             :             << " message: " << ec.message());
      62           0 :         session_->increment_write_ready_cb_error();
      63           0 :         return;
      64             :     }
      65             : 
      66             :     {
      67           0 :         std::scoped_lock lock(send_mutex_);
      68           0 :         ready_to_send_ = true;
      69           0 :     }
      70             : 
      71             :     // We may want to start the Runner for the send_queue
      72           0 :     session_->send_queue()->MayBeStartRunner();
      73             : }
      74             : 
      75       12973 : void SandeshWriter::SendMsg(Sandesh *sandesh, bool more) {
      76       12973 :     SandeshHeader header;
      77       12973 :     std::stringstream ss;
      78             :     uint8_t *buffer;
      79       12973 :     int32_t xfer = 0, ret;
      80             :     uint32_t offset;
      81             :     boost::shared_ptr<TMemoryBuffer> btrans(
      82       12973 :                     new TMemoryBuffer(kEncodeBufferSize));
      83             :     boost::shared_ptr<TXMLProtocol> prot(
      84       12973 :                     new TXMLProtocol(btrans));
      85             :     // Populate the header
      86       12973 :     header.set_Namespace(sandesh->scope());
      87       12973 :     header.set_Timestamp(sandesh->timestamp());
      88       12973 :     header.set_Module(sandesh->module());
      89       12973 :     header.set_Source(sandesh->source());
      90       12973 :     header.set_Context(sandesh->context());
      91       12973 :     header.set_SequenceNum(sandesh->seqnum());
      92       12973 :     header.set_VersionSig(sandesh->versionsig());
      93       12973 :     header.set_Type(sandesh->type());
      94       12973 :     header.set_Hints(sandesh->hints());
      95       12973 :     header.set_Level(sandesh->level());
      96       12973 :     header.set_Category(sandesh->category());
      97       12973 :     header.set_NodeType(sandesh->node_type());
      98       12973 :     header.set_InstanceId(sandesh->instance_id());
      99             : 
     100             :     // Write the sandesh open envelope.
     101       12973 :     buffer = btrans->getWritePtr(sandesh_open_.length());
     102       12973 :     memcpy(buffer, sandesh_open_.c_str(), sandesh_open_.length());
     103       12973 :     btrans->wroteBytes(sandesh_open_.length());
     104             :     // Write the sandesh header
     105       12973 :     if ((ret = header.write(prot)) < 0) {
     106           0 :         SANDESH_LOG(ERROR, __func__ << ": Sandesh header write FAILED: " <<
     107             :             sandesh->Name() << " : " << sandesh->source() << ":" <<
     108             :             sandesh->module() << ":" << sandesh->instance_id() <<
     109             :             " Sequence Number:" << sandesh->seqnum());
     110           0 :         session_->increment_send_msg_fail();
     111           0 :         Sandesh::UpdateTxMsgFailStats(sandesh->Name(), 0,
     112             :             SandeshTxDropReason::HeaderWriteFailed);
     113           0 :         sandesh->Release();
     114           0 :         return;
     115             :     }
     116       12973 :     xfer += ret;
     117             :     // Write the sandesh
     118       12973 :     if ((ret = sandesh->Write(prot)) < 0) {
     119           0 :         SANDESH_LOG(ERROR, __func__ << ": Sandesh write FAILED: "<<
     120             :             sandesh->Name() << " : " << sandesh->source() << ":" <<
     121             :             sandesh->module() << ":" << sandesh->instance_id() <<
     122             :             " Sequence Number:" << sandesh->seqnum());
     123           0 :         session_->increment_send_msg_fail();
     124           0 :         Sandesh::UpdateTxMsgFailStats(sandesh->Name(), 0,
     125             :             SandeshTxDropReason::WriteFailed);
     126           0 :         sandesh->Release();
     127           0 :         return;
     128             :     }
     129       12973 :     xfer += ret;
     130             :     // Write the sandesh close envelope
     131       12973 :     buffer = btrans->getWritePtr(sandesh_close_.length());
     132       12973 :     memcpy(buffer, sandesh_close_.c_str(), sandesh_close_.length());
     133       12973 :     btrans->wroteBytes(sandesh_close_.length());
     134             :     // Get the buffer
     135       12973 :     btrans->getBuffer(&buffer, &offset);
     136             :     // Sanity
     137       12973 :     assert(sandesh_open_.length() + xfer + sandesh_close_.length() ==
     138             :             offset);
     139             :     // Update the sandesh open envelope length;
     140       12973 :     char prev = ss.fill('0');
     141             :     // Adjust for '">'
     142       12973 :     ss.width(sandesh_open_.length() - sandesh_open_attr_length_.length() - 2);
     143       12973 :     ss << offset;
     144       12973 :     ss.fill(prev);
     145       12973 :     memcpy(buffer + sandesh_open_attr_length_.length(), ss.str().c_str(),
     146       25946 :             ss.str().length());
     147             : 
     148             :     // Update sandesh stats
     149       12973 :     Sandesh::UpdateTxMsgStats(sandesh->Name(), offset);
     150       12973 :     session_->increment_send_msg();
     151             : 
     152       12973 :     if (send_buf()) {
     153       12973 :         if (more) {
     154             :             // There are more messages in the send_queue_.
     155             :             // Try to package as many sandesh messages as possible
     156             :             // (== kEncodeBufferSize) before transporting to the
     157             :             // receiver.
     158        6877 :             SendMsgMore(btrans);
     159             :         } else {
     160             :             // send_queue_ is empty. Flush sandesh->send_buf_ and this message.
     161        6096 :             SendMsgAll(btrans);
     162             :         }
     163             :     } else {
     164             :         // Send the message
     165           0 :         SendInternal(btrans);
     166             :     }
     167       12973 :     sandesh->Release();
     168       12973 : }
     169             : 
     170             : // Package as many sandesh messages as possible [not more than
     171             : // kEncodeBufferSize] before transporting it to the receiver.
     172             : //
     173             : // send_buf_ => unsent data (partial/complete message).
     174             : // buf => new message
     175             : // buf_len => buf's len
     176        6877 : void SandeshWriter::SendMsgMore(boost::shared_ptr<TMemoryBuffer>
     177             :                                             send_buffer) {
     178             :     uint8_t *buf;
     179             :     uint32_t buf_len;
     180             : 
     181        6877 :     send_buffer->getBuffer(&buf, &buf_len);
     182             : 
     183        6877 :     if (send_buf_offset()) {
     184             :         // We have some unsent data.
     185        4630 :         size_t bulk_msg_len = send_buf_offset() + buf_len;
     186        4630 :         if (bulk_msg_len < kDefaultSendSize) {
     187             :             // We still have space for more data. Don't send the message yet.
     188             :             // Add the message to the existing data.
     189        4413 :             append_send_buf(buf, buf_len);
     190             :         } else {
     191             :             uint8_t *buffer;
     192             :             // (send_buf_offset() + buf_len) >= kDefaultSendSize
     193             :             boost::shared_ptr<TMemoryBuffer> bulk_msg(
     194         217 :                     new TMemoryBuffer(send_buf_offset()));
     195         217 :             buffer = bulk_msg->getWritePtr(send_buf_offset());
     196             :             // Copy unsent data
     197         217 :             memcpy(buffer, send_buf(), send_buf_offset());
     198         217 :             bulk_msg->wroteBytes(send_buf_offset());
     199             :             // Send it
     200         217 :             SendInternal(bulk_msg);
     201             :             // Cleanup send_buf
     202         217 :             reset_send_buf();
     203             :             // Next send the new message
     204         217 :             SendInternal(send_buffer);
     205         217 :         }
     206             :     } else {
     207             :         // We don't have any unsent data.
     208        2247 :         if (buf_len >= kDefaultSendSize) {
     209             :             // We don't have room to accommodate anything more.
     210             :             // Send the message now.
     211          17 :             SendInternal(send_buffer);
     212             :         } else {
     213             :             // We have room to accommodate more data.
     214             :             // Save this message.
     215             :             // Note: The memcpy here can be avoided by passing send_buf_
     216             :             // to TMemoryBuffer so that the message is encoded in
     217             :             // send_buf_ itself.
     218        2230 :             set_send_buf(buf, buf_len);
     219             :         }
     220             :     }
     221        6877 : }
     222             : 
     223             : // sandesh->send_queue_ is empty.
     224             : // Flush unsent data (if any) and this message.
     225        6096 : void SandeshWriter::SendMsgAll(boost::shared_ptr<TMemoryBuffer> send_buffer) {
     226             :     uint8_t *buf;
     227             :     uint32_t buf_len;
     228             : 
     229        6096 :     send_buffer->getBuffer(&buf, &buf_len);
     230             : 
     231        6096 :     if (send_buf_offset()) {
     232             :         // We have some unsent data.
     233        2013 :         size_t bulk_msg_len = send_buf_offset() + buf_len;
     234        2013 :         if (bulk_msg_len <= kDefaultSendSize) {
     235             :             uint8_t *buffer;
     236             :             // We have enough room to send all the pending data in one message.
     237             :             boost::shared_ptr<TMemoryBuffer> bulk_msg(new
     238        1960 :                     TMemoryBuffer(bulk_msg_len));
     239        1960 :             buffer = bulk_msg->getWritePtr(bulk_msg_len);
     240        1960 :             memcpy(buffer, send_buf(), send_buf_offset());
     241        1960 :             memcpy(buffer + send_buf_offset(), buf, buf_len);
     242        1960 :             bulk_msg->wroteBytes(bulk_msg_len);
     243             :             // send the message
     244        1960 :             SendInternal(bulk_msg);
     245             :             // reset send_buf_
     246        1960 :             reset_send_buf();
     247        1960 :         } else {
     248             :             uint8_t *buffer;
     249             :             // We don't have enough space to accommodate all the
     250             :             // pending data in one message.
     251             :             boost::shared_ptr<TMemoryBuffer> old_buf(new
     252          53 :                     TMemoryBuffer(send_buf_offset()));
     253          53 :             buffer = old_buf->getWritePtr(send_buf_offset());
     254          53 :             memcpy(buffer, send_buf(),
     255             :                    send_buf_offset());
     256          53 :             old_buf->wroteBytes(send_buf_offset());
     257             :             // Take care of the unsent data in send_buf_ first.
     258             :             // Note that we could have accomodated part of buf [last message]
     259             :             // here. But, not doing so to avoid additional memcpy() :)
     260          53 :             SendInternal(old_buf);
     261             :             // Cleanup send_buf_
     262          53 :             reset_send_buf();
     263             :             // Well, send the last message now.
     264          53 :             SendInternal(send_buffer);
     265          53 :         }
     266             :     } else {
     267             :         // No unsent data. Send the message now.
     268        4083 :         SendInternal(send_buffer);
     269             :     }
     270        6096 : }
     271             : 
     272        6600 : void SandeshWriter::SendInternal(boost::shared_ptr<TMemoryBuffer> buf) {
     273             :     uint8_t  *buffer;
     274             :     uint32_t len;
     275        6600 :     buf->getBuffer(&buffer, &len);
     276        6600 :     std::scoped_lock lock(send_mutex_);
     277        6600 :     ready_to_send_ = session_->Send((const uint8_t *)buffer, len, NULL);
     278        6600 : }
     279             : 
     280             : //
     281             : // SandeshSession
     282             : //
     283         142 : SandeshSession::SandeshSession(SslServer *client, SslSocket *socket,
     284         142 :         int task_instance, int writer_task_id, int reader_task_id) :
     285             :     SslSession(client, socket),
     286         142 :     instance_(task_instance),
     287         142 :     writer_(new SandeshWriter(this)),
     288         142 :     reader_(new SandeshReader(this)),
     289         284 :     send_queue_(new Sandesh::SandeshQueue(writer_task_id,
     290             :             task_instance,
     291             :             boost::bind(&SandeshSession::SendMsg, this, _1),
     292         142 :             kQueueSize)),
     293         142 :     stats_client_(NULL),
     294         142 :     connection_(NULL),
     295         142 :     keepalive_idle_time_(kSessionKeepaliveIdleTime),
     296         142 :     keepalive_interval_(kSessionKeepaliveInterval),
     297         142 :     keepalive_probes_(kSessionKeepaliveProbes),
     298         142 :     tcp_user_timeout_(kSessionTcpUserTimeout),
     299         142 :     reader_task_id_(reader_task_id),
     300         284 :     sending_level_(SandeshLevel::INVALID) {
     301         142 :     if (Sandesh::role() == Sandesh::SandeshRole::Collector) {
     302           0 :         send_buffer_queue_.reset(new Sandesh::SandeshBufferQueue(writer_task_id,
     303             :                 task_instance,
     304           0 :                 boost::bind(&SandeshSession::SendBuffer, this, _1)));
     305           0 :         send_buffer_queue_->SetStartRunnerFunc(boost::bind(&SandeshSession::SessionSendReady, this));
     306             :     }
     307         142 :     send_queue_->SetStartRunnerFunc(boost::bind(&SandeshSession::SessionSendReady, this));
     308         142 : }
     309             : 
     310         284 : SandeshSession::~SandeshSession() {
     311         284 : }
     312             : 
     313       12192 : bool SandeshSession::SessionSendReady() {
     314       24384 :     return (IsEstablished() && writer_->SendReady() &&
     315       24384 :             Sandesh::IsSendQueueEnabled());
     316             : }
     317             : 
     318         840 : void SandeshSession::SetSendQueueWaterMark(
     319             :     Sandesh::QueueWaterMarkInfo &swmi) {
     320         840 :     WaterMarkInfo wm(boost::get<0>(swmi),
     321             :         boost::bind(&SandeshSession::SetSendingLevel, this, _1,
     322        1680 :             boost::get<1>(swmi)));
     323         840 :     if (boost::get<2>(swmi)) {
     324         420 :         send_queue_->SetHighWaterMark(wm);
     325             :     } else {
     326         420 :         send_queue_->SetLowWaterMark(wm);
     327             :     }
     328         840 : }
     329             : 
     330           0 : void SandeshSession::ResetSendQueueWaterMark() {
     331           0 :     send_queue_->ResetHighWaterMark();
     332           0 :     send_queue_->ResetLowWaterMark();
     333           0 : }
     334             : 
     335         142 : void SandeshSession::SetSendingLevel(size_t count, SandeshLevel::type level) {
     336         142 :     if (sending_level_ != level) {
     337           0 :         sending_level_ = level;
     338             :     }
     339         142 : }
     340             : 
     341       13449 : SandeshLevel::type SandeshSession::SendingLevel() const {
     342       13449 :     return sending_level_;
     343             : }
     344             : 
     345         142 : void SandeshSession::Shutdown() {
     346         142 :     if (Sandesh::role() == Sandesh::SandeshRole::Collector) {
     347           0 :         send_buffer_queue_->Shutdown();
     348             :     }
     349         142 :     send_queue_->Shutdown();
     350         142 : }
     351             : 
     352         684 : std::string SandeshSession::ToString() const {
     353         684 :     std::stringstream out;
     354         684 :     out << TcpSession::ToString() << "(" << instance_ << ")";
     355        1368 :     return out.str();
     356         684 : }
     357             : 
     358         238 : boost::system::error_code SandeshSession::SetSocketOptions() {
     359         238 :     boost::system::error_code ec = TcpSession::SetSocketOptions();
     360         238 :     if (ec) {
     361           0 :         return ec;
     362             :     }
     363         238 :     return SetSocketKeepaliveOptions(keepalive_idle_time_, keepalive_interval_,
     364         238 :             keepalive_probes_, tcp_user_timeout_);
     365             : }
     366             : 
     367        5850 : void SandeshSession::OnRead(Buffer buffer) {
     368        5850 :     reader_->OnRead(buffer);
     369        5850 : }
     370             : 
     371       12973 : bool SandeshSession::SendMsg(SandeshElement element) {
     372       12973 :     Sandesh *sandesh = element.snh_;
     373       12973 :     std::scoped_lock lock(send_mutex_);
     374       12973 :     if (!IsEstablished()) {
     375           0 :         if (Sandesh::IsLoggingDroppedAllowed(sandesh->type())) {
     376           0 :             SANDESH_LOG(ERROR, __func__ << " Not Connected : Dropping Message: " <<
     377             :                 sandesh->ToString());
     378             :         }
     379           0 :         increment_send_msg_fail();
     380           0 :         Sandesh::UpdateTxMsgFailStats(sandesh->Name(), 0,
     381             :             SandeshTxDropReason::SessionNotConnected);
     382           0 :         sandesh->Release();
     383           0 :         return true;
     384             :     }
     385       12973 :     if (sandesh->IsLoggingAllowed()) {
     386        9180 :         sandesh->Log();
     387             :     }
     388       12973 :     bool more = !send_queue_->IsQueueEmpty();
     389       12973 :     if (stats_client_ && sandesh->type() == SandeshType::UVE) {
     390           0 :         stats_client_->SendMsg(sandesh);
     391             :     }
     392       12973 :     writer_->SendMsg(sandesh, more);
     393       12973 :     return true;
     394       12973 : }
     395             : 
     396           0 : bool SandeshSession::SendBuffer(boost::shared_ptr<TMemoryBuffer> sbuffer) {
     397           0 :     std::scoped_lock lock(send_mutex_);
     398           0 :     if (!IsEstablished()) {
     399           0 :         increment_send_buffer_fail();
     400           0 :         return true;
     401             :     }
     402             :     // No buffer packing supported currently
     403           0 :     writer_->SendBuffer(sbuffer);
     404           0 :     return true;
     405           0 : }
     406             : 
     407           0 : bool SandeshSession::EnqueueBuffer(u_int8_t *buf, u_int32_t buf_len) {
     408           0 :     boost::shared_ptr<TMemoryBuffer> sbuffer(new TMemoryBuffer(buf_len));
     409           0 :     u_int8_t *write_buf = sbuffer->getWritePtr(buf_len);
     410           0 :     memcpy(write_buf, buf, buf_len);
     411           0 :     sbuffer->wroteBytes(buf_len);
     412           0 :     return send_buffer_queue()->Enqueue(sbuffer);
     413           0 : }
     414             : 
     415         123 : Sandesh * SandeshSession::DecodeCtrlSandesh(const string& msg,
     416             :         const SandeshHeader& header,
     417             :         const string& sandesh_name, const uint32_t& header_offset) {
     418             :     namespace sandesh_prot = contrail::sandesh::protocol;
     419             :     namespace sandesh_trans = contrail::sandesh::transport;
     420             : 
     421         123 :     assert(header.get_Hints() & g_sandesh_constants.SANDESH_CONTROL_HINT);
     422             : 
     423             :     // Create and process the sandesh
     424         123 :     Sandesh *sandesh = SandeshBaseFactory::CreateInstance(sandesh_name);
     425         123 :     if (sandesh == NULL) {
     426           0 :         SANDESH_LOG(ERROR, __func__ << ": Unknown sandesh ctrl message: " << sandesh_name);
     427           0 :         return NULL;
     428             :     }
     429             :     boost::shared_ptr<sandesh_trans::TMemoryBuffer> btrans =
     430             :             boost::shared_ptr<sandesh_trans::TMemoryBuffer>(
     431         123 :                     new sandesh_trans::TMemoryBuffer((uint8_t *)msg.c_str() + header_offset,
     432         123 :                             msg.size() - header_offset));
     433             :     boost::shared_ptr<sandesh_prot::TXMLProtocol> prot =
     434         123 :             boost::shared_ptr<sandesh_prot::TXMLProtocol>(new sandesh_prot::TXMLProtocol(btrans));
     435         123 :     int32_t xfer = sandesh->Read(prot);
     436         123 :     if (xfer < 0) {
     437           0 :         SANDESH_LOG(ERROR, __func__ << ": Decoding " << sandesh_name << " for ctrl FAILED");
     438           0 :         sandesh->Release();
     439           0 :         return NULL;
     440             :     } else {
     441         123 :         return sandesh;
     442             :     }
     443         123 : }
     444             : 
     445           0 : void SandeshSession::EnqueueClose() {
     446           0 :     if (IsClosed()) {
     447           0 :         return;
     448             :     }
     449           0 :     std::scoped_lock lock(conn_mutex_);
     450           0 :     if (connection_) {
     451           0 :         connection_->state_machine()->OnSessionEvent(this,
     452             :             TcpSession::CLOSE);
     453             :     } else {
     454           0 :         TcpSession::EventObserver eobs(observer());
     455           0 :         if (eobs) {
     456           0 :             eobs(this, TcpSession::CLOSE);
     457             :         }
     458           0 :     }
     459           0 : }
     460             : 
     461             : //
     462             : // SandeshReader
     463             : //
     464         142 : SandeshReader::SandeshReader(SandeshSession *session) :
     465         142 :         buf_(""),
     466         142 :         offset_(0),
     467         142 :         msg_length_(-1),
     468         284 :         session_(session) {
     469         142 :     buf_.reserve(kDefaultRecvSize);
     470         142 : }
     471             : 
     472         284 : SandeshReader::~SandeshReader() {
     473         284 : }
     474             : 
     475         123 : int SandeshReader::ExtractMsgHeader(const std::string& msg,
     476             :         SandeshHeader& header, std::string& msg_type, uint32_t& header_offset) {
     477         123 :     int32_t xfer = 0, ret;
     478             :     boost::shared_ptr<TMemoryBuffer> btrans =
     479             :             boost::shared_ptr<TMemoryBuffer>(
     480         123 :                     new TMemoryBuffer((uint8_t *)msg.c_str(), msg.size()));
     481             :     boost::shared_ptr<TXMLProtocol> prot =
     482         123 :             boost::shared_ptr<TXMLProtocol>(new TXMLProtocol(btrans));
     483             :     // Read the sandesh header and note the offset
     484         123 :     if ((ret = header.read(prot)) <= 0) {
     485           0 :         SANDESH_LOG(ERROR, __func__ << ": Sandesh header read FAILED: " << msg);
     486           0 :         return EINVAL;
     487             :     }
     488         123 :     xfer += ret;
     489         123 :     header_offset = xfer;
     490             :     // Extract the message name
     491         123 :     if ((ret = prot->readSandeshBegin(msg_type)) <= 0) {
     492           0 :         SANDESH_LOG(ERROR, __func__ << ": Sandesh begin read FAILED: " << msg);
     493           0 :         return EINVAL;
     494             :     }
     495         123 :     xfer += ret;
     496         123 :     return 0;
     497         123 : }
     498             : 
     499        5850 : void SandeshReader::SetBuf(const std::string &str) {
     500        5850 :     if (buf_.empty()) {
     501        4943 :         ReplaceBuf(str);
     502             :     } else {
     503         907 :         buf_ += str;
     504             :     }
     505             :     // TODO handle buf_ > kMaxMessageSize
     506        5850 : }
     507             : 
     508       14282 : void SandeshReader::ReplaceBuf(const std::string &str) {
     509       14282 :     buf_ = str;
     510       14282 :     buf_.reserve(SandeshReader::kDefaultRecvSize);
     511       14282 :     offset_ = 0;
     512       14282 : }
     513             : 
     514       12535 : bool SandeshReader::LeftOver() const {
     515       12535 :     if (buf_.empty()) {
     516           0 :         return false;
     517             :     }
     518       12535 :     return (buf_.size() != offset_);
     519             : }
     520             : 
     521             : // Returns false if not able to extract the message length, true otherwise
     522       14292 : bool SandeshReader::ExtractMsgLength(size_t &msg_length, int *result) {
     523             :     // Have we read enough to extract the message length?
     524       14292 :     if (buf_.size() - offset_ < SandeshWriter::sandesh_open_.size()) {
     525        1757 :         return false;
     526             :     }
     527             :     // Some sanity check
     528       12535 :     if (!boost::algorithm::starts_with(buf_.c_str() + offset_,
     529             :             SandeshWriter::sandesh_open_attr_length_)) {
     530           0 :         *result = -1;
     531           0 :         return false;
     532             :     }
     533             : 
     534       12535 :     std::string::const_iterator end = buf_.begin() + offset_ +
     535       25070 :             SandeshWriter::sandesh_open_.size() - 1;
     536       12535 :     if (*end != '>') {
     537           0 :         *result = -2;
     538           0 :         return false;
     539             :     }
     540             : 
     541       12535 :     std::string::const_iterator st = buf_.begin() + offset_ +
     542       25070 :             SandeshWriter::sandesh_open_attr_length_.size();
     543             :     // Adjust for double quote
     544       12535 :     --end;
     545       12535 :     string length = string(st, end);
     546             : 
     547       12535 :     stringToInteger(length.c_str(), msg_length);
     548       12535 :     if (msg_length == 0) {
     549           0 :         *result = -3;
     550           0 :         return false;
     551             :     }
     552       12535 :     return true;
     553       12535 : }
     554             : 
     555             : // Returns false if not able to extract the full message, true otherwise
     556       15189 : bool SandeshReader::ExtractMsg(Buffer buffer, int *result, bool NewBuf) {
     557       15189 :     if (NewBuf) {
     558        5850 :         const uint8_t *cp = TcpSession::BufferData(buffer);
     559             :         // TODO Avoid this copy
     560        5850 :         std::string str(cp, cp + TcpSession::BufferSize(buffer));
     561        5850 :         SetBuf(str);
     562        5850 :     }
     563             :     // Extract the message length
     564       15189 :     if (!MsgLengthKnown()) {
     565       14292 :         size_t msg_length = 0;
     566       14292 :         bool done = ExtractMsgLength(msg_length, result);
     567       14292 :         if (done == false) {
     568        1757 :             return false;
     569             :         }
     570       12535 :         set_msg_length(msg_length);
     571             :     }
     572             :     // Check if the entire message is read or not
     573       13432 :     if (buf_.size() < msg_length()) {
     574         897 :         return false;
     575             :     }
     576       12535 :     return true;
     577             : }
     578             : 
     579        5850 : void SandeshReader::OnRead(Buffer buffer) {
     580        5850 :     std::scoped_lock lock(cb_mutex_);
     581             :     // Check if session is being deleted, then drop the packet
     582        5850 :     if (cb_.empty()) {
     583           0 :         SANDESH_LOG(ERROR, __func__ <<
     584             :             " Session being deleted: Dropping Message");
     585           0 :         session_->increment_recv_fail();
     586           0 :         session_->ReleaseBuffer(buffer);
     587           0 :         return;
     588             :     }
     589        5850 :     int result = 0;
     590        5850 :     bool done = ExtractMsg(buffer, &result, true);
     591             :     do {
     592       15189 :         if (result < 0) {
     593             :             // Generate error and close connection
     594           0 :             SANDESH_LOG(ERROR, __func__ << " Message extract failed: " << result);
     595           0 :             const uint8_t *cp = TcpSession::BufferData(buffer);
     596           0 :             size_t cp_size = TcpSession::BufferSize(buffer);
     597           0 :             SANDESH_LOG(ERROR, __func__ << " OnRead Buffer Size: " << cp_size);
     598           0 :             SANDESH_LOG(ERROR, __func__ << " OnRead Buffer: ");
     599           0 :             std::string debug((const char*)cp, cp_size);
     600           0 :             SANDESH_LOG(ERROR, debug);
     601           0 :             SANDESH_LOG(ERROR, __func__ << " Reader Size: " << buf_.size());
     602           0 :             SANDESH_LOG(ERROR, __func__ << " Reader Offset: " << offset_);
     603           0 :             SANDESH_LOG(ERROR, __func__ << " Reader Buffer: " << buf_);
     604           0 :             buf_.clear();
     605           0 :             offset_ = 0;
     606             :             // Enqueue a close on the state machine
     607           0 :             session_->increment_recv_fail();
     608           0 :             session_->EnqueueClose();
     609           0 :             break;
     610           0 :         }
     611       15189 :         if (done == true) {
     612             :             // We got good match. Process the message after extracting out
     613             :             // the sandesh open and close envelope
     614       12535 :             std::string::const_iterator st = buf_.begin() + offset_ +
     615       25070 :                     SandeshWriter::sandesh_open_.size();
     616       12535 :             std::string::const_iterator end = buf_.begin() + offset_ +
     617       25070 :                     msg_length() - SandeshWriter::sandesh_close_.size();
     618       12535 :             std::string xml(st, end);
     619       12535 :             offset_ += msg_length();
     620       12535 :             reset_msg_length();
     621       12535 :             if (!cb_(xml, session_)) {
     622             :                 // Enqueue a close on the state machine
     623           0 :                 session_->increment_recv_fail();
     624           0 :                 session_->EnqueueClose();
     625           0 :                 break;
     626             :             }
     627       12535 :         } else {
     628             :             // Read more data.
     629        2654 :             break;
     630             :         }
     631             : 
     632       12535 :         if (LeftOver()) {
     633        9339 :             ReplaceBuf(string(buf_, offset_, buf_.size() - offset_));
     634        9339 :             done = ExtractMsg(buffer, &result, false);
     635             :         } else {
     636             :             // No more data in the Buffer
     637        3196 :             buf_.clear();
     638        3196 :             offset_ = 0;
     639        3196 :             break;
     640             :         }
     641        9339 :     } while (true);
     642             : 
     643        5850 :     session_->ReleaseBuffer(buffer);
     644        5850 :     return;
     645        5850 : }
     646             : 
     647         284 : void SandeshReader::SetReceiveMsgCb(SandeshReceiveMsgCb cb) {
     648         284 :     std::scoped_lock lock(cb_mutex_);
     649         284 :     cb_ = cb;
     650         284 : }

Generated by: LCOV version 1.14