LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/io - tcp_session.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 49 49 100.0 %
Date: 2026-11-09 02:10:49 Functions: 23 23 100.0 %
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             : #ifndef SRC_IO_TCP_SESSION_H_
       7             : #define SRC_IO_TCP_SESSION_H_
       8             : 
       9             : #include <deque>
      10             : #include <list>
      11             : #include <string>
      12             : #include <mutex>
      13             : #include <atomic>
      14             : 
      15             : #include <boost/asio/buffer.hpp>
      16             : #include <boost/asio/io_service.hpp>
      17             : #include <boost/asio/ip/tcp.hpp>
      18             : #include <boost/asio/strand.hpp>
      19             : #include <boost/intrusive_ptr.hpp>
      20             : #include <boost/function.hpp>
      21             : #include <boost/scoped_ptr.hpp>
      22             : 
      23             : #include "base/util.h"
      24             : #include "base/task.h"
      25             : #include "io/tcp_server.h"
      26             : 
      27             : #define SSL_SHORT_READ_ERROR 335544539
      28             : 
      29             : class EventManager;
      30             : class TcpServer;
      31             : class TcpSession;
      32             : class TcpMessageWriter;
      33             : 
      34             : // TcpSession
      35             : //
      36             : // Concurrency: the session is created by the event manager thread, which
      37             : // also invokes the AsyncHandlers. ReleaseBuffer and Send will typically be
      38             : // invoked by a different thread.
      39             : class TcpSession {
      40             : public:
      41             :     static const int kDefaultBufferSize = 16 * 1024;
      42             :     static const int kDefaultWriteBufferSize = 32 * 1024;
      43             : 
      44             :     enum Event {
      45             :         EVENT_NONE,
      46             :         ACCEPT,
      47             :         CONNECT_COMPLETE,
      48             :         CONNECT_FAILED,
      49             :         CLOSE
      50             :     };
      51             : 
      52             :     enum Direction {
      53             :         ACTIVE,
      54             :         PASSIVE
      55             :     };
      56             : 
      57             :     typedef boost::asio::ip::tcp::socket Socket;
      58             :     typedef boost::asio::ip::tcp::socket::native_handle_type NativeSocketType;
      59             :     typedef boost::asio::ip::tcp::endpoint Endpoint;
      60             :     typedef boost::function<void(TcpSession *, Event)> EventObserver;
      61             :     typedef boost::asio::const_buffer Buffer;
      62             : 
      63             :     // TcpSession constructor takes ownership of socket.
      64             :     TcpSession(TcpServer *server, Socket *socket,
      65             :                bool async_read_ready = true,
      66             :                size_t buffer_send_size = TcpSession::kDefaultWriteBufferSize);
      67             :     // Performs a non-blocking send operation.
      68             :     virtual bool Send(const uint8_t *data, size_t size, size_t *sent);
      69             : 
      70             :     // Called by TcpServer to trigger async read.
      71             :     virtual bool Connected(Endpoint remote);
      72             : 
      73             :     // Called by TcpServer to trigger async read.
      74             :     virtual void Accepted();
      75             : 
      76             :     void ConnectFailed();
      77             : 
      78             :     void Close();
      79             : 
      80      107313 :     virtual std::string ToString() const { return name_; }
      81             : 
      82             :     // Getters and setters
      83      795217 :     virtual Socket *socket() const { return socket_.get(); }
      84             :     NativeSocketType sock_descriptor() { return socket_->native_handle(); }
      85      211025 :     TcpServer *server() { return server_.get(); }
      86             :     int32_t local_port() const;
      87             :     int32_t remote_port() const;
      88             : 
      89             :     // Concurrency: changing the observer guarantees mutual exclusion with
      90             :     // the observer invocation. e.g. if the caller sets the observer to NULL
      91             :     // it is guaranteed that the observer will not get invoked after this
      92             :     // method returns.
      93             :     void set_observer(EventObserver observer);
      94             : 
      95             :     // Buffers must be freed in arrival order.
      96             :     virtual void ReleaseBuffer(Buffer buffer);
      97             : 
      98             :     // This function returns the instance to run SessionTask.
      99             :     // Returning Task::kTaskInstanceAny would allow multiple session tasks to
     100             :     // run in parallel.
     101             :     // Derived class may override implementation if it expects the all the
     102             :     // Tasks of the session to run in specific instance
     103             :     // Note: Two tasks of same task ID and task instance can't run
     104             :     //       at in parallel
     105             :     // E.g. BgpSession is created per BgpPeer and to ensure that
     106             :     //      there is one SessionTask per peer, PeerIndex is returned
     107             :     //      from this function
     108             :     virtual int GetSessionInstance() const;
     109             : 
     110     1524767 :     static const uint8_t *BufferData(const Buffer &buffer) {
     111     1524767 :         return boost::asio::buffer_cast<const uint8_t *>(buffer);
     112             :     }
     113     2626016 :     static size_t BufferSize(const Buffer &buffer) {
     114     2626016 :         return boost::asio::buffer_size(buffer);
     115             :     }
     116             : 
     117     1430665 :     bool IsEstablished() const {
     118     1430665 :         std::scoped_lock lock(mutex_);
     119     1430691 :         return established_;
     120     1430688 :     }
     121             : 
     122        9857 :     bool IsClosed() const {
     123        9857 :         std::scoped_lock lock(mutex_);
     124        9861 :         return closed_;
     125        9862 :     }
     126             : 
     127        2931 :     bool IsServerSession() {
     128        2931 :         if (direction_ == PASSIVE) return true;
     129        1476 :         return false;
     130             :     }
     131             : 
     132     8040612 :     Endpoint remote_endpoint() const {
     133     8040612 :         return remote_;
     134             :     }
     135             : 
     136     1623678 :     const std::string &remote_addr_string() const {
     137     1623678 :         return remote_addr_str_;
     138             :     }
     139             : 
     140             :     Endpoint local_endpoint() const;
     141             : 
     142             :     const boost::system::error_code &close_reason() const {
     143             :         return close_reason_;
     144             :     }
     145             : 
     146             :     virtual boost::system::error_code SetSocketOptions();
     147             :     static bool IsSocketErrorHard(const boost::system::error_code &ec);
     148       13209 :     void set_read_on_connect(bool read) { read_on_connect_ = read; }
     149             :     void SessionEstablished(Endpoint remote, Direction direction);
     150             : 
     151             :     virtual void AsyncReadStart();
     152             :     virtual void SetDeferReader(bool defer_reader);
     153             :     // Is the reader deferred ? If reader is deferred, SetDeferReader needs
     154             :     // to be called to undefer/restart reading.
     155     1275419 :     virtual bool IsReaderDeferred() const {
     156     1275419 :         return defer_reader_;
     157             :     }
     158             : 
     159        1058 :     const io::SocketStats &GetSocketStats() const { return stats_; }
     160             :     void GetRxSocketStats(SocketIOStats *socket_stats) const;
     161             :     void GetTxSocketStats(SocketIOStats *socket_stats) const;
     162             : 
     163           6 :     void GetRxSocketStats(SocketIOStats &socket_stats) const {
     164           6 :         GetRxSocketStats(&socket_stats);
     165           6 :     }
     166             : 
     167           6 :     void GetTxSocketStats(SocketIOStats &socket_stats) const {
     168           6 :         GetTxSocketStats(&socket_stats);
     169           6 :     }
     170             : 
     171             :     int SetMd5SocketOption(uint32_t peer_ip, const std::string &md5_password);
     172             :     int ClearMd5SocketOption(uint32_t peer_ip);
     173             :     int SetDscpSocketOption(uint8_t value);
     174             :     uint8_t GetDscpValue() const;
     175       23232 :     const std::string &ToUVEKey() const { return uve_key_str_; }
     176             :     boost::system::error_code SetTcpNoDelay();
     177             :     boost::system::error_code SetTcpSendBufSize(uint32_t size);
     178             :     boost::system::error_code SetTcpRecvBufSize(uint32_t size);
     179             : 
     180             : protected:
     181             :     typedef boost::intrusive_ptr<TcpSession> TcpSessionPtr;
     182             :     static void AsyncReadHandler(TcpSessionPtr session);
     183             :     static void AsyncWriteHandler(TcpSessionPtr session,
     184             :                                   const boost::system::error_code &error,
     185             :                                   std::size_t bytes_transferred);
     186             : 
     187             :     void AsyncReadStartInternal(TcpSessionPtr session);
     188             :     virtual Task* CreateReaderTask(boost::asio::mutable_buffer, size_t);
     189             : 
     190             :     virtual ~TcpSession();
     191             : 
     192             :     // Read handler. Called from a TBB task.
     193             :     virtual void OnRead(Buffer buffer) = 0;
     194             :     // Callback after socket is ready for write.
     195             :     virtual void WriteReady(const boost::system::error_code &error);
     196             : 
     197             :     void AsyncWriteInternal(TcpSessionPtr session);
     198             : 
     199             :     virtual void AsyncReadSome();
     200             :     virtual size_t GetReadBufferSize() const;
     201             :     virtual size_t ReadSome(boost::asio::mutable_buffer buffer,
     202             :                             boost::system::error_code *error);
     203             :     virtual void AsyncWrite(const uint8_t *data, std::size_t size);
     204             : 
     205     1271553 :     virtual int reader_task_id() const {
     206     1271553 :         return reader_task_id_;
     207             :     }
     208             : 
     209     1187468 :     bool established() const { return established_; }
     210             : 
     211         114 :     EventObserver observer() { return observer_; }
     212             :     boost::system::error_code SetSocketKeepaliveOptions(int keepalive_time,
     213             :             int keepalive_intvl, int keepalive_probes,
     214             :             int tcp_user_timeout_val = 0);
     215             : 
     216             :     void CloseInternal(const boost::system::error_code &ec,
     217             :                        bool call_observer, bool notify_server = true);
     218             : 
     219             :     void TriggerAsyncReadHandler();
     220             : 
     221             :     // Protects session state and buffer queue.
     222             :     mutable std::mutex mutex_;
     223             :     io::SocketStats stats_;
     224             : 
     225             : protected:
     226             :     typedef boost::asio::strand<boost::asio::io_context::executor_type> Strand;
     227             :     boost::scoped_ptr<Strand> io_strand_;
     228             : 
     229             : private:
     230             :     class Reader;
     231             :     friend class TcpServer;
     232             :     friend class TcpMessageWriter;
     233             :     friend void intrusive_ptr_add_ref(TcpSession *session);
     234             :     friend void intrusive_ptr_release(TcpSession *session);
     235             :     typedef std::list<boost::asio::mutable_buffer> BufferQueue;
     236             : 
     237             :     static void WriteReadyInternal(TcpSessionPtr session,
     238             :                                    const boost::system::error_code &error,
     239             :                                    uint64_t block_start_time);
     240             :     void ReleaseBufferLocked(Buffer buffer);
     241             :     void SetEstablished(Endpoint remote, Direction dir);
     242             : 
     243     3369316 :     bool IsClosedLocked() const {
     244     3369316 :         return closed_;
     245             :     }
     246             : 
     247     2096138 :     bool IsEstablishedLocked() const {
     248     2096138 :         return (established_ && !tcp_close_in_progress_);
     249             :     }
     250             : 
     251             :     void SetName();
     252             : 
     253             :     boost::asio::mutable_buffer AllocateBuffer(size_t buffer_size);
     254             :     void DeleteBuffer(boost::asio::mutable_buffer buffer);
     255             : 
     256             :     static int reader_task_id_;
     257             : 
     258             :     TcpServerPtr server_;
     259             :     boost::scoped_ptr<Socket> socket_;
     260             :     bool read_on_connect_;
     261             : 
     262             :     /**************** protected by mutex_ ****************/
     263             :     bool established_;             // In TCP ESTABLISHED state.
     264             :     bool closed_;                  // Close has been called.
     265             :     Endpoint remote_;              // Remote end-point
     266             :     std::string remote_addr_str_;  // Remote end-point address string
     267             :     Direction direction_;          // direction (active, passive)
     268             :     BufferQueue buffer_queue_;
     269             :     boost::system::error_code close_reason_;
     270             :     /**************** end protected by mutex_ ****************/
     271             : 
     272             :     // Protects observer manipulation and invocation. When this lock is
     273             :     // held the session mutex should not be held and vice-versa.
     274             :     std::mutex obs_mutex_;
     275             :     EventObserver observer_;
     276             : 
     277             :     boost::scoped_ptr<TcpMessageWriter> writer_;
     278             : 
     279             :     std::atomic<int> refcount_;
     280             :     std::string name_;
     281             :     std::atomic<bool> defer_reader_;
     282             :     std::string uve_key_str_;
     283             :     std::atomic<bool> write_blocked_;
     284             :     std::atomic<bool> tcp_close_in_progress_;
     285             : 
     286             :     DISALLOW_COPY_AND_ASSIGN(TcpSession);
     287             : };
     288             : 
     289    45113497 : inline void intrusive_ptr_add_ref(TcpSession *session) {
     290    45113497 :     session->refcount_.fetch_add(1);
     291    45113497 : }
     292             : 
     293    45096622 : inline void intrusive_ptr_release(TcpSession *session) {
     294    45096622 :     int prev = session->refcount_.fetch_sub(1);
     295    45096622 :     if (prev == 1) {
     296       28508 :         delete session;
     297             :     }
     298    45096621 : }
     299             : 
     300             : // TcpMessageReader
     301             : //
     302             : // Provides base implementation of OnRead() for TcpSession assuming
     303             : // fixed message header length
     304             : //
     305             : class TcpMessageReader {
     306             : public:
     307             :     typedef boost::asio::const_buffer Buffer;
     308             :     typedef boost::function<bool(const uint8_t *, size_t)> ReceiveCallback;
     309             : 
     310             :     TcpMessageReader(TcpSession *session, ReceiveCallback callback);
     311             :     virtual ~TcpMessageReader();
     312             :     virtual void OnRead(Buffer buffer);
     313             : 
     314             : protected:
     315             :     virtual int MsgLength(Buffer buffer, int offset) = 0;
     316             :     virtual const int GetHeaderLenSize() = 0;
     317             :     virtual const int GetMaxMessageSize() = 0;
     318             : 
     319             : private:
     320             :     typedef std::deque<Buffer> BufferQueue;
     321             : 
     322             :     // Copy the queue into one contiguous buffer.
     323             :     uint8_t *BufferConcat(uint8_t *data, Buffer buffer, int msglength);
     324             : 
     325             :     int QueueByteLength() const;
     326             : 
     327             :     Buffer PullUp(uint8_t *data, Buffer buffer, size_t size) const;
     328             : 
     329             :     int AllocBufferSize(int length);
     330             : 
     331             :     TcpSession *session_;
     332             :     ReceiveCallback callback_;
     333             :     BufferQueue queue_;
     334             :     int offset_;
     335             :     int remain_;
     336             : 
     337             :     DISALLOW_COPY_AND_ASSIGN(TcpMessageReader);
     338             : };
     339             : 
     340             : #endif  // SRC_IO_TCP_SESSION_H_

Generated by: LCOV version 1.14