Skip to content

Commit 827fee1

Browse files
committed
feat(ipaddress): add support for ipv6 type, following arduinocore api
1 parent 0aefc94 commit 827fee1

File tree

2 files changed

+275
-39
lines changed

2 files changed

+275
-39
lines changed

Diff for: cores/esp32/IPAddress.cpp

+245-21
Original file line numberDiff line numberDiff line change
@@ -20,78 +20,225 @@
2020
#include <Arduino.h>
2121
#include <IPAddress.h>
2222
#include <Print.h>
23+
#include <StreamString.h>
2324

24-
IPAddress::IPAddress()
25+
IPAddress::IPAddress() : IPAddress(IPv4) {}
26+
27+
IPAddress::IPAddress(IPType ip_type)
2528
{
26-
_address.dword = 0;
29+
_type = ip_type;
30+
memset(_address.bytes, 0, sizeof(_address.bytes));
2731
}
2832

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

3763
IPAddress::IPAddress(uint32_t address)
3864
{
39-
_address.dword = address;
65+
// IPv4 only
66+
_type = IPv4;
67+
memset(_address.bytes, 0, sizeof(_address.bytes));
68+
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
69+
70+
// NOTE on conversion/comparison and uint32_t:
71+
// These conversions are host platform dependent.
72+
// There is a defined integer representation of IPv4 addresses,
73+
// based on network byte order (will be the value on big endian systems),
74+
// e.g. http://2398766798 is the same as http://142.250.70.206,
75+
// However on little endian systems the octets 0x83, 0xFA, 0x46, 0xCE,
76+
// in that order, will form the integer (uint32_t) 3460758158 .
4077
}
4178

42-
IPAddress::IPAddress(const uint8_t *address)
79+
IPAddress::IPAddress(const uint8_t *address) : IPAddress(IPv4, address) {}
80+
81+
IPAddress::IPAddress(IPType ip_type, const uint8_t *address)
4382
{
44-
memcpy(_address.bytes, address, sizeof(_address.bytes));
83+
_type = ip_type;
84+
if (ip_type == IPv4) {
85+
memset(_address.bytes, 0, sizeof(_address.bytes));
86+
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
87+
} else {
88+
memcpy(_address.bytes, address, sizeof(_address.bytes));
89+
}
4590
}
4691

4792
IPAddress& IPAddress::operator=(const uint8_t *address)
4893
{
49-
memcpy(_address.bytes, address, sizeof(_address.bytes));
94+
// IPv4 only conversion from byte pointer
95+
_type = IPv4;
96+
memset(_address.bytes, 0, sizeof(_address.bytes));
97+
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
5098
return *this;
5199
}
52100

53101
IPAddress& IPAddress::operator=(uint32_t address)
54102
{
55-
_address.dword = address;
103+
// IPv4 conversion
104+
// See note on conversion/comparison and uint32_t
105+
_type = IPv4;
106+
memset(_address.bytes, 0, sizeof(_address.bytes));
107+
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
56108
return *this;
57109
}
58110

111+
bool IPAddress::operator==(const IPAddress& addr) const
112+
{
113+
return (addr._type == _type)
114+
&& (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0);
115+
}
116+
59117
bool IPAddress::operator==(const uint8_t* addr) const
60118
{
61-
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
119+
// IPv4 only comparison to byte pointer
120+
// Can't support IPv6 as we know our type, but not the length of the pointer
121+
return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0;
122+
}
123+
124+
uint8_t IPAddress::operator[](int index) const {
125+
if (_type == IPv4) {
126+
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
127+
}
128+
return _address.bytes[index];
129+
}
130+
131+
uint8_t& IPAddress::operator[](int index) {
132+
if (_type == IPv4) {
133+
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
134+
}
135+
return _address.bytes[index];
62136
}
63137

64138
size_t IPAddress::printTo(Print& p) const
65139
{
66140
size_t n = 0;
67-
for(int i = 0; i < 3; i++) {
68-
n += p.print(_address.bytes[i], DEC);
141+
142+
if (_type == IPv6) {
143+
// IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case
144+
int8_t longest_start = -1;
145+
int8_t longest_length = 1;
146+
int8_t current_start = -1;
147+
int8_t current_length = 0;
148+
for (int8_t f = 0; f < 8; f++) {
149+
if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) {
150+
if (current_start == -1) {
151+
current_start = f;
152+
current_length = 1;
153+
} else {
154+
current_length++;
155+
}
156+
if (current_length > longest_length) {
157+
longest_start = current_start;
158+
longest_length = current_length;
159+
}
160+
} else {
161+
current_start = -1;
162+
}
163+
}
164+
for (int f = 0; f < 8; f++) {
165+
if (f < longest_start || f >= longest_start + longest_length) {
166+
uint8_t c1 = _address.bytes[f * 2] >> 4;
167+
uint8_t c2 = _address.bytes[f * 2] & 0xf;
168+
uint8_t c3 = _address.bytes[f * 2 + 1] >> 4;
169+
uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf;
170+
if (c1 > 0) {
171+
n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10));
172+
}
173+
if (c1 > 0 || c2 > 0) {
174+
n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10));
175+
}
176+
if (c1 > 0 || c2 > 0 || c3 > 0) {
177+
n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10));
178+
}
179+
n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10));
180+
if (f < 7) {
181+
n += p.print(':');
182+
}
183+
} else if (f == longest_start) {
184+
if (longest_start == 0) {
185+
n += p.print(':');
186+
}
187+
n += p.print(':');
188+
}
189+
}
190+
return n;
191+
}
192+
193+
// IPv4
194+
for (int i =0; i < 3; i++)
195+
{
196+
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC);
69197
n += p.print('.');
70198
}
71-
n += p.print(_address.bytes[3], DEC);
199+
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC);
72200
return n;
73201
}
74202

75203
String IPAddress::toString() const
76204
{
205+
if (_type == IPv6)
206+
{
207+
StreamString s;
208+
s.reserve(40);
209+
printTo(s);
210+
return s;
211+
}
212+
213+
// IPv4
77214
char szRet[16];
78215
sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]);
79216
return String(szRet);
80217
}
81218

82219
bool IPAddress::fromString(const char *address)
220+
{
221+
if (!fromString4(address))
222+
{
223+
return fromString6(address);
224+
}
225+
return true;
226+
}
227+
228+
bool IPAddress::fromString4(const char *address)
83229
{
84230
// TODO: add support for "a", "a.b", "a.b.c" formats
85231

86-
uint16_t acc = 0; // Accumulator
232+
int16_t acc = -1; // Accumulator
87233
uint8_t dots = 0;
88234

235+
memset(_address.bytes, 0, sizeof(_address.bytes));
89236
while (*address)
90237
{
91238
char c = *address++;
92239
if (c >= '0' && c <= '9')
93240
{
94-
acc = acc * 10 + (c - '0');
241+
acc = (acc < 0) ? (c - '0') : acc * 10 + (c - '0');
95242
if (acc > 255) {
96243
// Value out of [0..255] range
97244
return false;
@@ -100,11 +247,15 @@ bool IPAddress::fromString(const char *address)
100247
else if (c == '.')
101248
{
102249
if (dots == 3) {
103-
// Too much dots (there must be 3 dots)
250+
// Too many dots (there must be 3 dots)
104251
return false;
105252
}
106-
_address.bytes[dots++] = acc;
107-
acc = 0;
253+
if (acc < 0) {
254+
/* No value between dots, e.g. '1..' */
255+
return false;
256+
}
257+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + dots++] = acc;
258+
acc = -1;
108259
}
109260
else
110261
{
@@ -117,7 +268,80 @@ bool IPAddress::fromString(const char *address)
117268
// Too few dots (there must be 3 dots)
118269
return false;
119270
}
120-
_address.bytes[3] = acc;
271+
if (acc < 0) {
272+
/* No value between dots, e.g. '1..' */
273+
return false;
274+
}
275+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = acc;
276+
_type = IPv4;
277+
return true;
278+
}
279+
280+
bool IPAddress::fromString6(const char *address) {
281+
uint32_t acc = 0; // Accumulator
282+
int colons = 0, double_colons = -1;
283+
284+
while (*address)
285+
{
286+
char c = tolower(*address++);
287+
if (isalnum(c) && c <= 'f') {
288+
if (c >= 'a')
289+
c -= 'a' - '0' - 10;
290+
acc = acc * 16 + (c - '0');
291+
if (acc > 0xffff)
292+
// Value out of range
293+
return false;
294+
}
295+
else if (c == ':') {
296+
if (*address == ':') {
297+
if (double_colons >= 0) {
298+
// :: allowed once
299+
return false;
300+
}
301+
if (*address != '\0' && *(address + 1) == ':') {
302+
// ::: not allowed
303+
return false;
304+
}
305+
// remember location
306+
double_colons = colons + !!acc;
307+
address++;
308+
} else if (*address == '\0') {
309+
// can't end with a single colon
310+
return false;
311+
}
312+
if (colons == 7)
313+
// too many separators
314+
return false;
315+
_address.bytes[colons * 2] = acc >> 8;
316+
_address.bytes[colons * 2 + 1] = acc & 0xff;
317+
colons++;
318+
acc = 0;
319+
}
320+
else
321+
// Invalid char
322+
return false;
323+
}
324+
325+
if (double_colons == -1 && colons != 7) {
326+
// Too few separators
327+
return false;
328+
}
329+
if (double_colons > -1 && colons > 6) {
330+
// Too many segments (double colon must be at least one zero field)
331+
return false;
332+
}
333+
_address.bytes[colons * 2] = acc >> 8;
334+
_address.bytes[colons * 2 + 1] = acc & 0xff;
335+
colons++;
336+
337+
if (double_colons != -1) {
338+
for (int i = colons * 2 - double_colons * 2 - 1; i >= 0; i--)
339+
_address.bytes[16 - colons * 2 + double_colons * 2 + i] = _address.bytes[double_colons * 2 + i];
340+
for (int i = double_colons * 2; i < 16 - colons * 2 + double_colons * 2; i++)
341+
_address.bytes[i] = 0;
342+
}
343+
344+
_type = IPv6;
121345
return true;
122346
}
123347

0 commit comments

Comments
 (0)