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
Christopher Haster 2016-03-13 16:49:18 -05:00 committed by Russ Butler
parent 455f023949
commit 62bb777c1f
3 changed files with 245 additions and 33 deletions

View File

@ -20,6 +20,7 @@
#include "mbed.h"
#include "SocketAddress.h"
/** Enum of standardized error codes
* @enum ns_error_t
*/
@ -50,6 +51,15 @@ enum nsapi_protocol_t {
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.

View File

@ -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 @@ SocketAddress::SocketAddress(const char *addr, uint16_t port)
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 @@ void SocketAddress::set_port(uint16_t port)
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;
}

View File

@ -19,64 +19,118 @@
#include <stdint.h>
/** Maximum size of IP address
*/
#define NSAPI_IP_SIZE 16
/** Maximum size of MAC address
*/
#define NSAPI_MAC_SIZE 18
/** 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
/** 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;
};