diff --git a/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c b/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c index 61c2ffdb6f2..00c140f440c 100644 --- a/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c +++ b/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c @@ -273,7 +273,7 @@ static int lwip_err_remap(err_t err) { /* LWIP network stack implementation */ -static int lwip_gethostbyname(nsapi_stack_t *stack, nsapi_addr_t *addr, const char *host) +static int lwip_gethostbyname(nsapi_stack_t *stack, const char *host, nsapi_addr_t *addr) { err_t err = netconn_gethostbyname(host, (ip_addr_t *)addr->bytes); if (err != ERR_OK) { diff --git a/features/net/network-socket/NetworkInterface.cpp b/features/net/network-socket/NetworkInterface.cpp index 4effce5c099..163231eefc8 100644 --- a/features/net/network-socket/NetworkInterface.cpp +++ b/features/net/network-socket/NetworkInterface.cpp @@ -15,9 +15,11 @@ */ #include "network-socket/NetworkInterface.h" +#include "network-socket/NetworkStack.h" #include +// Default network-interface state const char *NetworkInterface::get_mac_address() { return 0; @@ -52,3 +54,19 @@ int NetworkInterface::set_dhcp(bool dhcp) } } +// DNS operations go through the underlying stack by default +int NetworkInterface::gethostbyname(const char *name, SocketAddress *address) +{ + return get_stack()->gethostbyname(name, address); +} + +int NetworkInterface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version) +{ + return get_stack()->gethostbyname(name, address, version); +} + +int NetworkInterface::add_dns_server(const SocketAddress &address) +{ + return get_stack()->add_dns_server(address); +} + diff --git a/features/net/network-socket/NetworkInterface.h b/features/net/network-socket/NetworkInterface.h index 0757dea1307..92e8eb4693e 100644 --- a/features/net/network-socket/NetworkInterface.h +++ b/features/net/network-socket/NetworkInterface.h @@ -18,6 +18,7 @@ #define NETWORK_INTERFACE_H #include "network-socket/nsapi_types.h" +#include "network-socket/SocketAddress.h" // Predeclared class class NetworkStack; @@ -99,6 +100,42 @@ class NetworkInterface { */ virtual int disconnect() = 0; + /** Translates a hostname to an IP address + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param address Destination for the host SocketAddress + * @param host Hostname to resolve + * @return 0 on success, negative error code on failure + */ + virtual int gethostbyname(const char *host, SocketAddress *address); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param address Destination for the host SocketAddress + * @param host Hostname to resolve + * @param version IP version of address to resolve + * @return 0 on success, negative error code on failure + */ + virtual int gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version); + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + virtual int add_dns_server(const SocketAddress &address); + protected: friend class Socket; friend class UDPSocket; diff --git a/features/net/network-socket/NetworkStack.cpp b/features/net/network-socket/NetworkStack.cpp index b9c39afd7cc..009bdbfae3b 100644 --- a/features/net/network-socket/NetworkStack.cpp +++ b/features/net/network-socket/NetworkStack.cpp @@ -22,9 +22,33 @@ // Default NetworkStack operations -int NetworkStack::gethostbyname(SocketAddress *address, const char *name) +int NetworkStack::gethostbyname(const char *name, SocketAddress *address) { - return nsapi_dns_query(this, address, name); + // check for simple ip addresses + if (address->set_ip_address(name)) { + return 0; + } + + return nsapi_dns_query(this, name, address); +} + +int NetworkStack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version) +{ + // check for simple ip addresses + if (address->set_ip_address(name)) { + if (address->get_ip_version() != version) { + return NSAPI_ERROR_DNS_FAILURE; + } + + return 0; + } + + return nsapi_dns_query(this, name, address, version); +} + +int NetworkStack::add_dns_server(const SocketAddress &address) +{ + return nsapi_dns_add_server(address); } int NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen) @@ -76,18 +100,27 @@ class NetworkStackWrapper : public NetworkStack return address->get_ip_address(); } - virtual int gethostbyname(SocketAddress *address, const char *name) + virtual int gethostbyname(const char *name, SocketAddress *address) { if (!_stack_api()->gethostbyname) { - return NetworkStack::gethostbyname(address, name); + return NetworkStack::gethostbyname(name, address); } nsapi_addr_t addr = {NSAPI_IPv4, 0}; - int err = _stack_api()->gethostbyname(_stack(), &addr, name); + int err = _stack_api()->gethostbyname(_stack(), name, &addr); address->set_addr(addr); return err; } + virtual int add_dns_server(const SocketAddress &address) + { + if (!_stack_api()->add_dns_server) { + return NetworkStack::add_dns_server(address); + } + + return _stack_api()->add_dns_server(_stack(), address.get_addr()); + } + virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen) { if (!_stack_api()->setstackopt) { diff --git a/features/net/network-socket/NetworkStack.h b/features/net/network-socket/NetworkStack.h index aff3541c6f7..123f8d29046 100644 --- a/features/net/network-socket/NetworkStack.h +++ b/features/net/network-socket/NetworkStack.h @@ -45,15 +45,37 @@ class NetworkStack * * The hostname may be either a domain name or an IP address. If the * hostname is an IP address, no network transactions will be performed. - * + * * If no stack-specific DNS resolution is provided, the hostname - * will be resolve using a UDP socket on the stack. + * will be resolve using a UDP socket on the stack. * + * @param host Hostname to resolve * @param address Destination for the host SocketAddress + * @return 0 on success, negative error code on failure + */ + virtual int gethostbyname(const char *host, SocketAddress *address); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * * @param host Hostname to resolve + * @param address Destination for the host SocketAddress + * @param version IP version of address to resolve + * @return 0 on success, negative error code on failure + */ + virtual int gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version); + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address * @return 0 on success, negative error code on failure */ - virtual int gethostbyname(SocketAddress *address, const char *host); + virtual int add_dns_server(const SocketAddress &address); /* Set stack-specific stack options * @@ -66,7 +88,7 @@ class NetworkStack * @param optval Option value * @param optlen Length of the option value * @return 0 on success, negative error code on failure - */ + */ virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen); /* Get stack-specific stack options @@ -80,7 +102,7 @@ class NetworkStack * @param optval Destination for option value * @param optlen Length of the option value * @return 0 on success, negative error code on failure - */ + */ virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen); protected: @@ -260,7 +282,7 @@ class NetworkStack * @param optval Option value * @param optlen Length of the option value * @return 0 on success, negative error code on failure - */ + */ virtual int setsockopt(nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen); /* Get stack-specific socket options @@ -275,7 +297,7 @@ class NetworkStack * @param optval Destination for option value * @param optlen Length of the option value * @return 0 on success, negative error code on failure - */ + */ virtual int getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen); }; diff --git a/features/net/network-socket/SocketAddress.cpp b/features/net/network-socket/SocketAddress.cpp index ccb3f733041..93ca75ccfcf 100644 --- a/features/net/network-socket/SocketAddress.cpp +++ b/features/net/network-socket/SocketAddress.cpp @@ -43,6 +43,8 @@ static bool ipv4_is_valid(const char *addr) static bool ipv6_is_valid(const char *addr) { // Check each digit for [0-9a-fA-F:] + // Must also have at least 2 colons + int colons = 0; for (int i = 0; addr[i]; i++) { if (!(addr[i] >= '0' && addr[i] <= '9') && !(addr[i] >= 'a' && addr[i] <= 'f') && @@ -50,9 +52,12 @@ static bool ipv6_is_valid(const char *addr) addr[i] != ':') { return false; } + if (addr[i] == ':') { + colons++; + } } - return true; + return colons >= 2; } static void ipv4_from_address(uint8_t *bytes, const char *addr) @@ -171,18 +176,21 @@ SocketAddress::SocketAddress(const SocketAddress &addr) set_port(addr.get_port()); } -void SocketAddress::set_ip_address(const char *addr) +bool SocketAddress::set_ip_address(const char *addr) { _ip_address[0] = '\0'; if (addr && ipv4_is_valid(addr)) { _addr.version = NSAPI_IPv4; ipv4_from_address(_addr.bytes, addr); + return true; } else if (addr && ipv6_is_valid(addr)) { _addr.version = NSAPI_IPv6; ipv6_from_address(_addr.bytes, addr); + return true; } else { _addr = nsapi_addr_t(); + return false; } } @@ -292,7 +300,7 @@ void SocketAddress::_SocketAddress(NetworkStack *iface, const char *host, uint16 _port = port; } else { // DNS lookup - int err = iface->gethostbyname(this, host); + int err = iface->gethostbyname(host, this); _port = port; if (err) { _addr = nsapi_addr_t(); diff --git a/features/net/network-socket/SocketAddress.h b/features/net/network-socket/SocketAddress.h index 9f1a81e1367..a0f91a5afd5 100644 --- a/features/net/network-socket/SocketAddress.h +++ b/features/net/network-socket/SocketAddress.h @@ -41,8 +41,14 @@ class SocketAddress { * @param stack Network stack to use for DNS resolution * @param host Hostname to resolve * @param port Optional 16-bit port + * @deprecated + * Constructors hide possible errors. Replaced by + * NetworkInterface::gethostbyname. */ template + MBED_DEPRECATED_SINCE("mbed-os-5.1.3", + "Constructors hide possible errors. Replaced by " + "NetworkInterface::gethostbyname.") SocketAddress(S *stack, const char *host, uint16_t port = 0) { _SocketAddress(nsapi_create_stack(stack), host, port); @@ -79,8 +85,10 @@ class SocketAddress { /** Set the IP address * * @param addr Null-terminated represention of the IP address + * @return True if address is a valid representation of an IP address, + * otherwise False and SocketAddress is set to null */ - void set_ip_address(const char *addr); + bool set_ip_address(const char *addr); /** Set the raw IP bytes and IP version * diff --git a/features/net/network-socket/TCPSocket.cpp b/features/net/network-socket/TCPSocket.cpp index 7a1d3893d7e..2c0f18d65c5 100644 --- a/features/net/network-socket/TCPSocket.cpp +++ b/features/net/network-socket/TCPSocket.cpp @@ -51,11 +51,14 @@ int TCPSocket::connect(const SocketAddress &address) int TCPSocket::connect(const char *host, uint16_t port) { - SocketAddress address(_stack, host, port); - if (!address) { + SocketAddress address; + int err = _stack->gethostbyname(host, &address); + if (err) { return NSAPI_ERROR_DNS_FAILURE; } + address.set_port(port); + // connect is thread safe return connect(address); } diff --git a/features/net/network-socket/UDPSocket.cpp b/features/net/network-socket/UDPSocket.cpp index dfee1fff6fa..fdfa4ce998f 100644 --- a/features/net/network-socket/UDPSocket.cpp +++ b/features/net/network-socket/UDPSocket.cpp @@ -36,11 +36,14 @@ nsapi_protocol_t UDPSocket::get_proto() int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size) { - SocketAddress address(_stack, host, port); - if (!address) { + SocketAddress address; + int err = _stack->gethostbyname(host, &address); + if (err) { return NSAPI_ERROR_DNS_FAILURE; } + address.set_port(port); + // sendto is thread safe return sendto(address, data, size); } diff --git a/features/net/network-socket/nsapi_dns.cpp b/features/net/network-socket/nsapi_dns.cpp index 1fab0ef7f6b..83461f4e9a1 100644 --- a/features/net/network-socket/nsapi_dns.cpp +++ b/features/net/network-socket/nsapi_dns.cpp @@ -18,10 +18,11 @@ #include "network-socket/UDPSocket.h" #include #include +#include // DNS options -#define DNS_BUFFER_SIZE 256 +#define DNS_BUFFER_SIZE 512 #define DNS_TIMEOUT 5000 #define DNS_SERVERS_SIZE 5 @@ -189,9 +190,8 @@ static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned add } // core query function -static int nsapi_dns_query_multiple(NetworkStack *stack, - nsapi_addr_t *addr, unsigned addr_count, - const char *host, nsapi_version_t version) +static int nsapi_dns_query_multiple(NetworkStack *stack, const char *host, + nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version) { // check for valid host name int host_len = host ? strlen(host) : 0; @@ -261,20 +261,18 @@ static int nsapi_dns_query_multiple(NetworkStack *stack, } // convenience functions for other forms of queries -extern "C" int nsapi_dns_query_multiple(nsapi_stack_t *stack, - nsapi_addr_t *addr, unsigned addr_count, - const char *host, nsapi_version_t version) +extern "C" int nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host, + nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version) { NetworkStack *nstack = nsapi_create_stack(stack); - return nsapi_dns_query_multiple(nstack, addr, addr_count, host, version); + return nsapi_dns_query_multiple(nstack, host, addr, addr_count, version); } -int nsapi_dns_query_multiple(NetworkStack *stack, - SocketAddress *addresses, unsigned addr_count, - const char *host, nsapi_version_t version) +int nsapi_dns_query_multiple(NetworkStack *stack, const char *host, + SocketAddress *addresses, unsigned addr_count, nsapi_version_t version) { nsapi_addr_t *addrs = new nsapi_addr_t[addr_count]; - int result = nsapi_dns_query_multiple(stack, addrs, addr_count, host, version); + int result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, version); if (result > 0) { for (int i = 0; i < result; i++) { @@ -286,19 +284,19 @@ int nsapi_dns_query_multiple(NetworkStack *stack, return result; } -extern "C" int nsapi_dns_query(nsapi_stack_t *stack, - nsapi_addr_t *addr, const char *host, nsapi_version_t version) +extern "C" int nsapi_dns_query(nsapi_stack_t *stack, const char *host, + nsapi_addr_t *addr, nsapi_version_t version) { NetworkStack *nstack = nsapi_create_stack(stack); - int result = nsapi_dns_query_multiple(nstack, addr, 1, host, version); + int result = nsapi_dns_query_multiple(nstack, host, addr, 1, version); return (result > 0) ? 0 : result; } -int nsapi_dns_query(NetworkStack *stack, - SocketAddress *address, const char *host, nsapi_version_t version) +int nsapi_dns_query(NetworkStack *stack, const char *host, + SocketAddress *address, nsapi_version_t version) { nsapi_addr_t addr; - int result = nsapi_dns_query_multiple(stack, &addr, 1, host, version); + int result = nsapi_dns_query_multiple(stack, host, &addr, 1, version); address->set_addr(addr); return (result > 0) ? 0 : result; } diff --git a/features/net/network-socket/nsapi_dns.h b/features/net/network-socket/nsapi_dns.h index e9a16855559..9f4deca8ba6 100644 --- a/features/net/network-socket/nsapi_dns.h +++ b/features/net/network-socket/nsapi_dns.h @@ -28,28 +28,27 @@ /** Query a domain name server for an IP address of a given hostname * * @param stack Network stack as target for DNS query - * @param addr Destination for the host address * @param host Hostname to resolve + * @param addr Destination for the host address * @param version IP version to resolve * @return 0 on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ -int nsapi_dns_query(nsapi_stack_t *stack, nsapi_addr_t *addr, - const char *host, nsapi_version_t version); +int nsapi_dns_query(nsapi_stack_t *stack, const char *host, + nsapi_addr_t *addr, nsapi_version_t version); /** Query a domain name server for multiple IP address of a given hostname * * @param stack Network stack as target for DNS query + * @param host Hostname to resolve * @param addr Array for the host addresses * @param addr_count Number of addresses allocated in the array - * @param host Hostname to resolve * @param version IP version to resolve * @return Number of addresses found on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ -int nsapi_dns_query_multiple(nsapi_stack_t *stack, - nsapi_addr_t *addr, unsigned addr_count, - const char *host, nsapi_version_t version); +int nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host, + nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version); /** Add a domain name server to list of servers to query * @@ -65,88 +64,85 @@ int nsapi_dns_add_server(nsapi_addr_t addr); /** Query a domain name server for an IP address of a given hostname * * @param stack Network stack as target for DNS query - * @param addr Destination for the host address * @param host Hostname to resolve + * @param addr Destination for the host address * @param version IP version to resolve (defaults to NSAPI_IPv4) * @return 0 on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ -int nsapi_dns_query(NetworkStack *stack, SocketAddress *addr, - const char *host, nsapi_version_t version = NSAPI_IPv4); +int nsapi_dns_query(NetworkStack *stack, const char *host, + SocketAddress *addr, nsapi_version_t version = NSAPI_IPv4); /** Query a domain name server for an IP address of a given hostname * * @param stack Network stack as target for DNS query - * @param addr Destination for the host address * @param host Hostname to resolve + * @param addr Destination for the host address * @param version IP version to resolve (defaults to NSAPI_IPv4) * @return 0 on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ -extern "C" int nsapi_dns_query(nsapi_stack_t *stack, nsapi_addr_t *addr, - const char *host, nsapi_version_t version = NSAPI_IPv4); +extern "C" int nsapi_dns_query(nsapi_stack_t *stack, const char *host, + nsapi_addr_t *addr, nsapi_version_t version = NSAPI_IPv4); /** Query a domain name server for an IP address of a given hostname * * @param stack Network stack as target for DNS query - * @param addr Destination for the host address * @param host Hostname to resolve + * @param addr Destination for the host address * @param version IP version to resolve (defaults to NSAPI_IPv4) * @return 0 on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ template -int nsapi_dns_query(S *stack, SocketAddress *addr, - const char *host, nsapi_version_t version = NSAPI_IPv4) +int nsapi_dns_query(S *stack, const char *host, + SocketAddress *addr, nsapi_version_t version = NSAPI_IPv4) { - return nsapi_dns_query(nsapi_create_stack(stack), addr, host, version); + return nsapi_dns_query(nsapi_create_stack(stack), host, addr, version); } /** Query a domain name server for multiple IP address of a given hostname * * @param stack Network stack as target for DNS query + * @param host Hostname to resolve * @param addr Array for the host addresses * @param addr_count Number of addresses allocated in the array - * @param host Hostname to resolve * @param version IP version to resolve (defaults to NSAPI_IPv4) * @return Number of addresses found on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ -int nsapi_dns_query_multiple(NetworkStack *stack, - SocketAddress *addr, unsigned addr_count, - const char *host, nsapi_version_t version = NSAPI_IPv4); +int nsapi_dns_query_multiple(NetworkStack *stack, const char *host, + SocketAddress *addr, unsigned addr_count, nsapi_version_t version = NSAPI_IPv4); /** Query a domain name server for multiple IP address of a given hostname * * @param stack Network stack as target for DNS query + * @param host Hostname to resolve * @param addr Array for the host addresses * @param addr_count Number of addresses allocated in the array - * @param host Hostname to resolve * @param version IP version to resolve (defaults to NSAPI_IPv4) * @return Number of addresses found on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ -extern "C" int nsapi_dns_query_multiple(nsapi_stack_t *stack, - nsapi_addr_t *addr, unsigned addr_count, - const char *host, nsapi_version_t version = NSAPI_IPv4); +extern "C" int nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host, + nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version = NSAPI_IPv4); /** Query a domain name server for multiple IP address of a given hostname * * @param stack Network stack as target for DNS query + * @param host Hostname to resolve * @param addr Array for the host addresses * @param addr_count Number of addresses allocated in the array - * @param host Hostname to resolve * @param version IP version to resolve (defaults to NSAPI_IPv4) * @return Number of addresses found on success, negative error code on failure * NSAPI_ERROR_DNS_FAILURE indicates the host could not be found */ template -int nsapi_dns_query_multiple(S *stack, - SocketAddress *addr, unsigned addr_count, - const char *host, nsapi_version_t version = NSAPI_IPv4) +int nsapi_dns_query_multiple(S *stack, const char *host, + SocketAddress *addr, unsigned addr_count, nsapi_version_t version = NSAPI_IPv4) { return nsapi_dns_query_multiple(nsapi_create_stack(stack), - addr, addr_count, host, version); + host, addr, addr_count, version); } /** Add a domain name server to list of servers to query diff --git a/features/net/network-socket/nsapi_types.h b/features/net/network-socket/nsapi_types.h index 669ef40311e..c1972f09265 100644 --- a/features/net/network-socket/nsapi_types.h +++ b/features/net/network-socket/nsapi_types.h @@ -199,7 +199,14 @@ typedef struct nsapi_stack_api * @param host Hostname to resolve * @return 0 on success, negative error code on failure */ - int (*gethostbyname)(nsapi_stack_t *stack, nsapi_addr_t *addr, const char *host); + int (*gethostbyname)(nsapi_stack_t *stack, const char *host, nsapi_addr_t *addr); + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + int (*add_dns_server)(nsapi_stack_t *stack, nsapi_addr_t addr); /* Set stack-specific stack options *