NetworkSocketAPI
Dependents: HelloWizFi250Interface
Fork of NetworkSocketAPI by
Revision 94:644df37bb05b, committed 2016-04-19
- 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
--- 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; };