Skip to content

Commit d84f4be

Browse files
committed
Added support for shortened form ipv6 addresses
supported: 1.2.3.4 1:2:3:4:5:6:7:8 1:2::7:8 :: currently not supported: 1:2:3:4:5:6:1.2.3.4
1 parent 3fa1bb6 commit d84f4be

File tree

1 file changed

+61
-31
lines changed

1 file changed

+61
-31
lines changed

SocketAddress.cpp

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
#include <string.h>
2020
#include "mbed.h"
2121

22-
static bool address_is_ipv4(const char *addr)
22+
23+
static bool ipv4_is_valid(const char *addr)
2324
{
2425
int i = 0;
2526

@@ -38,7 +39,7 @@ static bool address_is_ipv4(const char *addr)
3839
return true;
3940
}
4041

41-
static bool address_is_ipv6(const char *addr)
42+
static bool ipv6_is_valid(const char *addr)
4243
{
4344
// Check each digit for [0-9a-fA-F:]
4445
for (int i = 0; addr[i]; i++) {
@@ -53,20 +54,57 @@ static bool address_is_ipv6(const char *addr)
5354
return true;
5455
}
5556

56-
static void address_to_ipv4(uint8_t *bytes, const char *addr)
57+
static void ipv4_from_address(uint8_t *bytes, const char *addr)
5758
{
58-
sscanf(addr, "%hhd.%hhd.%hhd.%hhd", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);
59+
sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);
60+
}
61+
62+
static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
63+
int count = 0;
64+
int i = 0;
65+
66+
for (; count < NSAPI_IPv6_BYTES/2; count++) {
67+
int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
68+
if (scanned < 1) {
69+
return count;
70+
}
71+
72+
for (; chunk[i] != ':'; i++) {
73+
if (!chunk[i]) {
74+
return count+1;
75+
}
76+
}
77+
78+
i++;
79+
}
80+
81+
return count;
5982
}
6083

61-
static void address_to_ipv6(uint8_t *bytes, const char *addr)
84+
static void ipv6_from_address(uint8_t *bytes, const char *addr)
6285
{
63-
// TODO support short form (::1, 2001::ffee:100a)
64-
// Use a more intellegent algorithm
86+
// Start with zeroed address
6587
uint16_t shorts[NSAPI_IPv6_BYTES/2];
66-
sscanf(addr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
67-
&shorts[0], &shorts[1], &shorts[2], &shorts[3],
68-
&shorts[4], &shorts[5], &shorts[6], &shorts[7]);
88+
memset(shorts, 0, sizeof shorts);
6989

90+
int suffix = 0;
91+
92+
// Find double colons and scan suffix
93+
for (int i = 0; addr[i]; i++) {
94+
if (addr[i] == ':' && addr[i+1] == ':') {
95+
suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
96+
break;
97+
}
98+
}
99+
100+
// Move suffix to end
101+
memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
102+
suffix*sizeof(uint16_t));
103+
104+
// Scan prefix
105+
ipv6_scan_chunk(shorts, &addr[0]);
106+
107+
// Flip bytes
70108
for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
71109
bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
72110
bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
@@ -80,31 +118,23 @@ static void ipv4_to_address(char *addr, const uint8_t *bytes)
80118

81119
static void ipv6_to_address(char *addr, const uint8_t *bytes)
82120
{
83-
int pos = 0;
84-
for (int i = 0; i < NSAPI_IPv6_BYTES; i+=2) {
85-
int ret = sprintf(&addr[pos], "%02x%02x", bytes[i], bytes[i+1]);
86-
if (ret < 0) {
87-
memset(addr, 0, NSAPI_IPv6_SIZE + 1);
88-
return;
89-
}
90-
pos += ret;
91-
92-
addr[pos++] = ':';
121+
for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
122+
sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
123+
addr[5*i+4] = ':';
93124
}
94-
pos -= 1; // Overwrite last ':'
95-
addr[pos++] = '\0';
96-
MBED_ASSERT(NSAPI_IPv6_SIZE == pos);
125+
addr[NSAPI_IPv6_SIZE-1] = '\0';
97126
}
98127

128+
99129
SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port)
100130
{
101131
// Check for valid IP addresses
102-
if (host && address_is_ipv4(host)) {
132+
if (host && ipv4_is_valid(host)) {
103133
_ip_version = NSAPI_IPv4;
104-
address_to_ipv4(_ip_bytes, host);
105-
} else if (host && address_is_ipv6(host)) {
134+
ipv4_from_address(_ip_bytes, host);
135+
} else if (host && ipv6_is_valid(host)) {
106136
_ip_version = NSAPI_IPv6;
107-
address_to_ipv4(_ip_bytes, host);
137+
ipv4_from_address(_ip_bytes, host);
108138
} else {
109139
// DNS lookup
110140
int err = iface->gethostbyname(this, host);
@@ -140,12 +170,12 @@ void SocketAddress::set_ip_address(const char *addr)
140170
{
141171
_ip_address[0] = '\0';
142172

143-
if (addr && address_is_ipv4(addr)) {
173+
if (addr && ipv4_is_valid(addr)) {
144174
_ip_version = NSAPI_IPv4;
145-
address_to_ipv4(_ip_bytes, addr);
146-
} else if (addr && address_is_ipv6(addr)) {
175+
ipv4_from_address(_ip_bytes, addr);
176+
} else if (addr && ipv6_is_valid(addr)) {
147177
_ip_version = NSAPI_IPv6;
148-
address_to_ipv6(_ip_bytes, addr);
178+
ipv6_from_address(_ip_bytes, addr);
149179
} else {
150180
_ip_version = NSAPI_IPv4;
151181
memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);

0 commit comments

Comments
 (0)