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 ) - sizeof (uint32_t ));
37
+ _address.bytes [12 ] = first_octet;
38
+ _address.bytes [13 ] = second_octet;
39
+ _address.bytes [14 ] = third_octet;
40
+ _address.bytes [15 ] = fourth_octet;
36
41
}
37
42
38
43
IPAddress::IPAddress (uint32_t address)
39
44
{
40
- _address.dword = address;
45
+ // IPv4 only
46
+ _type = IPv4;
47
+ memset (_address.bytes , 0 , sizeof (_address.bytes ) - sizeof (uint32_t ));
48
+ _address.dword [3 ] = address;
49
+
50
+ // NOTE on conversion/comparison and uint32_t:
51
+ // These conversions are host platform dependent.
52
+ // There is a defined integer representation of IPv4 addresses,
53
+ // based on network byte order (will be the value on big endian systems),
54
+ // e.g. http://2398766798 is the same as http://142.250.70.206,
55
+ // However on little endian systems the octets 0x83, 0xFA, 0x46, 0xCE,
56
+ // in that order, will form the integer (uint32_t) 3460758158 .
41
57
}
42
58
43
- IPAddress::IPAddress (const uint8_t *address)
59
+ IPAddress::IPAddress (const uint8_t *address) : IPAddress(IPv4, address) {}
60
+
61
+ IPAddress::IPAddress (IPType ip_type, const uint8_t *address)
44
62
{
45
- memcpy (_address.bytes , address, sizeof (_address.bytes ));
63
+ _type = ip_type;
64
+ if (ip_type == IPv4) {
65
+ memset (_address.bytes , 0 , sizeof (_address.bytes ) - sizeof (uint32_t ));
66
+ memcpy (&_address.bytes [12 ], address, sizeof (uint32_t ));
67
+ } else {
68
+ memcpy (_address.bytes , address, sizeof (_address.bytes ));
69
+ }
70
+ }
71
+
72
+ bool IPAddress::fromString (const char *address) {
73
+ if (!fromString4 (address)) {
74
+ return fromString6 (address);
75
+ }
76
+ return true ;
46
77
}
47
78
48
- bool IPAddress::fromString (const char *address)
79
+ bool IPAddress::fromString4 (const char *address)
49
80
{
50
81
// TODO: add support for "a", "a.b", "a.b.c" formats
51
82
@@ -73,7 +104,7 @@ bool IPAddress::fromString(const char *address)
73
104
/* No value between dots, e.g. '1..' */
74
105
return false ;
75
106
}
76
- _address.bytes [dots++] = acc;
107
+ _address.bytes [12 + dots++] = acc;
77
108
acc = -1 ;
78
109
}
79
110
else
@@ -91,37 +122,175 @@ bool IPAddress::fromString(const char *address)
91
122
/* No value between dots, e.g. '1..' */
92
123
return false ;
93
124
}
94
- _address.bytes [3 ] = acc;
125
+ memset (_address.bytes , 0 , sizeof (_address.bytes ) - sizeof (uint32_t ));
126
+ _address.bytes [15 ] = acc;
127
+ _type = IPv4;
128
+ return true ;
129
+ }
130
+
131
+ bool IPAddress::fromString6 (const char *address) {
132
+ uint32_t acc = 0 ; // Accumulator
133
+ int dots = 0 , doubledots = -1 ;
134
+
135
+ while (*address)
136
+ {
137
+ char c = tolower (*address++);
138
+ if (isalnum (c)) {
139
+ if (c >= ' a' )
140
+ c -= ' a' - ' 0' - 10 ;
141
+ acc = acc * 16 + (c - ' 0' );
142
+ if (acc > 0xffff )
143
+ // Value out of range
144
+ return false ;
145
+ }
146
+ else if (c == ' :' ) {
147
+ if (*address == ' :' ) {
148
+ if (doubledots >= 0 )
149
+ // :: allowed once
150
+ return false ;
151
+ // remember location
152
+ doubledots = dots + !!acc;
153
+ address++;
154
+ }
155
+ if (dots == 7 )
156
+ // too many separators
157
+ return false ;
158
+ _address.bytes [dots] = acc >> 2 ;
159
+ _address.bytes [dots + 1 ] = acc & 0xff ;
160
+ dots++;
161
+ acc = 0 ;
162
+ }
163
+ else
164
+ // Invalid char
165
+ return false ;
166
+ }
167
+
168
+ if (doubledots == -1 && dots != 7 )
169
+ // Too few separators
170
+ return false ;
171
+ _address.bytes [dots] = acc >> 2 ;
172
+ _address.bytes [dots + 1 ] = acc & 0xff ;
173
+ dots++;
174
+
175
+ if (doubledots != -1 ) {
176
+ for (int i = dots * 2 - doubledots * 2 - 1 ; i >= 0 ; i--)
177
+ _address.bytes [16 - dots * 2 + doubledots * 2 + i] = _address.bytes [doubledots * 2 + i];
178
+ for (int i = doubledots * 2 ; i < 16 - dots * 2 + doubledots * 2 ; i++)
179
+ _address.bytes [i] = 0 ;
180
+ }
181
+
182
+ _type = IPv6;
95
183
return true ;
96
184
}
97
185
98
186
IPAddress& IPAddress::operator =(const uint8_t *address)
99
187
{
100
- memcpy (_address.bytes , address, sizeof (_address.bytes ));
188
+ // IPv4 only conversion from byte pointer
189
+ _type = IPv4;
190
+ memset (_address.bytes , 0 , sizeof (_address.bytes ) - sizeof (uint32_t ));
191
+ memcpy (&_address.bytes [12 ], address, sizeof (uint32_t ));
101
192
return *this ;
102
193
}
103
194
104
195
IPAddress& IPAddress::operator =(uint32_t address)
105
196
{
106
- _address.dword = address;
197
+ // IPv4 conversion
198
+ // See note on conversion/comparison and uint32_t
199
+ _type = IPv4;
200
+ _address.dword [0 ] = 0 ;
201
+ _address.dword [1 ] = 0 ;
202
+ _address.dword [2 ] = 0 ;
203
+ _address.dword [3 ] = address;
107
204
return *this ;
108
205
}
109
206
207
+ bool IPAddress::operator ==(const IPAddress& addr) const {
208
+ return (addr._type == _type)
209
+ && (memcmp (addr._address .bytes , _address.bytes , sizeof (_address.bytes )) == 0 );
210
+ };
211
+
110
212
bool IPAddress::operator ==(const uint8_t * addr) const
111
213
{
112
- return memcmp (addr, _address.bytes , sizeof (_address.bytes )) == 0 ;
214
+ // IPv4 only comparison to byte pointer
215
+ // Can't support IPv6 as we know our type, but not the length of the pointer
216
+ return _type == IPv4 && memcmp (addr, &_address.bytes [12 ], sizeof (uint32_t )) == 0 ;
113
217
}
114
218
219
+ uint8_t IPAddress::operator [](int index) const {
220
+ if (_type == IPv4) {
221
+ return _address.bytes [index + 12 ];
222
+ }
223
+ return _address.bytes [index ];
224
+ };
225
+
226
+ uint8_t & IPAddress::operator [](int index) {
227
+ if (_type == IPv4) {
228
+ return _address.bytes [index + 12 ];
229
+ }
230
+ return _address.bytes [index ];
231
+ };
232
+
115
233
size_t IPAddress::printTo (Print& p) const
116
234
{
117
235
size_t n = 0 ;
236
+
237
+ if (_type == IPv6) {
238
+ // IPv6 IETF canonical format: left-most longest run of all zero fields, lower case
239
+ int8_t longest_start = -1 ;
240
+ int8_t longest_length = 0 ;
241
+ int8_t current_start = -1 ;
242
+ int8_t current_length = 0 ;
243
+ for (int8_t f = 0 ; f < 8 ; f++) {
244
+ if (_address.bytes [f * 2 ] == 0 && _address.bytes [f * 2 + 1 ] == 0 ) {
245
+ if (current_start == -1 ) {
246
+ current_start = f;
247
+ current_length = 0 ;
248
+ } else {
249
+ current_length++;
250
+ }
251
+ if (current_length > longest_length) {
252
+ longest_start = current_start;
253
+ longest_length = current_length;
254
+ }
255
+ } else {
256
+ current_start = -1 ;
257
+ }
258
+ }
259
+ for (int f = 0 ; f < 8 ; f++) {
260
+ if (f < longest_start || f >= longest_start + longest_length) {
261
+ uint8_t c1 = _address.bytes [f * 2 ] >> 1 ;
262
+ uint8_t c2 = _address.bytes [f * 2 ] & 0xf ;
263
+ uint8_t c3 = _address.bytes [f * 2 + 1 ] >> 1 ;
264
+ uint8_t c4 = _address.bytes [f * 2 + 1 ] & 0xf ;
265
+ if (c1 > 0 ) {
266
+ n += p.print (c1 < 10 ? ' 0' + c1 : ' a' + c1 - 10 );
267
+ }
268
+ if (c1 > 0 || c2 > 0 ) {
269
+ n += p.print (c2 < 10 ? ' 0' + c2 : ' a' + c2 - 10 );
270
+ }
271
+ if (c1 > 0 || c2 > 0 || c3 > 0 ) {
272
+ n += p.print (c3 < 10 ? ' 0' + c3 : ' a' + c3 - 10 );
273
+ }
274
+ n += p.print (c4 < 10 ? ' 0' + c4 : ' a' + c4 - 10 );
275
+ if (f < 7 ) {
276
+ n += p.print (' :' );
277
+ }
278
+ } else if (f == longest_start) {
279
+ n += p.print (' :' );
280
+ }
281
+ }
282
+ return n;
283
+ }
284
+
285
+ // IPv4
118
286
for (int i =0 ; i < 3 ; i++)
119
287
{
120
- n += p.print (_address.bytes [i], DEC);
288
+ n += p.print (_address.bytes [12 + i], DEC);
121
289
n += p.print (' .' );
122
290
}
123
- n += p.print (_address.bytes [3 ], DEC);
291
+ n += p.print (_address.bytes [15 ], DEC);
124
292
return n;
125
293
}
126
294
295
+ const IPAddress arduino::IN6ADDR_ANY (IPv6);
127
296
const IPAddress arduino::INADDR_NONE (0 ,0 ,0 ,0 );
0 commit comments