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

Generated by: LCOV version 1.14