Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c8ee90f

Browse files
Merge pull request #169 from sgryphon/feature/add-v6-to-ipaddress
Add IPv6 support to IPAddress
2 parents ee040ed + bcc5233 commit c8ee90f

10 files changed

+998
-27
lines changed

‎api/IPAddress.cpp‎

Lines changed: 220 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,36 +22,88 @@
2222

2323
using namespace arduino;
2424

25-
IPAddress::IPAddress()
25+
IPAddress::IPAddress() : IPAddress(IPv4) {}
26+
27+
IPAddress::IPAddress(IPType ip_type)
2628
{
27-
_address.dword = 0;
29+
_type = ip_type;
30+
memset(_address.bytes, 0, sizeof(_address.bytes));
2831
}
2932

3033
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
3134
{
32-
_address.bytes[0] = first_octet;
33-
_address.bytes[1] = second_octet;
34-
_address.bytes[2] = third_octet;
35-
_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;
3661
}
3762

3863
IPAddress::IPAddress(uint32_t address)
3964
{
40-
_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 .
4177
}
4278

43-
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)
4482
{
45-
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+
}
4690
}
4791

48-
bool IPAddress::fromString(const char *address)
92+
bool IPAddress::fromString(const char *address) {
93+
if (!fromString4(address)) {
94+
return fromString6(address);
95+
}
96+
return true;
97+
}
98+
99+
bool IPAddress::fromString4(const char *address)
49100
{
50101
// TODO: add support for "a", "a.b", "a.b.c" formats
51102

52103
int16_t acc = -1; // Accumulator
53104
uint8_t dots = 0;
54105

106+
memset(_address.bytes, 0, sizeof(_address.bytes));
55107
while (*address)
56108
{
57109
char c = *address++;
@@ -73,7 +125,7 @@ bool IPAddress::fromString(const char *address)
73125
/* No value between dots, e.g. '1..' */
74126
return false;
75127
}
76-
_address.bytes[dots++] = acc;
128+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + dots++] = acc;
77129
acc = -1;
78130
}
79131
else
@@ -91,37 +143,188 @@ bool IPAddress::fromString(const char *address)
91143
/* No value between dots, e.g. '1..' */
92144
return false;
93145
}
94-
_address.bytes[3] = acc;
146+
_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = acc;
147+
_type = IPv4;
148+
return true;
149+
}
150+
151+
bool IPAddress::fromString6(const char *address) {
152+
uint32_t acc = 0; // Accumulator
153+
int colons = 0, double_colons = -1;
154+
155+
while (*address)
156+
{
157+
char c = tolower(*address++);
158+
if (isalnum(c) && c <= 'f') {
159+
if (c >= 'a')
160+
c -= 'a' - '0' - 10;
161+
acc = acc * 16 + (c - '0');
162+
if (acc > 0xffff)
163+
// Value out of range
164+
return false;
165+
}
166+
else if (c == ':') {
167+
if (*address == ':') {
168+
if (double_colons >= 0) {
169+
// :: allowed once
170+
return false;
171+
}
172+
if (*address != '0円' && *(address + 1) == ':') {
173+
// ::: not allowed
174+
return false;
175+
}
176+
// remember location
177+
double_colons = colons + !!acc;
178+
address++;
179+
} else if (*address == '0円') {
180+
// can't end with a single colon
181+
return false;
182+
}
183+
if (colons == 7)
184+
// too many separators
185+
return false;
186+
_address.bytes[colons * 2] = acc >> 8;
187+
_address.bytes[colons * 2 + 1] = acc & 0xff;
188+
colons++;
189+
acc = 0;
190+
}
191+
else
192+
// Invalid char
193+
return false;
194+
}
195+
196+
if (double_colons == -1 && colons != 7) {
197+
// Too few separators
198+
return false;
199+
}
200+
if (double_colons > -1 && colons > 6) {
201+
// Too many segments (double colon must be at least one zero field)
202+
return false;
203+
}
204+
_address.bytes[colons * 2] = acc >> 8;
205+
_address.bytes[colons * 2 + 1] = acc & 0xff;
206+
colons++;
207+
208+
if (double_colons != -1) {
209+
for (int i = colons * 2 - double_colons * 2 - 1; i >= 0; i--)
210+
_address.bytes[16 - colons * 2 + double_colons * 2 + i] = _address.bytes[double_colons * 2 + i];
211+
for (int i = double_colons * 2; i < 16 - colons * 2 + double_colons * 2; i++)
212+
_address.bytes[i] = 0;
213+
}
214+
215+
_type = IPv6;
95216
return true;
96217
}
97218

98219
IPAddress& IPAddress::operator=(const uint8_t *address)
99220
{
100-
memcpy(_address.bytes, address, sizeof(_address.bytes));
221+
// IPv4 only conversion from byte pointer
222+
_type = IPv4;
223+
memset(_address.bytes, 0, sizeof(_address.bytes));
224+
memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t));
101225
return *this;
102226
}
103227

104228
IPAddress& IPAddress::operator=(uint32_t address)
105229
{
106-
_address.dword = address;
230+
// IPv4 conversion
231+
// See note on conversion/comparison and uint32_t
232+
_type = IPv4;
233+
memset(_address.bytes, 0, sizeof(_address.bytes));
234+
_address.dword[IPADDRESS_V4_DWORD_INDEX] = address;
107235
return *this;
108236
}
109237

238+
bool IPAddress::operator==(const IPAddress& addr) const {
239+
return (addr._type == _type)
240+
&& (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0);
241+
}
242+
110243
bool IPAddress::operator==(const uint8_t* addr) const
111244
{
112-
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
245+
// IPv4 only comparison to byte pointer
246+
// Can't support IPv6 as we know our type, but not the length of the pointer
247+
return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0;
248+
}
249+
250+
uint8_t IPAddress::operator[](int index) const {
251+
if (_type == IPv4) {
252+
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
253+
}
254+
return _address.bytes[index];
255+
}
256+
257+
uint8_t& IPAddress::operator[](int index) {
258+
if (_type == IPv4) {
259+
return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index];
260+
}
261+
return _address.bytes[index];
113262
}
114263

115264
size_t IPAddress::printTo(Print& p) const
116265
{
117266
size_t n = 0;
267+
268+
if (_type == IPv6) {
269+
// IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case
270+
int8_t longest_start = -1;
271+
int8_t longest_length = 1;
272+
int8_t current_start = -1;
273+
int8_t current_length = 0;
274+
for (int8_t f = 0; f < 8; f++) {
275+
if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) {
276+
if (current_start == -1) {
277+
current_start = f;
278+
current_length = 1;
279+
} else {
280+
current_length++;
281+
}
282+
if (current_length > longest_length) {
283+
longest_start = current_start;
284+
longest_length = current_length;
285+
}
286+
} else {
287+
current_start = -1;
288+
}
289+
}
290+
for (int f = 0; f < 8; f++) {
291+
if (f < longest_start || f >= longest_start + longest_length) {
292+
uint8_t c1 = _address.bytes[f * 2] >> 4;
293+
uint8_t c2 = _address.bytes[f * 2] & 0xf;
294+
uint8_t c3 = _address.bytes[f * 2 + 1] >> 4;
295+
uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf;
296+
if (c1 > 0) {
297+
n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10));
298+
}
299+
if (c1 > 0 || c2 > 0) {
300+
n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10));
301+
}
302+
if (c1 > 0 || c2 > 0 || c3 > 0) {
303+
n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10));
304+
}
305+
n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10));
306+
if (f < 7) {
307+
n += p.print(':');
308+
}
309+
} else if (f == longest_start) {
310+
if (longest_start == 0) {
311+
n += p.print(':');
312+
}
313+
n += p.print(':');
314+
}
315+
}
316+
return n;
317+
}
318+
319+
// IPv4
118320
for (int i =0; i < 3; i++)
119321
{
120-
n += p.print(_address.bytes[i], DEC);
322+
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC);
121323
n += p.print('.');
122324
}
123-
n += p.print(_address.bytes[3], DEC);
325+
n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC);
124326
return n;
125327
}
126328

329+
const IPAddress arduino::IN6ADDR_ANY(IPv6);
127330
const IPAddress arduino::INADDR_NONE(0,0,0,0);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /