GCC Code Coverage Report


Directory: ./
File: lib/packetmanager/src/packetManager.cpp
Date: 2025-09-29 13:19:55
Exec Total Coverage
Lines: 127 148 85.8%
Functions: 13 14 92.9%
Branches: 84 154 54.5%

Line Branch Exec Source
1 /*
2 ** EPITECH PROJECT, 2025
3 ** rtype
4 ** File description:
5 ** TODO: add description
6 */
7
8 #include "packetmanager.h"
9 #include <cstring>
10 #include <memory>
11 #include <stdexcept>
12 #include <algorithm>
13
14 27 PacketManager::PacketManager() : _send_seqid(0), _recv_seqid(0) {
15 27 }
16
17 // Add destructor to clean up memory
18 27 PacketManager::~PacketManager() {
19 27 clean();
20 27 }
21
22 19 packet_t PacketManager::deserializePacket(const uint8_t *data, size_t size, packet_t &packet) {
23
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17 times.
19 if (size < sizeof(packet_header_t)) {
24
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 throw std::runtime_error("Data size is smaller than packet header size");
25 }
26 17 std::memcpy(&packet.header, data, sizeof(packet_header_t));
27
28 // Validate that the data_size field matches the actual data received
29 17 size_t expected_total_size = sizeof(packet_header_t) + packet.header.data_size;
30
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (size != expected_total_size) {
31
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 throw std::runtime_error("Packet size mismatch: expected " + std::to_string(expected_total_size) +
32
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
3 ", got " + std::to_string(size));
33 }
34
35
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
16 if (packet.header.data_size > 0) {
36 15 packet.data = new uint8_t[packet.header.data_size];
37 15 std::memcpy(packet.data, data + sizeof(packet_header_t), packet.header.data_size);
38 } else {
39 1 packet.data = nullptr;
40 }
41 16 return packet;
42 }
43
44 54 std::vector<uint8_t> PacketManager::serializePacket(const packet_t &packet) {
45
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 std::vector<uint8_t> buffer(sizeof(packet_header_t) + packet.header.data_size);
46 54 std::memcpy(buffer.data(), &packet.header, sizeof(packet_header_t));
47
3/4
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
54 if (packet.header.data_size > 0 && packet.data) {
48 52 std::memcpy(buffer.data() + sizeof(packet_header_t), packet.data, packet.header.data_size);
49 }
50 54 return buffer;
51 }
52
53
54 19 void PacketManager::handlePacketBytes(const uint8_t *data, size_t size) {
55 try {
56 // Deserialize the packet and store it in unique_ptr<packet_t>
57
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 std::unique_ptr<packet_t> packet = std::make_unique<packet_t>();
58
2/2
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 3 times.
19 deserializePacket(data, size, *packet);
59
1/2
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
16 _handlePacket(std::move(packet));
60
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
22 } catch (const std::exception &e) {
61 // Invalid packet, ignore it
62 3 return;
63 3 }
64 }
65 //
66
67 // Add safer version of sendPacketBytes that returns smart pointer
68 38 std::unique_ptr<uint8_t[]> PacketManager::sendPacketBytesSafe(const void *data, size_t data_size, uint8_t packet_type,
69 size_t *output_size, bool important) {
70 packet_header_t header;
71
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 std::unique_ptr<packet_t> packet = std::make_unique<packet_t>();
72
73
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 header.seqid = important ? ++_send_seqid : 0;
74 38 header.ack = 0;
75 38 header.type = packet_type;
76 38 header.auth = _auth_key;
77 38 header.data_size = data_size;
78
79 38 packet->header = header;
80 // Make a copy of the input data for the packet
81
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1 times.
38 if (data_size > 0) {
82
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 packet->data = new uint8_t[data_size];
83 37 std::memcpy(packet->data, data, data_size);
84 } else {
85 1 packet->data = nullptr;
86 }
87
88 // Serialize the packet
89
1/2
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
38 std::vector<uint8_t> serialized_packet = serializePacket(*packet);
90
91 // Create smart pointer for output data
92
1/2
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
38 auto output_data = std::make_unique<uint8_t[]>(serialized_packet.size());
93 38 std::memcpy(output_data.get(), serialized_packet.data(), serialized_packet.size());
94 38 *output_size = serialized_packet.size();
95
96 // Store the packet in the send buffer
97
1/2
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
38 _buffer_send.push_back(std::move(packet));
98
99 76 return output_data;
100 38 }
101
102 // Add safer deserialize function using smart pointers
103 std::unique_ptr<packet_t> PacketManager::deserializePacketSafe(const uint8_t *data, size_t size) {
104 auto packet = std::make_unique<packet_t>();
105
106 if (size < sizeof(packet_header_t)) {
107 throw std::runtime_error("Data size is smaller than packet header size");
108 }
109 std::memcpy(&packet->header, data, sizeof(packet_header_t));
110
111 // Validate that the data_size field matches the actual data received
112 size_t expected_total_size = sizeof(packet_header_t) + packet->header.data_size;
113 if (size != expected_total_size) {
114 throw std::runtime_error("Packet size mismatch: expected " + std::to_string(expected_total_size) +
115 ", got " + std::to_string(size));
116 }
117
118 if (packet->header.data_size > 0) {
119 packet->data = new uint8_t[packet->header.data_size];
120 std::memcpy(packet->data, data + sizeof(packet_header_t), packet->header.data_size);
121 } else {
122 packet->data = nullptr;
123 }
124 return packet;
125 }
126
127 28 void PacketManager::clean() {
128 // Clean up history data before clearing
129
2/2
✓ Branch 5 taken 38 times.
✓ Branch 6 taken 28 times.
66 for (auto &packet: _history_sent) {
130
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1 times.
38 if (packet.data) {
131
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 delete[] static_cast<uint8_t *>(packet.data);
132 37 packet.data = nullptr;
133 }
134 }
135
136 // Clean up received buffer data
137
2/2
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 28 times.
32 for (auto &packet: _buffer_received) {
138
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
4 if (packet && packet->data) {
139
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 delete[] static_cast<uint8_t *>(packet->data);
140 4 packet->data = nullptr;
141 }
142 }
143
144 // Clean up send buffer data
145
2/2
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 28 times.
32 for (auto &packet: _buffer_send) {
146
5/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 3 times.
4 if (packet && packet->data) {
147
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 delete[] static_cast<uint8_t *>(packet->data);
148 1 packet->data = nullptr;
149 }
150 }
151
152 28 _history_sent.clear();
153 28 _missed_packets.clear();
154 28 _buffer_received.clear();
155 28 _buffer_send.clear();
156 28 _send_seqid = 0;
157 28 _recv_seqid = 0;
158 28 }
159
160 11 void PacketManager::ackMissing() {
161 packet_header_t header;
162 packet_t packet;
163 11 header.seqid = 0;
164 11 header.type = 0;
165 11 header.auth = _auth_key;
166 11 header.ack = 0;
167 11 header.data_size = 0; // ACK packets have no data payload
168
169
2/2
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 11 times.
19 for (auto seqid: _missed_packets) {
170 8 header.ack = seqid;
171 8 packet.header = header;
172 8 packet.data = nullptr;
173
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 _buffer_send.push_back(std::make_unique<packet_t>(packet));
174 }
175 11 _missed_packets.clear();
176 11 }
177
178
179 1 bool PacketManager::_resendPacket(uint32_t seqid) {
180
1/2
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 for (const packet_t &packet: _history_sent) {
181
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (packet.header.seqid == seqid) {
182 // Create a proper deep copy of the packet for retransmission
183
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::unique_ptr<packet_t> retrans_packet = std::make_unique<packet_t>();
184 1 retrans_packet->header = packet.header;
185
186 // Deep copy the data if it exists
187
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (packet.header.data_size > 0 && packet.data) {
188
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 retrans_packet->data = new uint8_t[packet.header.data_size];
189 1 std::memcpy(retrans_packet->data, packet.data, packet.header.data_size);
190 } else {
191 retrans_packet->data = nullptr;
192 }
193
194
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 _buffer_send.push_back(std::move(retrans_packet));
195 1 return true;
196 1 }
197 }
198 return false;
199 }
200
201
202 16 void PacketManager::_handlePacket(std::unique_ptr<packet_t> packet) {
203 // Check if this is an ACK packet, handle it separately
204
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 15 times.
16 if (packet->header.ack != 0) {
205 1 _resendPacket(packet->header.ack);
206 1 return;
207 }
208
209 // If this is a missed packet, remove it from the missed list
210
2/4
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
15 _missed_packets.erase(std::remove(_missed_packets.begin(), _missed_packets.end(), packet->header.seqid),
211 15 _missed_packets.end());
212
213 // Update highest received sequence ID and detect missing packets
214
5/6
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 4 times.
15 if (packet->header.seqid != 0 && packet->header.seqid > _recv_seqid) {
215 // Declare as missed all packets between last received and this one
216
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 11 times.
19 for (uint32_t i = _recv_seqid + 1; i < packet->header.seqid; i++) {
217
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 _missed_packets.push_back(i);
218 }
219 11 _recv_seqid = packet->header.seqid;
220
221 // Acknowledge all missed packets
222 11 ackMissing();
223 }
224
225 // Always store the packet in the received buffer (allows duplicates and out-of-order)
226 15 _buffer_received.push_back(std::move(packet));
227
228 // Sort the received buffer by seqid
229 15 std::sort(_buffer_received.begin(), _buffer_received.end(),
230 17 [](const std::unique_ptr<packet_t> &a, const std::unique_ptr<packet_t> &b) {
231 17 return a->header.seqid < b->header.seqid;
232 });
233 }
234
235 6 std::vector<std::unique_ptr<packet_t> > PacketManager::fetchReceivedPackets() {
236 6 std::vector<std::unique_ptr<packet_t> > tmp = std::move(_buffer_received);
237 6 _buffer_received.clear();
238 6 return tmp;
239 }
240
241 23 std::vector<std::unique_ptr<packet_t> > PacketManager::fetchPacketsToSend() {
242 23 std::vector<std::unique_ptr<packet_t> > tmp = std::move(_buffer_send);
243 23 _buffer_send.clear();
244
245 // Fill the packets history
246
2/2
✓ Branch 5 taken 43 times.
✓ Branch 6 taken 23 times.
66 for (auto &packet: tmp) {
247
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
43 if (_history_sent.size() >= PACKET_HISTORY_SIZE) {
248 // Properly clean up the oldest packet before removing it
249 if (_history_sent.front().data) {
250 delete[] static_cast<uint8_t *>(_history_sent.front().data);
251 }
252 _history_sent.erase(_history_sent.begin());
253 }
254 // Skip if not important
255
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 38 times.
43 if (packet->header.seqid == 0)
256 5 continue;
257 // Create a copy of the packet to store in history
258 packet_t packet_copy;
259 38 packet_copy.header = packet->header;
260
261 // Now we can properly copy the data using the data_size from header
262
5/6
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
✓ Branch 7 taken 1 times.
38 if (packet->header.data_size > 0 && packet->data) {
263
1/2
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
37 packet_copy.data = new uint8_t[packet->header.data_size];
264 37 std::memcpy(packet_copy.data, packet->data, packet->header.data_size);
265 } else {
266 1 packet_copy.data = nullptr;
267 }
268
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 _history_sent.push_back(packet_copy);
269 }
270 23 return tmp;
271 }
272