NetworkSocketAPI

Dependencies:   DnsQuery

Dependents:   HelloWizFi250Interface

Fork of NetworkSocketAPI by NetworkSocketAPI

Revision:
100:90d8f662de83
Parent:
97:68232387bc75
Child:
105:2fd212f8da61
--- a/SocketAddress.cpp	Tue Apr 19 18:25:12 2016 -0500
+++ b/SocketAddress.cpp	Tue Apr 19 18:25:23 2016 -0500
@@ -19,7 +19,8 @@
 #include <string.h>
 #include "mbed.h"
 
-static bool address_is_ipv4(const char *addr)
+
+static bool ipv4_is_valid(const char *addr)
 {
     int i = 0;
 
@@ -38,7 +39,7 @@
     return true;
 }
 
-static bool address_is_ipv6(const char *addr)
+static bool ipv6_is_valid(const char *addr)
 {
     // Check each digit for [0-9a-fA-F:]
     for (int i = 0; addr[i]; i++) {
@@ -53,20 +54,57 @@
     return true;
 }
 
-static void address_to_ipv4(uint8_t *bytes, const char *addr)
+static void ipv4_from_address(uint8_t *bytes, const char *addr)
 {
-    sscanf(addr, "%hhd.%hhd.%hhd.%hhd", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);
+    sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);
 }
 
-static void address_to_ipv6(uint8_t *bytes, const char *addr)
+static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
+    int count = 0;
+    int i = 0;
+
+    for (; count < NSAPI_IPv6_BYTES/2; count++) {
+        int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
+        if (scanned < 1) {
+            return count;
+        }
+
+        for (; chunk[i] != ':'; i++) {
+            if (!chunk[i]) {
+                return count+1;
+            }
+        }
+
+        i++;
+    }
+
+    return count;
+}
+
+static void ipv6_from_address(uint8_t *bytes, const char *addr)
 {
-    // TODO support short form (::1, 2001::ffee:100a)
-    // Use a more intellegent algorithm
+    // Start with zeroed address
     uint16_t shorts[NSAPI_IPv6_BYTES/2];
-    sscanf(addr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
-            &shorts[0], &shorts[1], &shorts[2], &shorts[3],
-            &shorts[4], &shorts[5], &shorts[6], &shorts[7]);
+    memset(shorts, 0, sizeof shorts);
+
+    int suffix = 0;
 
+    // Find double colons and scan suffix
+    for (int i = 0; addr[i]; i++) {
+        if (addr[i] == ':' && addr[i+1] == ':') {
+            suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
+            break;
+        }
+    }
+
+    // Move suffix to end
+    memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
+            suffix*sizeof(uint16_t));
+
+    // Scan prefix
+    ipv6_scan_chunk(shorts, &addr[0]);
+
+    // Flip bytes
     for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
         bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
         bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
@@ -80,31 +118,23 @@
 
 static void ipv6_to_address(char *addr, const uint8_t *bytes)
 {
-    int pos = 0;
-    for (int i = 0; i < NSAPI_IPv6_BYTES; i+=2) {
-        int ret = sprintf(&addr[pos], "%02x%02x", bytes[i], bytes[i+1]);
-        if (ret < 0) {
-            memset(addr, 0, NSAPI_IPv6_SIZE + 1);
-            return;
-        }
-        pos += ret;
+    for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
+        sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
+        addr[5*i+4] = ':';
+    }
+    addr[NSAPI_IPv6_SIZE-1] = '\0';
+}
 
-        addr[pos++] = ':';
-    }
-    pos -= 1; // Overwrite last ':'
-    addr[pos++] = '\0';
-    MBED_ASSERT(NSAPI_IPv6_SIZE == pos);
-}
 
 SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port)
 {
     // Check for valid IP addresses
-    if (host && address_is_ipv4(host)) {
+    if (host && ipv4_is_valid(host)) {
         _ip_version = NSAPI_IPv4;
-        address_to_ipv4(_ip_bytes, host);
-    } else if (host && address_is_ipv6(host)) {
+        ipv4_from_address(_ip_bytes, host);
+    } else if (host && ipv6_is_valid(host)) {
         _ip_version = NSAPI_IPv6;
-        address_to_ipv4(_ip_bytes, host);
+        ipv4_from_address(_ip_bytes, host);
     } else {
         // DNS lookup
         int err = iface->gethostbyname(this, host);
@@ -140,12 +170,12 @@
 {
     _ip_address[0] = '\0';
 
-    if (addr && address_is_ipv4(addr)) {
+    if (addr && ipv4_is_valid(addr)) {
         _ip_version = NSAPI_IPv4;
-        address_to_ipv4(_ip_bytes, addr);
-    } else if (addr && address_is_ipv6(addr)) {
+        ipv4_from_address(_ip_bytes, addr);
+    } else if (addr && ipv6_is_valid(addr)) {
         _ip_version = NSAPI_IPv6;
-        address_to_ipv6(_ip_bytes, addr);
+        ipv6_from_address(_ip_bytes, addr);
     } else {
         _ip_version = NSAPI_IPv4;
         memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);