NetworkSocketAPI

Dependencies:   DnsQuery

Dependents:   HelloWizFi250Interface

Fork of NetworkSocketAPI by NetworkSocketAPI

Files at this revision

API Documentation at this revision

Comitter:
Christopher Haster
Date:
Tue Apr 19 18:23:58 2016 -0500
Parent:
93:65a9f84862f0
Child:
95:b3c679f20d13
Commit message:
Added support for storing bytes directly in SocketAddress

Bytes are stored by default, however enough space is allocated in
a SocketAddress to generate the string representation if necessary.

Currently there is no support for shortened addresses

Changed in this revision

NetworkInterface.h Show annotated file Show diff for this revision Revisions of this file
SocketAddress.cpp Show annotated file Show diff for this revision Revisions of this file
SocketAddress.h Show annotated file Show diff for this revision Revisions of this file
--- a/NetworkInterface.h	Tue Apr 19 18:23:42 2016 -0500
+++ b/NetworkInterface.h	Tue Apr 19 18:23:58 2016 -0500
@@ -20,6 +20,7 @@
 #include "mbed.h"
 #include "SocketAddress.h"
 
+
 /** Enum of standardized error codes
  *  @enum ns_error_t
  */
@@ -50,6 +51,15 @@
    NSAPI_UDP, /*!< Socket is of UDP type */
 };
 
+/** Maximum size of MAC address representation
+ */
+#define NSAPI_MAC_SIZE 18
+
+/** Maximum number of bytes for MAC address
+ */
+#define NSAPI_MAC_BYTES 6
+
+
 /** NetworkInterface class
  *  Common interface that is shared between all hardware that
  *  can connect to a network over IP.
--- a/SocketAddress.cpp	Tue Apr 19 18:23:42 2016 -0500
+++ b/SocketAddress.cpp	Tue Apr 19 18:23:58 2016 -0500
@@ -19,14 +19,95 @@
 #include <string.h>
 #include "mbed.h"
 
+static bool address_is_ipv4(const char *addr)
+{
+    int i = 0;
+
+    // Check each digit for [0-9.]
+    for (; addr[i]; i++) {
+        if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') {
+            return false;
+        }
+    }
+
+    // Ending with '.' garuntees host
+    if (i > 0 && addr[i-1] == '.') {
+        return false;
+    }
+
+    return true;
+}
+
+static bool address_is_ipv6(const char *addr)
+{
+    // Check each digit for [0-9a-fA-F:]
+    for (int i = 0; addr[i]; i++) {
+        if (!(addr[i] >= '0' && addr[i] <= '9') &&
+            !(addr[i] >= 'a' && addr[i] <= 'f') &&
+            !(addr[i] >= 'A' && addr[i] <= 'F') &&
+            addr[i] != ':') {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void address_to_ipv4(uint8_t *bytes, const char *addr)
+{
+    sscanf(addr, "%hhd.%hhd.%hhd.%hhd", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);
+}
+
+static void address_to_ipv6(uint8_t *bytes, const char *addr)
+{
+    // TODO support short form (::1, 2001::ffee:100a)
+    // Use a more intellegent algorithm
+    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]);
+
+    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);
+    }
+}
+
+static void ipv4_to_address(char *addr, const uint8_t *bytes)
+{
+    sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
+}
+
+static void ipv6_to_address(char *addr, const uint8_t *bytes)
+{
+    for (int i = 0; i < NSAPI_IPv6_BYTES; i+=2) {
+        sprintf(&addr[5*i], "%02x%02x", bytes[i], bytes[i+1]);
+        addr[5*i+4] = ':';
+    }
+    addr[NSAPI_IPv6_BYTES-1] = '\0';
+}
+
 SocketAddress::SocketAddress(NetworkInterface *iface, const char *host, uint16_t port)
 {
-    int err = iface->gethostbyname(host, _ip_address);
-    set_port(port);
-
-    if (err) {
-        _ip_address[0] = '\0';
-        _port = 0;
+    // Check for valid IP addresses
+    if (host && address_is_ipv4(host)) {
+        _ip_version = NSAPI_IPv4;
+        address_to_ipv4(_ip_bytes, host);
+    } else if (host && address_is_ipv6(host)) {
+        _ip_version = NSAPI_IPv6;
+        address_to_ipv4(_ip_bytes, host);
+    } else {
+        // DNS lookup
+        char addr[NSAPI_IP_SIZE];
+        int err = iface->gethostbyname(host, addr);
+        if (!err) {
+            set_ip_address(addr);
+            set_port(port);
+        } else {
+            _ip_version = NSAPI_IPv4;
+            memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
+            set_port(0);
+        }
     }
 }
 
@@ -36,16 +117,48 @@
     set_port(port);
 }
 
+SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
+{
+    set_ip_bytes(bytes, version);
+    set_port(port);
+}
+
 SocketAddress::SocketAddress(const SocketAddress &addr)
 {
-    set_ip_address(addr.get_ip_address());
+    set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version());
     set_port(addr.get_port());
 }
 
 void SocketAddress::set_ip_address(const char *addr)
 {
-    strncpy(_ip_address, addr, sizeof _ip_address);
-    _ip_address[sizeof _ip_address - 1] = '\0';
+    _ip_address[0] = '\0';
+
+    if (addr && address_is_ipv4(addr)) {
+        _ip_version = NSAPI_IPv4;
+        address_to_ipv4(_ip_bytes, addr);
+    } else if (addr && address_is_ipv6(addr)) {
+        _ip_version = NSAPI_IPv6;
+        address_to_ipv4(_ip_bytes, addr);
+    } else {
+        _ip_version = NSAPI_IPv4;
+        memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
+    }
+}
+
+void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
+{
+    _ip_address[0] = '\0';
+
+    if (_ip_version == NSAPI_IPv4) {
+        _ip_version = NSAPI_IPv4;
+        memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES);
+    } else if (_ip_version == NSAPI_IPv6) {
+        _ip_version = NSAPI_IPv6;
+        memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES);
+    } else {
+        _ip_version = NSAPI_IPv4;
+        memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
+    }
 }
 
 void SocketAddress::set_port(uint16_t port)
@@ -55,13 +168,48 @@
 
 const char *SocketAddress::get_ip_address() const
 {
-    if (!_ip_address[0]) {
-        return 0;
+    char *ip_address = (char *)_ip_address;
+
+    if (!ip_address[0]) {
+        if (_ip_version == NSAPI_IPv4) {
+            ipv4_to_address(ip_address, _ip_bytes);
+        } else if (_ip_version == NSAPI_IPv4) {
+            ipv6_to_address(ip_address, _ip_bytes);
+        }
     }
-    return _ip_address;
+
+    return ip_address;
+}
+
+const void *SocketAddress::get_ip_bytes() const
+{
+    return _ip_bytes;
+}
+
+nsapi_version_t SocketAddress::get_ip_version() const
+{
+    return _ip_version;
 }
 
 uint16_t SocketAddress::get_port() const
 {
     return _port;
 }
+
+SocketAddress::operator bool() const
+{
+    int count = 0;
+    if (_ip_version == NSAPI_IPv4) {
+        count = NSAPI_IPv4_BYTES;
+    } else if (_ip_version == NSAPI_IPv6) {
+        count = NSAPI_IPv6_BYTES;
+    }
+
+    for (int i = 0; i < count; i++) {
+        if (_ip_bytes[i]) {
+            return true;
+        }
+    }
+
+    return false;
+}
--- a/SocketAddress.h	Tue Apr 19 18:23:42 2016 -0500
+++ b/SocketAddress.h	Tue Apr 19 18:23:58 2016 -0500
@@ -19,64 +19,118 @@
 
 #include <stdint.h>
 
-/** Maximum size of IP address
-*/
-#define NSAPI_IP_SIZE 16
+
+/** Maximum size of IP address representation
+ */
+#define NSAPI_IP_SIZE NSAPI_IPv6_SIZE
+
+/** Maximum number of bytes for IP address
+ */
+#define NSAPI_IP_BYTES NSAPI_IPv6_BYTES
 
-/** Maximum size of MAC address
-*/
-#define NSAPI_MAC_SIZE 18
+/** Enum of address families
+ *  @enum nsapi_family_t
+ */
+enum nsapi_version_t {
+    NSAPI_IPv4, /*!< Address is IPv4 */
+    NSAPI_IPv6, /*!< Address is IPv6 */
+};
+
+/** Size of IPv4 representation
+ */
+#define NSAPI_IPv4_SIZE 16
+
+/** Number of bytes in IPv4 address
+ */
+#define NSAPI_IPv4_BYTES 4
+
+/** Size of IPv6 representation
+ */
+#define NSAPI_IPv6_SIZE 40
+
+/** Number of bytes in IPv6 address
+ */
+#define NSAPI_IPv6_BYTES 16
 
 // Predeclared classes
 class NetworkInterface;
 
-/**
- * A general socket address composed of the IP address and port
+
+/** A general address class composed of the IP address and optional port
  */
 class SocketAddress {
 public:
     /** SocketAddress construction using DNS resolution
-     * @param iface NetworkInterface to use for DNS resolution
-     * @param addr  Null-terminated hostname that will be resolved
-     * @param port  16-bit port
-     * @note on failure, IP address and port will be set to null
+     *  @param iface    NetworkInterface to use for DNS resolution
+     *  @param addr     Null-terminated hostname that will be resolved
+     *  @param port     Optional 16-bit port
+     *  @note on failure, IP address and port will be set to zero
      */
     SocketAddress(NetworkInterface *iface, const char *addr, uint16_t port = 0);
 
     /** SocketAddress construction
-     * @param addr  Null-terminated IP address
-     * @param port  16-bit port
-     * @note on failure, IP address and port will be set to null
+     *  @param addr     Null-terminated IP address
+     *  @param port     Optional 16-bit port
      */
     SocketAddress(const char *addr = 0, uint16_t port = 0);
 
     /** SocketAddress construction
-     * @param addr  SocketAddress to copy
+     *  @param bytes    Bytes to assign to address in big-endian order
+     *  @param version  IP address version, NSAPI_IPv4 or NSAPI_IPv6
+     *  @param port     Optional 16-bit port
+     */
+    SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port = 0);
+
+    /** SocketAddress construction
+     *  @param addr     SocketAddress to copy
      */
     SocketAddress(const SocketAddress &addr);
    
     /** Set the IP address
-     * @param addr  Null-terminated string representing the IP address
+     *  @param addr     Null-terminated string representing the IP address
      */
     void set_ip_address(const char *addr);
 
+    /** Set the IP address bytes directly
+     *  @param bytes    Bytes to assign to address in big-endian order
+     *  @param version  IP address version, NSAPI_IPv4 or NSAPI_IPv6
+     */
+    void set_ip_bytes(const void *bytes, nsapi_version_t version);
+
     /** Set the port
-     * @param port  16-bit port
+     *  @param port     16-bit port
      */
     void set_port(uint16_t port);
     
     /** Get the IP address
-     * @return      The string representation of the IP Address
+     *  @return         The string representation of the IP Address
      */
     const char *get_ip_address() const;
+
+    /** Get the IP address bytes directly
+     *  @return         IP address bytes
+     */
+    const void *get_ip_bytes() const;
+
+    /** Get the type of the IP address
+     *  @return         IP address version, NSAPI_IPv4 or NSAPI_IPv6
+     */
+    nsapi_version_t get_ip_version() const;
     
     /** Get the port
-     * @return      The 16-bit port
+     *  @return         The 16-bit port
      */
-    uint16_t get_port(void) const;
+    uint16_t get_port() const;
+
+    /** Determine if address is all zeros
+     *  @return         True if address is not zero address
+     */
+    operator bool() const;
 
 private:
     char _ip_address[NSAPI_IP_SIZE];
+    uint8_t _ip_bytes[NSAPI_IP_BYTES];
+    nsapi_version_t _ip_version;
     uint16_t _port;
 };