Skip to content

Commit 1ea59e0

Browse files
authored
Added sized overloads for buffer construction of IPv6Address and MacAddress. (#1847)
* Added sized overloads of copyTo and constructor for IPAddress and MacAddress. Deprecated allocating copyTo method. * Updated mac test. * Header fix. * Doc improvement. * Fixed docs. * Fixed docs. * Doc fix. * Deprecated allocating API. Updated non-allocating copyTo API to return written bytes. * Lint * Updated sized MacAddress ctor. Added tests. * Updated raw array to smart ptr array. * Added unit tests for copy to. * Added safety checks on IPv4 and IPv6 buffer constructors. * Fixed test * Added unit tests for IPv6Address::copyTo * Lint * Returned allocating `copyTo` under the name `copyToNewBuffer`. * Simplified tests. * Added unit tests for copyToNewBuffer. * Lint * Typo fix * Moved larger constructors to cpp files. * Removed aliases
1 parent ed08e08 commit 1ea59e0

File tree

5 files changed

+319
-29
lines changed

5 files changed

+319
-29
lines changed

Common++/header/IpAddress.h

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <array>
99
#include <memory>
1010

11+
#include "DeprecationUtils.h"
12+
1113
/// @file
1214

1315
/// @namespace pcpp
@@ -39,10 +41,17 @@ namespace pcpp
3941

4042
/// A constructor that creates an instance of the class out of 4-byte array.
4143
/// @param[in] bytes The address as 4-byte array in network byte order
42-
IPv4Address(const uint8_t bytes[4])
43-
{
44-
memcpy(m_Bytes.data(), bytes, 4 * sizeof(uint8_t));
45-
}
44+
/// @remarks This constructor assumes that the provided array is exactly 4 bytes long.
45+
/// Prefer using the constructor with size parameter if the array length is not guaranteed to be 4 bytes.
46+
IPv4Address(const uint8_t bytes[4]) : IPv4Address(bytes, 4)
47+
{}
48+
49+
/// A constructor that creates an instance of the class out of a 4-byte array.
50+
/// @param[in] bytes The address as 4-byte array in network byte order
51+
/// @param[in] size The size of the array in bytes
52+
/// @throws std::invalid_argument If the provided bytes pointer is null.
53+
/// @throws std::out_of_range If the provided size is smaller than 4 bytes.
54+
IPv4Address(const uint8_t* bytes, size_t size);
4655

4756
/// A constructor that creates an instance of the class out of a 4-byte standard array.
4857
/// @param[in] bytes The address as 4-byte standard array in network byte order
@@ -160,10 +169,17 @@ namespace pcpp
160169

161170
/// A constructor that creates an instance of the class out of 16-byte array.
162171
/// @param[in] bytes The address as 16-byte array in network byte order
163-
IPv6Address(const uint8_t bytes[16])
164-
{
165-
memcpy(m_Bytes.data(), bytes, 16 * sizeof(uint8_t));
166-
}
172+
/// @remarks This constructor assumes that the provided array is exactly 16 bytes long.
173+
/// Prefer using the constructor with size parameter if the array length is not guaranteed to be 16 bytes.
174+
IPv6Address(const uint8_t bytes[16]) : IPv6Address(bytes, 16)
175+
{}
176+
177+
/// @brief A constructor that creates an instance of the class out of a 16-byte array.
178+
/// @param bytes The address as 16-byte array in network byte order
179+
/// @param size The size of the array in bytes
180+
/// @throws std::invalid_argument If the provided buffer is null.
181+
/// @throws std::out_of_range If the provided size is smaller than 16 bytes.
182+
IPv6Address(const uint8_t* bytes, size_t size);
167183

168184
/// A constructor that creates an instance of the class out of a 16-byte standard array.
169185
/// @param[in] bytes The address as 16-byte standard array in network byte order
@@ -224,15 +240,41 @@ namespace pcpp
224240
/// Allocates a byte array and copies address value into it. Array deallocation is user responsibility
225241
/// @param[in] arr A pointer to where array will be allocated
226242
/// @param[out] length Returns the length in bytes of the array that was allocated
243+
/// @throws std::invalid_argument If the provided pointer is null.
244+
/// @deprecated Use copyToNewBuffer instead.
245+
PCPP_DEPRECATED("Use copyToNewBuffer instead.")
227246
void copyTo(uint8_t** arr, size_t& length) const;
228247

229248
/// Gets a pointer to an already allocated byte array and copies the address value to it.
230249
/// This method assumes array allocated size is at least 16 (the size of an IPv6 address)
231250
/// @param[in] arr A pointer to the array which address will be copied to
251+
/// @remarks This method assumes that the provided array is at least 16 bytes long.
252+
/// Prefer using the copyTo(uint8_t* buffer, size_t size) method if the array length is not guaranteed to be 16
253+
/// bytes.
232254
void copyTo(uint8_t* arr) const
233255
{
234-
memcpy(arr, m_Bytes.data(), m_Bytes.size() * sizeof(uint8_t));
235-
}
256+
copyTo(arr, 16);
257+
}
258+
259+
/// @brief Copies the address value to a user-provided buffer.
260+
///
261+
/// This function supports querying. If the buffer is null and size is zero, it returns the required size.
262+
///
263+
/// @param[in] buffer A pointer to the buffer where the address will be copied
264+
/// @param[in] size The size of the buffer in bytes
265+
/// @return The number of bytes copied to the buffer or the number of required bytes, which is always 16 for
266+
/// IPv6 addresses.
267+
/// @throws std::invalid_argument If the provided buffer is null and size is not zero.
268+
size_t copyTo(uint8_t* buffer, size_t size) const;
269+
270+
/// @brief Allocates a new buffer and copies the address value to it.
271+
/// The user is responsible for deallocating the buffer.
272+
///
273+
/// @param buffer A pointer to a pointer where the new buffer will be allocated
274+
/// @param size A reference to a size_t variable that will be updated with the size of the allocated buffer
275+
/// @return True if the buffer was successfully allocated and the address was copied, false otherwise.
276+
/// @throws std::invalid_argument If the buffer pointer is null.
277+
bool copyToNewBuffer(uint8_t** buffer, size_t& size) const;
236278

237279
/// Checks whether the address matches a network.
238280
/// @param network An IPv6Network network

Common++/header/MacAddress.h

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include <cstdint>
88
#include <string>
99
#include <array>
10+
#include <memory>
11+
12+
#include "DeprecationUtils.h"
1013

1114
/// @file
1215

@@ -28,10 +31,17 @@ namespace pcpp
2831
/// The byte array length should be 6 (as MAC address is 6-byte long), and the remaining bytes are ignored.
2932
/// If the byte array is invalid, the constructor throws an exception.
3033
/// @param[in] addr A pointer to the byte array containing 6 bytes representing the MAC address
31-
explicit MacAddress(const uint8_t addr[6])
32-
{
33-
std::copy(addr, addr + 6, m_Address.begin());
34-
}
34+
/// @remarks This constructor assumes that the provided array is exactly 6 bytes long.
35+
/// Prefer using the constructor with size parameter if the array length is not guaranteed to be 6 bytes.
36+
explicit MacAddress(const uint8_t addr[6]) : MacAddress(addr, 6)
37+
{}
38+
39+
/// @brief A constructor that creates an instance of the class out of a byte array of 6 bytes.
40+
/// @param[in] addr The address as a byte array in network byte order
41+
/// @param[in] size The size of the array in bytes
42+
/// @throws std::invalid_argument If the address pointer is null.
43+
/// @throws std::out_of_range If the provided size is smaller than 6 bytes.
44+
explicit MacAddress(const uint8_t* addr, size_t size);
3545

3646
/// A constructor that creates an instance of the class out of a std::array.
3747
/// The array length should be 6 (as MAC address is 6-byte long).
@@ -127,20 +137,45 @@ namespace pcpp
127137
/// Allocates a byte array of length 6 and copies address value into it. Array deallocation is user
128138
/// responsibility
129139
/// @param[in] arr A pointer to where array will be allocated
140+
/// @throws std::invalid_argument If the buffer pointer is null.
141+
/// @deprecated Use copyToNewBuffer instead.
142+
PCPP_DEPRECATED("Use copyToNewBuffer instead.")
130143
void copyTo(uint8_t** arr) const
131144
{
132-
*arr = new uint8_t[m_Address.size()];
133-
std::copy(m_Address.begin(), m_Address.end(), *arr);
145+
size_t unused = 0;
146+
copyToNewBuffer(arr, unused);
134147
}
135148

136149
/// Gets a pointer to an already allocated byte array and copies the address value to it.
137150
/// This method assumes array allocated size is at least 6 (the size of a MAC address)
138151
/// @param[in] arr A pointer to the array which address will be copied to
152+
/// @remarks This method assumes that the provided array is at least 6 bytes long.
153+
/// Prefer using the copyTo(uint8_t* buffer, size_t size) method if the array length is not guaranteed to be 6
154+
/// bytes.
139155
void copyTo(uint8_t arr[6]) const
140156
{
141-
std::copy(m_Address.begin(), m_Address.end(), arr);
157+
copyTo(arr, 6);
142158
}
143159

160+
/// @brief Copies the address value to a user-provided buffer.
161+
///
162+
/// This function supports querying. If the buffer is null and size is zero, it returns the required size.
163+
///
164+
/// @param[in] buffer A pointer to the buffer where the address will be copied
165+
/// @param[in] size The size of the buffer in bytes
166+
/// @return The number of bytes copied to the buffer or the required size if the buffer is too small.
167+
/// @throws std::invalid_argument If the provided buffer is null and size is not zero.
168+
size_t copyTo(uint8_t* buffer, size_t size) const;
169+
170+
/// @brief Allocates a new buffer and copies the address value to it.
171+
/// The user is responsible for deallocating the buffer.
172+
///
173+
/// @param buffer A pointer to a pointer where the new buffer will be allocated
174+
/// @param size A reference to a size_t variable that will be updated with the size of the allocated buffer
175+
/// @return True if the buffer was successfully allocated and the address was copied, false otherwise.
176+
/// @throws std::invalid_argument If the buffer pointer is null.
177+
bool copyToNewBuffer(uint8_t** buffer, size_t& size) const;
178+
144179
/// A static value representing a zero value of MAC address, meaning address of value "00:00:00:00:00:00"
145180
static MacAddress Zero;
146181
/// A static value representing a broadcast MAC address, meaning address of value "ff:ff:ff:ff:ff:ff"

Common++/src/IpAddress.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,20 @@ namespace pcpp
4646
(operator<(MulticastRangeUpperBound) || operator==(MulticastRangeUpperBound));
4747
}
4848

49+
IPv4Address::IPv4Address(const uint8_t* bytes, size_t size)
50+
{
51+
if (bytes == nullptr)
52+
{
53+
throw std::invalid_argument("Buffer pointer is null");
54+
}
55+
56+
if (size < 4)
57+
{
58+
throw std::out_of_range("Buffer size is smaller than IPv4 address size");
59+
}
60+
memcpy(m_Bytes.data(), bytes, 4 * sizeof(uint8_t));
61+
}
62+
4963
IPv4Address::IPv4Address(const std::string& addrAsString)
5064
{
5165
if (inet_pton(AF_INET, addrAsString.data(), m_Bytes.data()) <= 0)
@@ -101,6 +115,20 @@ namespace pcpp
101115
return !operator<(MulticastRangeLowerBound);
102116
}
103117

118+
IPv6Address::IPv6Address(const uint8_t* bytes, size_t size)
119+
{
120+
if (bytes == nullptr)
121+
{
122+
throw std::invalid_argument("Buffer pointer is null");
123+
}
124+
125+
if (size < 16)
126+
{
127+
throw std::out_of_range("Buffer size is smaller than IPv6 address size");
128+
}
129+
std::memcpy(m_Bytes.data(), bytes, 16 * sizeof(uint8_t));
130+
}
131+
104132
IPv6Address::IPv6Address(const std::string& addrAsString)
105133
{
106134
if (inet_pton(AF_INET6, addrAsString.data(), m_Bytes.data()) <= 0)
@@ -117,6 +145,49 @@ namespace pcpp
117145
memcpy(*arr, m_Bytes.data(), addrLen);
118146
}
119147

148+
size_t IPv6Address::copyTo(uint8_t* buffer, size_t size) const
149+
{
150+
const size_t requiredSize = m_Bytes.size();
151+
152+
if (buffer == nullptr)
153+
{
154+
if (size != 0)
155+
{
156+
throw std::invalid_argument("Buffer is null but size is not zero");
157+
}
158+
159+
return requiredSize;
160+
}
161+
162+
if (size < requiredSize)
163+
{
164+
return requiredSize;
165+
}
166+
167+
std::memcpy(buffer, m_Bytes.data(), requiredSize);
168+
return requiredSize;
169+
}
170+
171+
bool IPv6Address::copyToNewBuffer(uint8_t** buffer, size_t& size) const
172+
{
173+
if (buffer == nullptr)
174+
{
175+
throw std::invalid_argument("Buffer pointer is null");
176+
}
177+
178+
size = copyTo(nullptr, 0);
179+
*buffer = new uint8_t[size];
180+
if (copyTo(*buffer, size) != size)
181+
{
182+
delete[] *buffer;
183+
*buffer = nullptr;
184+
size = 0;
185+
return false;
186+
}
187+
188+
return true;
189+
}
190+
120191
bool IPv6Address::matchNetwork(const IPv6Network& network) const
121192
{
122193
return network.includes(*this);

Common++/src/MacAddress.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ namespace pcpp
1818
return str;
1919
}
2020

21+
MacAddress::MacAddress(const uint8_t* addr, size_t size)
22+
{
23+
if (addr == nullptr)
24+
{
25+
throw std::invalid_argument("Address pointer is null");
26+
}
27+
28+
if (size < 6)
29+
{
30+
throw std::out_of_range("Buffer size is smaller than MAC address size (6 bytes)");
31+
}
32+
33+
std::copy(addr, addr + 6, m_Address.begin());
34+
}
35+
2136
MacAddress::MacAddress(const std::string& address)
2237
{
2338
constexpr size_t validMacAddressLength = 17;
@@ -35,4 +50,42 @@ namespace pcpp
3550
}
3651
}
3752

53+
size_t MacAddress::copyTo(uint8_t* buffer, size_t size) const
54+
{
55+
const size_t requiredSize = m_Address.size();
56+
if (buffer == nullptr)
57+
{
58+
if (size != 0)
59+
{
60+
throw std::invalid_argument("Buffer is null but size is not zero");
61+
}
62+
return requiredSize;
63+
}
64+
if (size < m_Address.size())
65+
{
66+
return requiredSize;
67+
}
68+
std::copy(m_Address.begin(), m_Address.end(), buffer);
69+
return requiredSize;
70+
}
71+
72+
bool MacAddress::copyToNewBuffer(uint8_t** buffer, size_t& size) const
73+
{
74+
if (buffer == nullptr)
75+
{
76+
throw std::invalid_argument("Buffer pointer is null");
77+
}
78+
79+
size = copyTo(nullptr, 0); // Get the required size
80+
*buffer = new uint8_t[size]; // Allocate memory for the buffer
81+
if (copyTo(*buffer, size) != size) // Copy the address to the newly allocated buffer
82+
{
83+
delete[] *buffer; // Clean up if copy fails
84+
*buffer = nullptr;
85+
size = 0;
86+
return false;
87+
}
88+
89+
return true;
90+
}
3891
} // namespace pcpp

0 commit comments

Comments
 (0)