20
20
#include < Arduino.h>
21
21
#include < IPAddress.h>
22
22
#include < Print.h>
23
+ #include < StreamString.h>
23
24
24
- IPAddress::IPAddress ()
25
+ IPAddress::IPAddress () : IPAddress(IPv4) {}
26
+
27
+ IPAddress::IPAddress (IPType ip_type)
25
28
{
26
- _address.dword = 0 ;
29
+ _type = ip_type;
30
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
27
31
}
28
32
29
33
IPAddress::IPAddress (uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
30
34
{
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;
35
61
}
36
62
37
63
IPAddress::IPAddress (uint32_t address)
38
64
{
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 .
40
77
}
41
78
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)
43
82
{
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
+ }
45
90
}
46
91
47
92
IPAddress& IPAddress::operator =(const uint8_t *address)
48
93
{
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 ));
50
98
return *this ;
51
99
}
52
100
53
101
IPAddress& IPAddress::operator =(uint32_t address)
54
102
{
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;
56
108
return *this ;
57
109
}
58
110
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
+
59
117
bool IPAddress::operator ==(const uint8_t * addr) const
60
118
{
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 ];
62
136
}
63
137
64
138
size_t IPAddress::printTo (Print& p) const
65
139
{
66
140
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);
69
197
n += p.print (' .' );
70
198
}
71
- n += p.print (_address.bytes [3 ], DEC);
199
+ n += p.print (_address.bytes [IPADDRESS_V4_BYTES_INDEX + 3 ], DEC);
72
200
return n;
73
201
}
74
202
75
203
String IPAddress::toString () const
76
204
{
205
+ if (_type == IPv6)
206
+ {
207
+ StreamString s;
208
+ s.reserve (40 );
209
+ printTo (s);
210
+ return s;
211
+ }
212
+
213
+ // IPv4
77
214
char szRet[16 ];
78
215
sprintf (szRet," %u.%u.%u.%u" , _address.bytes [0 ], _address.bytes [1 ], _address.bytes [2 ], _address.bytes [3 ]);
79
216
return String (szRet);
80
217
}
81
218
82
219
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)
83
229
{
84
230
// TODO: add support for "a", "a.b", "a.b.c" formats
85
231
86
- uint16_t acc = 0 ; // Accumulator
232
+ int16_t acc = - 1 ; // Accumulator
87
233
uint8_t dots = 0 ;
88
234
235
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
89
236
while (*address)
90
237
{
91
238
char c = *address++;
92
239
if (c >= ' 0' && c <= ' 9' )
93
240
{
94
- acc = acc * 10 + (c - ' 0' );
241
+ acc = (acc < 0 ) ? (c - ' 0 ' ) : acc * 10 + (c - ' 0' );
95
242
if (acc > 255 ) {
96
243
// Value out of [0..255] range
97
244
return false ;
@@ -100,11 +247,15 @@ bool IPAddress::fromString(const char *address)
100
247
else if (c == ' .' )
101
248
{
102
249
if (dots == 3 ) {
103
- // Too much dots (there must be 3 dots)
250
+ // Too many dots (there must be 3 dots)
104
251
return false ;
105
252
}
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 ;
108
259
}
109
260
else
110
261
{
@@ -117,7 +268,80 @@ bool IPAddress::fromString(const char *address)
117
268
// Too few dots (there must be 3 dots)
118
269
return false ;
119
270
}
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;
121
345
return true ;
122
346
}
123
347
0 commit comments