22
22
23
23
using namespace arduino ;
24
24
25
- IPAddress::IPAddress ()
25
+ IPAddress::IPAddress () : IPAddress(IPv4) {}
26
+
27
+ IPAddress::IPAddress (IPType ip_type)
26
28
{
27
- _address.dword = 0 ;
29
+ _type = ip_type;
30
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
28
31
}
29
32
30
33
IPAddress::IPAddress (uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
31
34
{
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;
36
61
}
37
62
38
63
IPAddress::IPAddress (uint32_t address)
39
64
{
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 .
41
77
}
42
78
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)
44
82
{
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
+ }
46
90
}
47
91
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)
49
100
{
50
101
// TODO: add support for "a", "a.b", "a.b.c" formats
51
102
52
103
int16_t acc = -1 ; // Accumulator
53
104
uint8_t dots = 0 ;
54
105
106
+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
55
107
while (*address)
56
108
{
57
109
char c = *address++;
@@ -73,7 +125,7 @@ bool IPAddress::fromString(const char *address)
73
125
/* No value between dots, e.g. '1..' */
74
126
return false ;
75
127
}
76
- _address.bytes [dots++] = acc;
128
+ _address.bytes [IPADDRESS_V4_BYTES_INDEX + dots++] = acc;
77
129
acc = -1 ;
78
130
}
79
131
else
@@ -91,37 +143,188 @@ bool IPAddress::fromString(const char *address)
91
143
/* No value between dots, e.g. '1..' */
92
144
return false ;
93
145
}
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;
95
216
return true ;
96
217
}
97
218
98
219
IPAddress& IPAddress::operator =(const uint8_t *address)
99
220
{
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 ));
101
225
return *this ;
102
226
}
103
227
104
228
IPAddress& IPAddress::operator =(uint32_t address)
105
229
{
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;
107
235
return *this ;
108
236
}
109
237
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
+
110
243
bool IPAddress::operator ==(const uint8_t * addr) const
111
244
{
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 ];
113
262
}
114
263
115
264
size_t IPAddress::printTo (Print& p) const
116
265
{
117
266
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
118
320
for (int i =0 ; i < 3 ; i++)
119
321
{
120
- n += p.print (_address.bytes [i], DEC);
322
+ n += p.print (_address.bytes [IPADDRESS_V4_BYTES_INDEX + i], DEC);
121
323
n += p.print (' .' );
122
324
}
123
- n += p.print (_address.bytes [3 ], DEC);
325
+ n += p.print (_address.bytes [IPADDRESS_V4_BYTES_INDEX + 3 ], DEC);
124
326
return n;
125
327
}
126
328
329
+ const IPAddress arduino::IN6ADDR_ANY (IPv6);
127
330
const IPAddress arduino::INADDR_NONE (0 ,0 ,0 ,0 );
0 commit comments