Line data Source code
1 : /**
2 : * @file fix_frame_decoder.cpp
3 : * @brief FixFrameDecoder 类实现
4 : */
5 :
6 : #include "fix/fix_frame_decoder.hpp"
7 : #include "base/config.hpp"
8 : #include <stdexcept>
9 : #include <iostream>
10 :
11 : namespace fix40 {
12 :
13 15 : FixFrameDecoder::FixFrameDecoder(size_t max_buffer_size, size_t max_body_length)
14 15 : : max_buffer_size_(max_buffer_size), max_body_length_(max_body_length) {}
15 :
16 8 : bool FixFrameDecoder::can_append(size_t len) const {
17 8 : if (buffer_.size() >= max_buffer_size_) return false;
18 7 : if (len > max_buffer_size_ - buffer_.size()) return false;
19 4 : return true;
20 : }
21 :
22 41 : void FixFrameDecoder::append(const char* data, size_t len) {
23 : // 安全的溢出防护:使用减法代替加法
24 : // 当 buffer_.size() + len 可能超过 SIZE_MAX 时,这可以防止整数溢出
25 41 : if (buffer_.size() >= max_buffer_size_ || len > max_buffer_size_ - buffer_.size()) {
26 : // 让上层 Connection 或 Session 来决定如何处理这个错误
27 1 : throw std::runtime_error("Buffer size limit exceeded. Closing connection.");
28 : }
29 40 : buffer_.append(data, len);
30 40 : }
31 :
32 15 : bool FixFrameDecoder::next_message(std::string& message) {
33 15 : if (buffer_.empty()) {
34 3 : return false;
35 : }
36 :
37 : // --- FIX 消息分架逻辑 ---
38 12 : const auto begin_string_pos = buffer_.find("8=FIX.4.0\x01");
39 12 : if (begin_string_pos == std::string::npos) {
40 : // 未找到有效的开头。为了防止缓冲增长,直接清空
41 : // 更健壮的实现也许会有不同策略
42 1 : buffer_.clear();
43 1 : return false;
44 : }
45 11 : if (begin_string_pos > 0) {
46 : // 丢弃消息开头前的无用数据
47 1 : buffer_.erase(0, begin_string_pos);
48 : }
49 :
50 11 : const auto body_length_tag_pos = buffer_.find("\x01""9=");
51 11 : if (body_length_tag_pos == std::string::npos) return false; // 未得到 BodyLength 标签所需的数据
52 :
53 11 : const auto body_length_val_pos = body_length_tag_pos + 3;
54 11 : const auto body_length_end_pos = buffer_.find('\x01', body_length_val_pos);
55 11 : if (body_length_end_pos == std::string::npos) return false; // BodyLength 值数据不足
56 :
57 11 : int body_length = 0;
58 : try {
59 11 : const std::string body_length_str = buffer_.substr(body_length_val_pos, body_length_end_pos - body_length_val_pos);
60 11 : body_length = std::stoi(body_length_str);
61 10 : if (body_length < 0 || static_cast<size_t>(body_length) > max_body_length_) { // 基本有效性检查
62 2 : throw std::runtime_error("Invalid BodyLength value");
63 : }
64 14 : } catch (const std::exception&) {
65 : // 如果 BodyLength 无效,这是一个严重的协议错误,我们应该丢弃缓冲区的数据以避免死循环
66 3 : buffer_.clear();
67 : // 也许应该向上层报告这个错误
68 3 : throw;
69 3 : }
70 :
71 : // 计算总的预期消息长度
72 8 : const size_t soh_after_body_length_pos = body_length_end_pos + 1;
73 8 : const size_t total_msg_len = soh_after_body_length_pos + body_length + 7; // "10=NNN\x01" 为 7 个字符
74 :
75 8 : if (buffer_.size() < total_msg_len) {
76 : // 数据不足以形成完整消息
77 2 : return false;
78 : }
79 :
80 : // 已经抽出一个完整消息
81 6 : message = buffer_.substr(0, total_msg_len);
82 :
83 : // 从缓冲中移除已处理的消息
84 6 : buffer_.erase(0, total_msg_len);
85 :
86 6 : return true;
87 : }
88 :
89 : } // namespace fix40
|