Skip to content

Commit ea43b1e

Browse files
Virensfpistm
Virens
andcommitted
chore: update IPAdress class vs Arduino Core API
Fixes #2303 Signed-off-by: Virens <[email protected]> Co-Authored-By: Frederic Pillon <[email protected]>
1 parent f91e64f commit ea43b1e

File tree

2 files changed

+344
-43
lines changed

2 files changed

+344
-43
lines changed

Diff for: cores/arduino/IPAddress.cpp

+284-22
Original file line numberDiff line numberDiff line change
@@ -17,54 +17,144 @@
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1818
*/
1919

20-
#include <Arduino.h>
21-
#include <IPAddress.h>
20+
#include "IPAddress.h"
21+
#include "Print.h"
2222

23-
IPAddress::IPAddress()
23+
IPAddress::IPAddress() : IPAddress(IPv4) {}
24+
25+
IPAddress::IPAddress(IPType ip_type)
2426
{
25-
_address.dword = 0;
27+
_type = ip_type;
28+
memset(_address.bytes, 0, sizeof(_address.bytes));
2629
}
2730

2831
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
2932
{
30-
_address.bytes[0] = first_octet;
31-
_address.bytes[1] = second_octet;
32-
_address.bytes[2] = third_octet;
33-
_address.bytes[3] = fourth_octet;
33+
_type = IPv4;
34+
memset(_address.bytes, 0, sizeof(_address.bytes));
35+
_address.bytes[IPADDRESS_V4_BYTES_INDEX] = first_octet;
36+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 1] = second_octet;
37+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 2] = third_octet;
38+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = fourth_octet;
39+
}
40+
41+
IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16)
42+
{
43+
_type = IPv6;
44+
_address.bytes[0] = o1;
45+
_address.bytes[1] = o2;
46+
_address.bytes[2] = o3;
47+
_address.bytes[3] = o4;
48+
_address.bytes[4] = o5;
49+
_address.bytes[5] = o6;
50+
_address.bytes[6] = o7;
51+
_address.bytes[7] = o8;
52+
_address.bytes[8] = o9;
53+
_address.bytes[9] = o10;
54+
_address.bytes[10] = o11;
55+
_address.bytes[11] = o12;
56+
_address.bytes[12] = o13;
57+
_address.bytes[13] = o14;
58+
_address.bytes[14] = o15;
59+
_address.bytes[15] = o16;
3460
}
3561

3662
IPAddress::IPAddress(uint32_t address)
3763
{
38-
_address.dword = address;
64+
// IPv4 only
65+
_type = IPv4;
66+
memset(_address.bytes, 0, sizeof(_address.bytes));
67+
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
68+
69+
// NOTE on conversion/comparison and uint32_t:
70+
// These conversions are host platform dependent.
71+
// There is a defined integer representation of IPv4 addresses,
72+
// based on network byte order (will be the value on big endian systems),
73+
// e.g. http://2398766798 is the same as http://142.250.70.206,
74+
// However on little endian systems the octets 0x83, 0xFA, 0x46, 0xCE,
75+
// in that order, will form the integer (uint32_t) 3460758158 .
76+
}
77+
78+
IPAddress::IPAddress(const uint8_t *address) : IPAddress(IPv4, address) {}
79+
80+
IPAddress::IPAddress(IPType ip_type, const uint8_t *address)
81+
{
82+
_type = ip_type;
83+
if (ip_type == IPv4) {
84+
memset(_address.bytes, 0, sizeof(_address.bytes));
85+
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
86+
} else {
87+
memcpy(_address.bytes, address, sizeof(_address.bytes));
88+
}
89+
}
90+
91+
IPAddress::IPAddress(const char *address)
92+
{
93+
fromString(address);
94+
}
95+
96+
String IPAddress::toString4() const
97+
{
98+
char szRet[16];
99+
snprintf(szRet, sizeof(szRet), "%u.%u.%u.%u", _address.bytes[IPADDRESS_V4_BYTES_INDEX], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 1], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 2], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 3]);
100+
return String(szRet);
39101
}
40102

41-
IPAddress::IPAddress(const uint8_t *address)
103+
String IPAddress::toString6() const
42104
{
43-
memcpy(_address.bytes, address, sizeof(_address.bytes));
105+
char szRet[40];
106+
snprintf(szRet, sizeof(szRet), "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
107+
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
108+
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
109+
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
110+
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
111+
return String(szRet);
112+
}
113+
114+
String IPAddress::toString() const
115+
{
116+
if (_type == IPv4) {
117+
return toString4();
118+
} else {
119+
return toString6();
120+
}
44121
}
45122

46123
bool IPAddress::fromString(const char *address)
124+
{
125+
if (!fromString4(address)) {
126+
return fromString6(address);
127+
}
128+
return true;
129+
}
130+
131+
bool IPAddress::fromString4(const char *address)
47132
{
48133
// TODO: add support for "a", "a.b", "a.b.c" formats
49134

50-
uint16_t acc = 0; // Accumulator
135+
int16_t acc = -1; // Accumulator
51136
uint8_t dots = 0;
52137

138+
memset(_address.bytes, 0, sizeof(_address.bytes));
53139
while (*address) {
54140
char c = *address++;
55141
if (c >= '0' && c <= '9') {
56-
acc = acc * 10 + (c - '0');
142+
acc = (acc < 0) ? (c - '0') : acc * 10 + (c - '0');
57143
if (acc > 255) {
58144
// Value out of [0..255] range
59145
return false;
60146
}
61147
} else if (c == '.') {
62148
if (dots == 3) {
63-
// Too much dots (there must be 3 dots)
149+
// Too many dots (there must be 3 dots)
64150
return false;
65151
}
66-
_address.bytes[dots++] = acc;
67-
acc = 0;
152+
if (acc < 0) {
153+
/* No value between dots, e.g. '1..' */
154+
return false;
155+
}
156+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + dots++] = acc;
157+
acc = -1;
68158
} else {
69159
// Invalid char
70160
return false;
@@ -75,35 +165,207 @@ bool IPAddress::fromString(const char *address)
75165
// Too few dots (there must be 3 dots)
76166
return false;
77167
}
78-
_address.bytes[3] = acc;
168+
if (acc < 0) {
169+
/* No value between dots, e.g. '1..' */
170+
return false;
171+
}
172+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = acc;
173+
_type = IPv4;
174+
return true;
175+
}
176+
177+
bool IPAddress::fromString6(const char *address)
178+
{
179+
uint32_t acc = 0; // Accumulator
180+
int colons = 0, double_colons = -1;
181+
182+
while (*address) {
183+
char c = tolower(*address++);
184+
if (isalnum(c) && c <= 'f') {
185+
if (c >= 'a') {
186+
c -= 'a' - '0' - 10;
187+
}
188+
acc = acc * 16 + (c - '0');
189+
if (acc > 0xffff)
190+
// Value out of range
191+
{
192+
return false;
193+
}
194+
} else if (c == ':') {
195+
if (*address == ':') {
196+
if (double_colons >= 0) {
197+
// :: allowed once
198+
return false;
199+
}
200+
if (*address != '\0' && *(address + 1) == ':') {
201+
// ::: not allowed
202+
return false;
203+
}
204+
// remember location
205+
double_colons = colons + !!acc;
206+
address++;
207+
} else if (*address == '\0') {
208+
// can't end with a single colon
209+
return false;
210+
}
211+
if (colons == 7)
212+
// too many separators
213+
{
214+
return false;
215+
}
216+
_address.bytes[colons * 2] = acc >> 8;
217+
_address.bytes[colons * 2 + 1] = acc & 0xff;
218+
colons++;
219+
acc = 0;
220+
} else
221+
// Invalid char
222+
{
223+
return false;
224+
}
225+
}
226+
227+
if (double_colons == -1 && colons != 7) {
228+
// Too few separators
229+
return false;
230+
}
231+
if (double_colons > -1 && colons > 6) {
232+
// Too many segments (double colon must be at least one zero field)
233+
return false;
234+
}
235+
_address.bytes[colons * 2] = acc >> 8;
236+
_address.bytes[colons * 2 + 1] = acc & 0xff;
237+
colons++;
238+
239+
if (double_colons != -1) {
240+
for (int i = colons * 2 - double_colons * 2 - 1; i >= 0; i--) {
241+
_address.bytes[16 - colons * 2 + double_colons * 2 + i] = _address.bytes[double_colons * 2 + i];
242+
}
243+
for (int i = double_colons * 2; i < 16 - colons * 2 + double_colons * 2; i++) {
244+
_address.bytes[i] = 0;
245+
}
246+
}
247+
248+
_type = IPv6;
79249
return true;
80250
}
81251

82252
IPAddress &IPAddress::operator=(const uint8_t *address)
83253
{
84-
memcpy(_address.bytes, address, sizeof(_address.bytes));
254+
// IPv4 only conversion from byte pointer
255+
_type = IPv4;
256+
memset(_address.bytes, 0, sizeof(_address.bytes));
257+
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
258+
return *this;
259+
}
260+
261+
IPAddress &IPAddress::operator=(const char *address)
262+
{
263+
fromString(address);
85264
return *this;
86265
}
87266

88267
IPAddress &IPAddress::operator=(uint32_t address)
89268
{
90-
_address.dword = address;
269+
// IPv4 conversion
270+
// See note on conversion/comparison and uint32_t
271+
_type = IPv4;
272+
memset(_address.bytes, 0, sizeof(_address.bytes));
273+
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
91274
return *this;
92275
}
93276

277+
bool IPAddress::operator==(const IPAddress &addr) const
278+
{
279+
return (addr._type == _type)
280+
&& (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0);
281+
}
282+
94283
bool IPAddress::operator==(const uint8_t *addr) const
95284
{
96-
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
285+
// IPv4 only comparison to byte pointer
286+
// Can't support IPv6 as we know our type, but not the length of the pointer
287+
return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0;
288+
}
289+
290+
uint8_t IPAddress::operator[](int index) const
291+
{
292+
if (_type == IPv4) {
293+
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
294+
}
295+
return _address.bytes[index];
296+
}
297+
298+
uint8_t &IPAddress::operator[](int index)
299+
{
300+
if (_type == IPv4) {
301+
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
302+
}
303+
return _address.bytes[index];
97304
}
98305

99306
size_t IPAddress::printTo(Print &p) const
100307
{
101308
size_t n = 0;
309+
310+
if (_type == IPv6) {
311+
// IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case
312+
int8_t longest_start = -1;
313+
int8_t longest_length = 1;
314+
int8_t current_start = -1;
315+
int8_t current_length = 0;
316+
for (int8_t f = 0; f < 8; f++) {
317+
if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) {
318+
if (current_start == -1) {
319+
current_start = f;
320+
current_length = 1;
321+
} else {
322+
current_length++;
323+
}
324+
if (current_length > longest_length) {
325+
longest_start = current_start;
326+
longest_length = current_length;
327+
}
328+
} else {
329+
current_start = -1;
330+
}
331+
}
332+
for (int f = 0; f < 8; f++) {
333+
if (f < longest_start || f >= longest_start + longest_length) {
334+
uint8_t c1 = _address.bytes[f * 2] >> 4;
335+
uint8_t c2 = _address.bytes[f * 2] & 0xf;
336+
uint8_t c3 = _address.bytes[f * 2 + 1] >> 4;
337+
uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf;
338+
if (c1 > 0) {
339+
n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10));
340+
}
341+
if (c1 > 0 || c2 > 0) {
342+
n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10));
343+
}
344+
if (c1 > 0 || c2 > 0 || c3 > 0) {
345+
n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10));
346+
}
347+
n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10));
348+
if (f < 7) {
349+
n += p.print(':');
350+
}
351+
} else if (f == longest_start) {
352+
if (longest_start == 0) {
353+
n += p.print(':');
354+
}
355+
n += p.print(':');
356+
}
357+
}
358+
return n;
359+
}
360+
361+
// IPv4
102362
for (int i = 0; i < 3; i++) {
103-
n += p.print(_address.bytes[i], DEC);
363+
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC);
104364
n += p.print('.');
105365
}
106-
n += p.print(_address.bytes[3], DEC);
366+
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC);
107367
return n;
108368
}
109369

370+
const IPAddress IN6ADDR_ANY(IPv6);
371+
const IPAddress INADDR_NONE(0, 0, 0, 0);

0 commit comments

Comments
 (0)