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