LCOV - code coverage report
Current view: top level - wirestead/framer - length_prefix_framer.cc (source / functions) Coverage Total Hit
Test: Wirestead Coverage Report Lines: 100.0 % 46 46
Test Date: 2026-08-30 10:35:09 Functions: 100.0 % 5 5
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 93.3 % 30 28

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright 2025 Jinwoo Sung
       3                 :             :  *
       4                 :             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :             :  * you may not use this file except in compliance with the License.
       6                 :             :  * You may obtain a copy of the License at
       7                 :             :  *
       8                 :             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :             :  *
      10                 :             :  * Unless required by applicable law or agreed to in writing, software
      11                 :             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :             :  * See the License for the specific language governing permissions and
      14                 :             :  * limitations under the License.
      15                 :             :  */
      16                 :             : 
      17                 :             : #include "wirestead/framer/length_prefix_framer.hpp"
      18                 :             : 
      19                 :             : #include <stdexcept>
      20                 :             : #include <utility>
      21                 :             : 
      22                 :             : #include "wirestead/diagnostics/logger.hpp"
      23                 :             : 
      24                 :             : namespace wirestead {
      25                 :             : namespace framer {
      26                 :             : 
      27                 :          16 : LengthPrefixFramer::LengthPrefixFramer(size_t prefix_bytes, Endian endian, size_t max_length,
      28                 :          16 :                                        bool length_includes_prefix)
      29                 :          16 :     : prefix_bytes_(prefix_bytes),
      30                 :          16 :       endian_(endian),
      31                 :          16 :       max_length_(max_length),
      32                 :          16 :       length_includes_prefix_(length_includes_prefix) {
      33   [ +  +  +  +  :          16 :   if (prefix_bytes != 1 && prefix_bytes != 2 && prefix_bytes != 4) {
                   +  + ]
      34                 :           2 :     throw std::invalid_argument("LengthPrefixFramer: prefix_bytes must be 1, 2 or 4");
      35                 :             :   }
      36         [ +  + ]:          14 :   if (max_length == 0) {
      37                 :           1 :     throw std::invalid_argument("LengthPrefixFramer: max_length must be greater than 0");
      38                 :             :   }
      39                 :          22 : }
      40                 :             : 
      41                 :          26 : bool LengthPrefixFramer::read_length(size_t offset, size_t& out) const {
      42         [ +  + ]:          26 :   if (buffer_.size() - offset < prefix_bytes_) return false;
      43                 :             : 
      44                 :          16 :   uint64_t value = 0;
      45         [ +  + ]:          54 :   for (size_t i = 0; i < prefix_bytes_; ++i) {
      46         [ +  + ]:          38 :     const size_t idx = endian_ == Endian::Big ? offset + i : offset + (prefix_bytes_ - 1 - i);
      47                 :          38 :     value = (value << 8) | buffer_[idx];
      48                 :             :   }
      49                 :          16 :   out = static_cast<size_t>(value);
      50                 :          16 :   return true;
      51                 :             : }
      52                 :             : 
      53                 :          15 : void LengthPrefixFramer::push_bytes(memory::ConstByteSpan data) {
      54         [ +  - ]:          15 :   if (!data.empty()) {
      55                 :          15 :     buffer_.insert(buffer_.end(), data.data(), data.data() + data.size());
      56                 :             :   }
      57                 :             : 
      58                 :          15 :   size_t consumed = 0;
      59                 :             :   while (true) {
      60                 :          26 :     size_t declared = 0;
      61         [ +  + ]:          26 :     if (!read_length(consumed, declared)) break;
      62                 :             : 
      63                 :             :     // Both conventions exist for what the length counts. A frame claiming to
      64                 :             :     // be shorter than its own header cannot be either, so it is corruption.
      65                 :          16 :     size_t payload_len = declared;
      66         [ +  + ]:          16 :     if (length_includes_prefix_) {
      67         [ +  + ]:           2 :       if (declared < prefix_bytes_) {
      68                 :           1 :         WIRESTEAD_LOG_WARNING("framer", "length_prefix",
      69                 :             :                               "Declared length is shorter than the prefix itself; resynchronising");
      70                 :           1 :         reset();
      71                 :           2 :         return;
      72                 :             :       }
      73                 :           1 :       payload_len = declared - prefix_bytes_;
      74                 :             :     }
      75                 :             : 
      76         [ +  + ]:          15 :     if (payload_len > max_length_) {
      77                 :             :       // Never allocate what a bad or hostile header asked for. Without a sync
      78                 :             :       // word there is nothing to hunt for, so the only honest recovery is to
      79                 :             :       // drop what we have and start over.
      80                 :           1 :       WIRESTEAD_LOG_WARNING("framer", "length_prefix",
      81                 :             :                             "Declared payload length exceeds max_length; dropping the buffer");
      82                 :           1 :       reset();
      83                 :           1 :       return;
      84                 :             :     }
      85                 :             : 
      86                 :          14 :     const size_t frame_end = consumed + prefix_bytes_ + payload_len;
      87         [ +  + ]:          14 :     if (buffer_.size() < frame_end) break;  // wait for the rest of the payload
      88                 :             : 
      89         [ +  - ]:          11 :     if (on_message_) {
      90                 :          11 :       on_message_(memory::ConstByteSpan(buffer_.data() + consumed + prefix_bytes_, payload_len));
      91                 :             :     }
      92                 :          11 :     consumed = frame_end;
      93                 :          11 :   }
      94                 :             : 
      95         [ +  + ]:          13 :   if (consumed > 0) {
      96                 :           9 :     buffer_.erase(buffer_.begin(), buffer_.begin() + static_cast<std::ptrdiff_t>(consumed));
      97                 :             :   }
      98                 :             : }
      99                 :             : 
     100                 :          11 : void LengthPrefixFramer::on_message(MessageCallback cb) { on_message_ = std::move(cb); }
     101                 :             : 
     102                 :           3 : void LengthPrefixFramer::reset() { buffer_.clear(); }
     103                 :             : 
     104                 :             : }  // namespace framer
     105                 :             : }  // namespace wirestead
        

Generated by: LCOV version 2.0-1