21
21
#include < IPAddress.h>
22
22
#include < Print.h>
23
23
24
- IPAddress::IPAddress ()
24
+ IPAddress::IPAddress () : IPAddress(IPv4) {}
25
+
26
+ IPAddress::IPAddress (IPType ip_type)
25
27
{
26
- _address.dword = 0 ;
28
+ _type = ip_type;
29
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
27
30
}
28
31
29
32
IPAddress::IPAddress (uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
30
33
{
31
- _address.bytes [0 ] = first_octet;
32
- _address.bytes [1 ] = second_octet;
33
- _address.bytes [2 ] = third_octet;
34
- _address.bytes [3 ] = fourth_octet;
34
+ _type = IPv4;
35
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
36
+ _address.bytes [IPADDRESS_V4_BYTES_INDEX] = first_octet;
37
+ _address.bytes [IPADDRESS_V4_BYTES_INDEX + 1 ] = second_octet;
38
+ _address.bytes [IPADDRESS_V4_BYTES_INDEX + 2 ] = third_octet;
39
+ _address.bytes [IPADDRESS_V4_BYTES_INDEX + 3 ] = fourth_octet;
40
+ }
41
+
42
+ 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) {
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;
35
60
}
36
61
37
62
IPAddress::IPAddress (uint32_t address)
38
63
{
39
- _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 .
40
76
}
41
77
42
- IPAddress::IPAddress (const uint8_t *address)
78
+ IPAddress::IPAddress (const uint8_t *address) : IPAddress(IPv4, address) {}
79
+
80
+ IPAddress::IPAddress (IPType ip_type, const uint8_t *address)
43
81
{
44
- memcpy (_address.bytes , address, sizeof (_address.bytes ));
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
+ }
45
89
}
46
90
47
91
IPAddress& IPAddress::operator =(const uint8_t *address)
48
92
{
49
- memcpy (_address.bytes , address, sizeof (_address.bytes ));
93
+ // IPv4 only conversion from byte pointer
94
+ _type = IPv4;
95
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
96
+ memcpy (&_address.bytes [IPADDRESS_V4_BYTES_INDEX], address, sizeof (uint32_t ));
50
97
return *this ;
51
98
}
52
99
53
100
IPAddress& IPAddress::operator =(uint32_t address)
54
101
{
55
- _address.dword = address;
102
+ // IPv4 conversion
103
+ // See note on conversion/comparison and uint32_t
104
+ _type = IPv4;
105
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
106
+ _address.dword [IPADDRESS_V4_DWORD_INDEX] = address;
56
107
return *this ;
57
108
}
58
109
59
110
bool IPAddress::operator ==(const uint8_t * addr) const
60
111
{
61
- return memcmp (addr, _address.bytes , sizeof (_address.bytes )) == 0 ;
112
+ return (addr._type == _type)
113
+ && (memcmp (addr._address .bytes , _address.bytes , sizeof (_address.bytes )) == 0 );
114
+ }
115
+
116
+ bool IPAddress::operator ==(const uint8_t * addr) const
117
+ {
118
+ // IPv4 only comparison to byte pointer
119
+ // Can't support IPv6 as we know our type, but not the length of the pointer
120
+ return _type == IPv4 && memcmp (addr, &_address.bytes [IPADDRESS_V4_BYTES_INDEX], sizeof (uint32_t )) == 0 ;
121
+ }
122
+
123
+ uint8_t IPAddress::operator [](int index) const {
124
+ if (_type == IPv4) {
125
+ return _address.bytes [IPADDRESS_V4_BYTES_INDEX + index];
126
+ }
127
+ return _address.bytes [index];
128
+ }
129
+
130
+ uint8_t & IPAddress::operator [](int index) {
131
+ if (_type == IPv4) {
132
+ return _address.bytes [IPADDRESS_V4_BYTES_INDEX + index];
133
+ }
134
+ return _address.bytes [index];
62
135
}
63
136
64
137
size_t IPAddress::printTo (Print& p) const
65
138
{
66
139
size_t n = 0 ;
67
- for (int i = 0 ; i < 3 ; i++) {
68
- n += p.print (_address.bytes [i], DEC);
140
+
141
+ if (_type == IPv6) {
142
+ // IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case
143
+ int8_t longest_start = -1 ;
144
+ int8_t longest_length = 1 ;
145
+ int8_t current_start = -1 ;
146
+ int8_t current_length = 0 ;
147
+ for (int8_t f = 0 ; f < 8 ; f++) {
148
+ if (_address.bytes [f * 2 ] == 0 && _address.bytes [f * 2 + 1 ] == 0 ) {
149
+ if (current_start == -1 ) {
150
+ current_start = f;
151
+ current_length = 1 ;
152
+ } else {
153
+ current_length++;
154
+ }
155
+ if (current_length > longest_length) {
156
+ longest_start = current_start;
157
+ longest_length = current_length;
158
+ }
159
+ } else {
160
+ current_start = -1 ;
161
+ }
162
+ }
163
+ for (int f = 0 ; f < 8 ; f++) {
164
+ if (f < longest_start || f >= longest_start + longest_length) {
165
+ uint8_t c1 = _address.bytes [f * 2 ] >> 4 ;
166
+ uint8_t c2 = _address.bytes [f * 2 ] & 0xf ;
167
+ uint8_t c3 = _address.bytes [f * 2 + 1 ] >> 4 ;
168
+ uint8_t c4 = _address.bytes [f * 2 + 1 ] & 0xf ;
169
+ if (c1 > 0 ) {
170
+ n += p.print ((char )(c1 < 10 ? ' 0' + c1 : ' a' + c1 - 10 ));
171
+ }
172
+ if (c1 > 0 || c2 > 0 ) {
173
+ n += p.print ((char )(c2 < 10 ? ' 0' + c2 : ' a' + c2 - 10 ));
174
+ }
175
+ if (c1 > 0 || c2 > 0 || c3 > 0 ) {
176
+ n += p.print ((char )(c3 < 10 ? ' 0' + c3 : ' a' + c3 - 10 ));
177
+ }
178
+ n += p.print ((char )(c4 < 10 ? ' 0' + c4 : ' a' + c4 - 10 ));
179
+ if (f < 7 ) {
180
+ n += p.print (' :' );
181
+ }
182
+ } else if (f == longest_start) {
183
+ if (longest_start == 0 ) {
184
+ n += p.print (' :' );
185
+ }
186
+ n += p.print (' :' );
187
+ }
188
+ }
189
+ return n;
190
+ }
191
+
192
+ // IPv4
193
+ for (int i =0 ; i < 3 ; i++)
194
+ {
195
+ n += p.print (_address.bytes [IPADDRESS_V4_BYTES_INDEX + i], DEC);
69
196
n += p.print (' .' );
70
197
}
71
- n += p.print (_address.bytes [3 ], DEC);
198
+ n += p.print (_address.bytes [IPADDRESS_V4_BYTES_INDEX + 3 ], DEC);
72
199
return n;
73
200
}
74
201
75
202
String IPAddress::toString () const
76
203
{
204
+ if (_type == IPv6)
205
+ {
206
+ StreamString s;
207
+ s.reserve (40 );
208
+ printTo (s);
209
+ return s;
210
+ }
211
+
212
+ // IPv4
77
213
char szRet[16 ];
78
214
sprintf (szRet," %u.%u.%u.%u" , _address.bytes [0 ], _address.bytes [1 ], _address.bytes [2 ], _address.bytes [3 ]);
79
215
return String (szRet);
80
216
}
81
217
82
218
bool IPAddress::fromString (const char *address)
219
+ {
220
+ if (!fromString4 (address))
221
+ {
222
+ return fromString6 (address);
223
+ }
224
+ return true ;
225
+ }
226
+
227
+ bool IPAddress::fromString4 (const char *address)
83
228
{
84
229
// TODO: add support for "a", "a.b", "a.b.c" formats
85
230
86
- uint16_t acc = 0 ; // Accumulator
231
+ int16_t acc = - 1 ; // Accumulator
87
232
uint8_t dots = 0 ;
88
233
234
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
89
235
while (*address)
90
236
{
91
237
char c = *address++;
92
238
if (c >= ' 0' && c <= ' 9' )
93
239
{
94
- acc = acc * 10 + (c - ' 0' );
240
+ acc = (acc < 0 ) ? (c - ' 0 ' ) : acc * 10 + (c - ' 0' );
95
241
if (acc > 255 ) {
96
242
// Value out of [0..255] range
97
243
return false ;
@@ -100,11 +246,15 @@ bool IPAddress::fromString(const char *address)
100
246
else if (c == ' .' )
101
247
{
102
248
if (dots == 3 ) {
103
- // Too much dots (there must be 3 dots)
249
+ // Too many dots (there must be 3 dots)
104
250
return false ;
105
251
}
106
- _address.bytes [dots++] = acc;
107
- acc = 0 ;
252
+ if (acc < 0 ) {
253
+ /* No value between dots, e.g. '1..' */
254
+ return false ;
255
+ }
256
+ _address.bytes [IPADDRESS_V4_BYTES_INDEX + dots++] = acc;
257
+ acc = -1 ;
108
258
}
109
259
else
110
260
{
@@ -117,7 +267,80 @@ bool IPAddress::fromString(const char *address)
117
267
// Too few dots (there must be 3 dots)
118
268
return false ;
119
269
}
120
- _address.bytes [3 ] = acc;
270
+ if (acc < 0 ) {
271
+ /* No value between dots, e.g. '1..' */
272
+ return false ;
273
+ }
274
+ _address.bytes [IPADDRESS_V4_BYTES_INDEX + 3 ] = acc;
275
+ _type = IPv4;
276
+ return true ;
277
+ }
278
+
279
+ bool IPAddress::fromString6 (const char *address) {
280
+ uint32_t acc = 0 ; // Accumulator
281
+ int colons = 0 , double_colons = -1 ;
282
+
283
+ while (*address)
284
+ {
285
+ char c = tolower (*address++);
286
+ if (isalnum (c) && c <= ' f' ) {
287
+ if (c >= ' a' )
288
+ c -= ' a' - ' 0' - 10 ;
289
+ acc = acc * 16 + (c - ' 0' );
290
+ if (acc > 0xffff )
291
+ // Value out of range
292
+ return false ;
293
+ }
294
+ else if (c == ' :' ) {
295
+ if (*address == ' :' ) {
296
+ if (double_colons >= 0 ) {
297
+ // :: allowed once
298
+ return false ;
299
+ }
300
+ if (*address != ' \0 ' && *(address + 1 ) == ' :' ) {
301
+ // ::: not allowed
302
+ return false ;
303
+ }
304
+ // remember location
305
+ double_colons = colons + !!acc;
306
+ address++;
307
+ } else if (*address == ' \0 ' ) {
308
+ // can't end with a single colon
309
+ return false ;
310
+ }
311
+ if (colons == 7 )
312
+ // too many separators
313
+ return false ;
314
+ _address.bytes [colons * 2 ] = acc >> 8 ;
315
+ _address.bytes [colons * 2 + 1 ] = acc & 0xff ;
316
+ colons++;
317
+ acc = 0 ;
318
+ }
319
+ else
320
+ // Invalid char
321
+ return false ;
322
+ }
323
+
324
+ if (double_colons == -1 && colons != 7 ) {
325
+ // Too few separators
326
+ return false ;
327
+ }
328
+ if (double_colons > -1 && colons > 6 ) {
329
+ // Too many segments (double colon must be at least one zero field)
330
+ return false ;
331
+ }
332
+ _address.bytes [colons * 2 ] = acc >> 8 ;
333
+ _address.bytes [colons * 2 + 1 ] = acc & 0xff ;
334
+ colons++;
335
+
336
+ if (double_colons != -1 ) {
337
+ for (int i = colons * 2 - double_colons * 2 - 1 ; i >= 0 ; i--)
338
+ _address.bytes [16 - colons * 2 + double_colons * 2 + i] = _address.bytes [double_colons * 2 + i];
339
+ for (int i = double_colons * 2 ; i < 16 - colons * 2 + double_colons * 2 ; i++)
340
+ _address.bytes [i] = 0 ;
341
+ }
342
+
343
+ _type = IPv6;
121
344
return true ;
122
345
}
123
346
0 commit comments