2020#include < Arduino.h>
2121#include < IPAddress.h>
2222#include < Print.h>
23+ #include < StreamString.h>
2324
24- IPAddress::IPAddress ()
25+ IPAddress::IPAddress () : IPAddress(IPv4) {}
26+
27+ IPAddress::IPAddress (IPType ip_type)
2528{
26- _address.dword = 0 ;
29+ _type = ip_type;
30+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
2731}
2832
2933IPAddress::IPAddress (uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
3034{
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;
3561}
3662
3763IPAddress::IPAddress (uint32_t address)
3864{
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+ }
4090}
4191
42- IPAddress::IPAddress (const uint8_t *address)
92+ IPAddress::IPAddress (const char *address)
4393{
44- memcpy (_address. bytes , address, sizeof (_address. bytes ) );
94+ fromString ( address);
4595}
4696
4797IPAddress& IPAddress::operator =(const uint8_t *address)
4898{
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);
50109 return *this ;
51110}
52111
53112IPAddress& IPAddress::operator =(uint32_t address)
54113{
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;
56119 return *this ;
57120}
58121
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+
59128bool IPAddress::operator ==(const uint8_t * addr) const
60129{
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];
62147}
63148
64149size_t IPAddress::printTo (Print& p) const
65150{
66151 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);
69208 n += p.print (' .' );
70209 }
71- n += p.print (_address.bytes [3 ], DEC);
210+ n += p.print (_address.bytes [IPADDRESS_V4_BYTES_INDEX + 3 ], DEC);
72211 return n;
73212}
74213
75- String IPAddress::toString () const
214+ String IPAddress::toString4 () const
76215{
77216 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 ]);
79218 return String (szRet);
80219}
81220
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+
82238bool 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)
83248{
84249 // TODO: add support for "a", "a.b", "a.b.c" formats
85250
86- uint16_t acc = 0 ; // Accumulator
251+ int16_t acc = - 1 ; // Accumulator
87252 uint8_t dots = 0 ;
88253
254+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
89255 while (*address)
90256 {
91257 char c = *address++;
92258 if (c >= ' 0' && c <= ' 9' )
93259 {
94- acc = acc * 10 + (c - ' 0' );
260+ acc = (acc < 0 ) ? (c - ' 0 ' ) : acc * 10 + (c - ' 0' );
95261 if (acc > 255 ) {
96262 // Value out of [0..255] range
97263 return false ;
@@ -100,11 +266,15 @@ bool IPAddress::fromString(const char *address)
100266 else if (c == ' .' )
101267 {
102268 if (dots == 3 ) {
103- // Too much dots (there must be 3 dots)
269+ // Too many dots (there must be 3 dots)
104270 return false ;
105271 }
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 ;
108278 }
109279 else
110280 {
@@ -117,7 +287,80 @@ bool IPAddress::fromString(const char *address)
117287 // Too few dots (there must be 3 dots)
118288 return false ;
119289 }
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;
121364 return true ;
122365}
123366
0 commit comments