Branch data Line data Source code
1 : : // Copyright 2026 HPActor Contributors
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #include <hpactor/net/frame.hpp>
16 : :
17 : : #include <hpactor/log/logger.hpp>
18 : :
19 : : #include <arpa/inet.h>
20 : : #include <cstring>
21 : :
22 : : namespace hpactor {
23 : :
24 : : namespace net {
25 : :
26 : 18 : StreamBuffer WireFrame::encode() const {
27 : 18 : std::string serialized = pb_frame.SerializeAsString();
28 : :
29 : 18 : StreamBuffer result;
30 : 18 : result.reserve(HeaderSize + serialized.size());
31 : :
32 : : // Magic "HPAC"
33 : 18 : const std::array<uint8_t, 4> magic = {'H', 'P', 'A', 'C'};
34 : 18 : result.append(magic.data(), 4);
35 : :
36 : : // Remaining length in network byte order
37 : 18 : uint32_t payload_len = static_cast<uint32_t>(serialized.size());
38 : 18 : uint32_t net_len = htonl(payload_len);
39 : 18 : result.append(reinterpret_cast<const uint8_t*>(&net_len), 4);
40 : :
41 : 18 : result.append(reinterpret_cast<const uint8_t*>(serialized.data()),
42 : : serialized.size());
43 : 18 : return result;
44 : 18 : }
45 : :
46 : 6 : WireFrame WireFrame::decode(const StreamBuffer& data) {
47 : 6 : if (data.size() < HeaderSize) {
48 : 1 : return WireFrame{};
49 : : }
50 : :
51 : : // Validate magic header
52 : 5 : const std::array<uint8_t, 4> expected_magic = {'H', 'P', 'A', 'C'};
53 : 5 : if (std::memcmp(data.data(), expected_magic.data(), 4) != 0) {
54 : 0 : HPACTOR_LOG_ERROR(
55 : : log::LogCategory::kNetwork, ActorId{0},
56 : : static_cast<uint32_t>(log::LogEventId::kNetworkFrameDecodeFailed),
57 : : "network frame decode failed");
58 : 0 : return WireFrame{};
59 : : }
60 : :
61 : : // Read remaining length (network byte order)
62 : 5 : uint32_t net_len = 0;
63 : 5 : std::memcpy(&net_len, data.data() + 4, 4);
64 : 5 : uint32_t payload_len = ntohl(net_len);
65 : :
66 : 5 : if (data.size() < HeaderSize + payload_len) {
67 : 0 : return WireFrame{};
68 : : }
69 : :
70 : : // Parse protobuf payload directly into pb_frame
71 : 5 : WireFrame frame;
72 : 5 : std::string serialized(data.begin() + HeaderSize,
73 : 5 : data.begin() + HeaderSize + payload_len);
74 : 5 : if (!frame.pb_frame.ParseFromString(serialized)) {
75 : 0 : HPACTOR_LOG_ERROR(log::LogCategory::kNetwork, ActorId{0}, 0,
76 : : "protobuf parse failure");
77 : 0 : return WireFrame{};
78 : : }
79 : :
80 : 5 : HPACTOR_LOG_TRACE(
81 : : log::LogCategory::kNetwork, ActorId{0},
82 : : static_cast<uint32_t>(log::LogEventId::kNetworkFrameReceived),
83 : : "network frame received",
84 : : log::field("bytes", static_cast<uint64_t>(data.size())),
85 : : log::field("tag", static_cast<uint64_t>(frame.pb_frame.type_tag())));
86 : 5 : return frame;
87 : 5 : }
88 : :
89 : 0 : WireFrame WireFrame::decode(std::span<const uint8_t> data) {
90 : 0 : return decode(StreamBuffer(data.begin(), data.end()));
91 : : }
92 : :
93 : : } // namespace net
94 : : } // namespace hpactor
|