2222
2323using namespace arduino ;
2424
25- IPAddress::IPAddress ()
25+ IPAddress::IPAddress () : IPAddress(IPv4) {}
26+
27+ IPAddress::IPAddress (IPType ip_type)
2628{
27- _address.dword = 0 ;
29+ _type = ip_type;
30+ memset (_address.bytes , 0 , sizeof (_address.bytes ));
2831}
2932
3033IPAddress::IPAddress (uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
3134{
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;
3641}
3742
3843IPAddress::IPAddress (uint32_t address)
3944{
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 .
4157}
4258
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)
4462{
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 ;
4677}
4778
48- bool IPAddress::fromString (const char *address)
79+ bool IPAddress::fromString4 (const char *address)
4980{
5081 // TODO: add support for "a", "a.b", "a.b.c" formats
5182
@@ -73,7 +104,7 @@ bool IPAddress::fromString(const char *address)
73104 /* No value between dots, e.g. '1..' */
74105 return false ;
75106 }
76- _address.bytes [dots++] = acc;
107+ _address.bytes [12 + dots++] = acc;
77108 acc = -1 ;
78109 }
79110 else
@@ -91,37 +122,175 @@ bool IPAddress::fromString(const char *address)
91122 /* No value between dots, e.g. '1..' */
92123 return false ;
93124 }
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;
95183 return true ;
96184}
97185
98186IPAddress& IPAddress::operator =(const uint8_t *address)
99187{
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 ));
101192 return *this ;
102193}
103194
104195IPAddress& IPAddress::operator =(uint32_t address)
105196{
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;
107204 return *this ;
108205}
109206
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+
110212bool IPAddress::operator ==(const uint8_t * addr) const
111213{
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 ;
113217}
114218
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+
115233size_t IPAddress::printTo (Print& p) const
116234{
117235 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
118286 for (int i =0 ; i < 3 ; i++)
119287 {
120- n += p.print (_address.bytes [i], DEC);
288+ n += p.print (_address.bytes [12 + i], DEC);
121289 n += p.print (' .' );
122290 }
123- n += p.print (_address.bytes [3 ], DEC);
291+ n += p.print (_address.bytes [15 ], DEC);
124292 return n;
125293}
126294
295+ const IPAddress arduino::IN6ADDR_ANY (IPv6);
127296const IPAddress arduino::INADDR_NONE (0 ,0 ,0 ,0 );
0 commit comments