17
17
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
18
*/
19
19
20
- #include < Arduino.h >
21
- #include < IPAddress.h >
20
+ #include " IPAddress.h "
21
+ #include " Print.h "
22
22
23
- IPAddress::IPAddress ()
23
+ IPAddress::IPAddress () : IPAddress(IPv4) {}
24
+
25
+ IPAddress::IPAddress (IPType ip_type)
24
26
{
25
- _address.dword = 0 ;
27
+ _type = ip_type;
28
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
26
29
}
27
30
28
31
IPAddress::IPAddress (uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
29
32
{
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;
34
60
}
35
61
36
62
IPAddress::IPAddress (uint32_t address)
37
63
{
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);
39
101
}
40
102
41
- IPAddress::IPAddress ( const uint8_t *address)
103
+ String IPAddress::toString6 () const
42
104
{
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
+ }
44
121
}
45
122
46
123
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)
47
132
{
48
133
// TODO: add support for "a", "a.b", "a.b.c" formats
49
134
50
- uint16_t acc = 0 ; // Accumulator
135
+ int16_t acc = - 1 ; // Accumulator
51
136
uint8_t dots = 0 ;
52
137
138
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
53
139
while (*address) {
54
140
char c = *address++;
55
141
if (c >= ' 0' && c <= ' 9' ) {
56
- acc = acc * 10 + (c - ' 0' );
142
+ acc = (acc < 0 ) ? (c - ' 0 ' ) : acc * 10 + (c - ' 0' );
57
143
if (acc > 255 ) {
58
144
// Value out of [0..255] range
59
145
return false ;
60
146
}
61
147
} else if (c == ' .' ) {
62
148
if (dots == 3 ) {
63
- // Too much dots (there must be 3 dots)
149
+ // Too many dots (there must be 3 dots)
64
150
return false ;
65
151
}
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 ;
68
158
} else {
69
159
// Invalid char
70
160
return false ;
@@ -75,35 +165,207 @@ bool IPAddress::fromString(const char *address)
75
165
// Too few dots (there must be 3 dots)
76
166
return false ;
77
167
}
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;
79
249
return true ;
80
250
}
81
251
82
252
IPAddress &IPAddress::operator =(const uint8_t *address)
83
253
{
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);
85
264
return *this ;
86
265
}
87
266
88
267
IPAddress &IPAddress::operator =(uint32_t address)
89
268
{
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;
91
274
return *this ;
92
275
}
93
276
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
+
94
283
bool IPAddress::operator ==(const uint8_t *addr) const
95
284
{
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 ];
97
304
}
98
305
99
306
size_t IPAddress::printTo (Print &p) const
100
307
{
101
308
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
102
362
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);
104
364
n += p.print (' .' );
105
365
}
106
- n += p.print (_address.bytes [3 ], DEC);
366
+ n += p.print (_address.bytes [IPADDRESS_V4_BYTES_INDEX + 3 ], DEC);
107
367
return n;
108
368
}
109
369
370
+ const IPAddress IN6ADDR_ANY (IPv6);
371
+ const IPAddress INADDR_NONE (0 , 0 , 0 , 0 );
0 commit comments