diff --git a/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c b/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c index 3ab138380aa..1e048082755 100644 --- a/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c +++ b/features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c @@ -217,7 +217,7 @@ static int lwip_err_remap(err_t err) { /* LWIP network stack implementation */ -static nsapi_addr_t lwip_get_addr(nsapi_stack_t *stack) +static nsapi_addr_t lwip_getaddr(nsapi_stack_t *stack) { if (!lwip_get_ip_address()) { return (nsapi_addr_t){0}; @@ -229,6 +229,17 @@ static nsapi_addr_t lwip_get_addr(nsapi_stack_t *stack) return addr; } +static int lwip_gethostbyname(nsapi_stack_t *stack, nsapi_addr_t *addr, const char *host) +{ + err_t err = netconn_gethostbyname(host, (ip_addr_t *)addr->bytes); + if (err != ERR_OK) { + return NSAPI_ERROR_DNS_FAILURE; + } + + addr->version = NSAPI_IPv4; + return 0; +} + static int lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t *handle, nsapi_protocol_t proto) { struct lwip_socket *s = lwip_arena_alloc(); @@ -449,7 +460,8 @@ static void lwip_socket_attach(nsapi_stack_t *stack, nsapi_socket_t handle, void /* LWIP network stack */ const nsapi_stack_api_t lwip_stack_api = { - .get_ip_address = lwip_get_addr, + .get_ip_address = lwip_getaddr, + .gethostbyname = lwip_gethostbyname, .socket_open = lwip_socket_open, .socket_close = lwip_socket_close, .socket_bind = lwip_socket_bind, diff --git a/features/net/FEATURE_IPV4/lwip-interface/lwipopts.h b/features/net/FEATURE_IPV4/lwip-interface/lwipopts.h index 5e16535ba29..f557e353cb1 100644 --- a/features/net/FEATURE_IPV4/lwip-interface/lwipopts.h +++ b/features/net/FEATURE_IPV4/lwip-interface/lwipopts.h @@ -66,6 +66,7 @@ #define LWIP_DHCP 1 #define LWIP_DNS 1 +#define LWIP_SOCKET 0 #define SO_REUSE 1 diff --git a/features/net/network-socket/DnsQuery/DnsQuery.cpp b/features/net/network-socket/DnsQuery/DnsQuery.cpp deleted file mode 100644 index 2c209f529e1..00000000000 --- a/features/net/network-socket/DnsQuery/DnsQuery.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "DnsQuery.h" -#include -#include - - -#define DNS_COUNT (sizeof DNS_IPS / sizeof DNS_IPS[0]) -const char *DNS_IPS[] = { - "8.8.8.8", - "209.244.0.3", - "84.200.69.80", - "8.26.56.26", - "208.67.222.222" -}; - -static bool isIP(const char *host) -{ - int i; - - for (i = 0; host[i]; i++) { - if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') { - return false; - } - } - - // Ending with '.' garuntees host - if (i > 0 && host[i-1] == '.') { - return false; - } - - return true; -} - - -static bool parseRR(uint8_t *resp, int &c, char *adr) -{ - int n = 0; - while((n=resp[c++]) != 0) { - if ((n & 0xc0) != 0) { - // This is a link - c++; - break; - } else { - // skip this segment, not interested in string domain names - c+= n; - } - } - - int TYPE = (((int)resp[c])<<8) + resp[c+1]; - int CLASS = (((int)resp[c+2])<<8) + resp[c+3]; - int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9]; - - c+= 10; - if ((CLASS == 1) && (TYPE == 1)) { - sprintf(adr,"%d.%d.%d.%d", resp[c], resp[c+1], resp[c+2], resp[c+3]); - c+= RDLENGTH; - return true; - } - c+= RDLENGTH; - - return false; -} - - -static bool resolve(unsigned char *resp, char *ipaddress) -{ - - int ID = (((int)resp[0]) <<8) + resp[1]; - int QR = resp[2] >>7; - int Opcode = (resp[2]>>3) & 0x0F; - int RCODE = (resp[3] & 0x0F); - int ANCOUNT = (((int)resp[6])<<8)+ resp[7]; - - if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) { - return false; - } - - int c = 12; - int d; - // Skip domain question - while( (d=resp[c++]) != 0) { - c+=d; - } - c+= 4; // skip QTYPE and QCLASS - - // Here comes the resource record - for (int ans = 0 ; ans < ANCOUNT; ans++) { - if (parseRR(resp, c, ipaddress)) { - return true; - } - } - - return false; -} - -static int32_t query(UDPSocket *socket, const SocketAddress &addr, const char *hostname, char *ipaddress) -{ - int len = 0; - if (hostname == NULL) { - return false; - } - len = strlen(hostname); - if ((len > 128) || (len == 0)) { - return false; - } - - int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1; - uint8_t *packet = new uint8_t[packetlen]; /* this is the UDP packet to send to the DNS */ - if (packet == NULL) { - return false; - } - - // Fill the header - memset(packet, 0, packetlen); - packet[1] = 1; // ID = 1 - packet[5] = 1; // QDCOUNT = 1 (contains one question) - packet[2] = 1; // recursion requested - - int c = 13; // point to NAME element in question section or request - int cnt = 12; // points to the counter of - packet[cnt] = 0; - for (int i = 0 ; i < len ; i++) { - if (hostname[i] != '.') { - // Copy the character and increment the character counter - packet[cnt]++; - packet[c++] = hostname[i]; - } else { - // Finished with this part, so go to the next - cnt = c++; - packet[cnt] = 0; - } - } - - // Terminate this domain name with a zero entry - packet[c++] = 0; - - // Set QTYPE - packet[c++] = 0; - packet[c++] = 1; - // Set QCLASS - packet[c++] = 0; - packet[c++] = 1; - - - if (socket->sendto(addr, packet, packetlen) < 0) { - delete packet; - return false; - } - delete packet; - - packet = new uint8_t [1024]; - - // Receive the answer from DNS - int response_length = 0; - response_length = socket->recvfrom(NULL, packet, 1024); - - if (response_length > 0 ) { - if (!resolve(packet, ipaddress)) { - delete packet; - return NSAPI_ERROR_DNS_FAILURE; - } - - // cleanup and return - delete packet; - return 0; - } - - delete packet; - return NSAPI_ERROR_DNS_FAILURE; -} - -int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip) -{ - if (isIP(host)) { - strcpy(ip, host); - return 0; - } - - UDPSocket sock(iface); - - for (unsigned i = 0; i < DNS_COUNT; i++) { - return query(&sock, SocketAddress(DNS_IPS[0], 53), host, ip); - } - - return NSAPI_ERROR_DNS_FAILURE; -} - -int32_t dnsQuery(UDPSocket *socket, const char *host, char *ip) -{ - if (isIP(host)) { - strcpy(ip, host); - return 0; - } - - for (unsigned i = 0; i < DNS_COUNT; i++) { - return query(socket, SocketAddress(DNS_IPS[0], 53), host, ip); - } - - return NSAPI_ERROR_DNS_FAILURE; -} diff --git a/features/net/network-socket/DnsQuery/DnsQuery.h b/features/net/network-socket/DnsQuery/DnsQuery.h deleted file mode 100644 index 3c5dfa7d701..00000000000 --- a/features/net/network-socket/DnsQuery/DnsQuery.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef __DNSQUERY_H__ -#define __DNSQUERY_H__ - -#include "NetworkStack.h" -#include "UDPSocket.h" - - -/** Function dnsQuery implements the functionality to query a domain name - * server for an IP-Address of a given hostname. - * @param iface : Network interface to use for DNS resolution. - * @param sock : Previously opened socket to use for DNS resolution. - * @param hostname : The hostname of interest as a string. - * Format must be without http:// or www. IE google.com, mbed.org, etc. - * If a standard IP Address is passed, it will be copied into ip unmodified. - * @param ipaddress : A reference to a IPADDRESS_t object which will receive - * the resolved IP Address of the host in question. - * @returns 0 on succes, NS_DNS_FAILURE if host is not found, - * or a negative value for other errors. - */ -int32_t dnsQuery(NetworkStack *iface, const char *host, char *ip); -int32_t dnsQuery(UDPSocket *sock, const char *host, char *ip); - - -#endif // __DNSQUERY_H__ diff --git a/features/net/network-socket/NetworkStack.cpp b/features/net/network-socket/NetworkStack.cpp index 2198507d9e2..b9c39afd7cc 100644 --- a/features/net/network-socket/NetworkStack.cpp +++ b/features/net/network-socket/NetworkStack.cpp @@ -15,7 +15,7 @@ */ #include "NetworkStack.h" -#include "DnsQuery.h" +#include "nsapi_dns.h" #include "mbed.h" #include "stddef.h" #include @@ -24,14 +24,7 @@ // Default NetworkStack operations int NetworkStack::gethostbyname(SocketAddress *address, const char *name) { - char buffer[NSAPI_IP_SIZE]; - int err = dnsQuery(this, name, buffer); - if (err) { - return err; - } - - address->set_ip_address(buffer); - return 0; + return nsapi_dns_query(this, address, name); } int NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen) diff --git a/features/net/network-socket/nsapi_dns.cpp b/features/net/network-socket/nsapi_dns.cpp new file mode 100644 index 00000000000..1fab0ef7f6b --- /dev/null +++ b/features/net/network-socket/nsapi_dns.cpp @@ -0,0 +1,304 @@ +/* nsapi_dns.cpp + * Original work Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) + * Modified work Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "nsapi_dns.h" +#include "network-socket/UDPSocket.h" +#include +#include + + +// DNS options +#define DNS_BUFFER_SIZE 256 +#define DNS_TIMEOUT 5000 +#define DNS_SERVERS_SIZE 5 + +nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = { + {NSAPI_IPv4, {8, 8, 8, 8}}, + {NSAPI_IPv4, {209, 244, 0, 3}}, + {NSAPI_IPv4, {84, 200, 69, 80}}, + {NSAPI_IPv4, {8, 26, 56, 26}}, + {NSAPI_IPv4, {208, 67, 222, 222}}, +}; + + +// DNS server configuration +extern "C" int nsapi_dns_add_server(nsapi_addr_t addr) +{ + memmove(&dns_servers[1], &dns_servers[0], + (DNS_SERVERS_SIZE-1)*sizeof(nsapi_addr_t)); + + dns_servers[0] = addr; + return 0; +} + + +// DNS packet parsing +static void dns_append_byte(uint8_t **p, uint8_t byte) +{ + *(*p)++ = byte; +} + +static void dns_append_word(uint8_t **p, uint16_t word) +{ + + dns_append_byte(p, 0xff & (word >> 8)); + dns_append_byte(p, 0xff & (word >> 0)); +} + +static void dns_append_name(uint8_t **p, const char *name, uint8_t len) +{ + dns_append_byte(p, len); + memcpy(*p, name, len); + *p += len; +} + +static uint8_t dns_scan_byte(const uint8_t **p) +{ + return *(*p)++; +} + +static uint16_t dns_scan_word(const uint8_t **p) +{ + uint16_t a = dns_scan_byte(p); + uint16_t b = dns_scan_byte(p); + return (a << 8) | b; +} + + +static void dns_append_question(uint8_t **p, const char *host, nsapi_version_t version) +{ + // fill the header + dns_append_word(p, 1); // id = 1 + dns_append_word(p, 0x0100); // flags = recursion required + dns_append_word(p, 1); // qdcount = 1 + dns_append_word(p, 0); // ancount = 0 + dns_append_word(p, 0); // nscount = 0 + dns_append_word(p, 0); // arcount = 0 + + // fill out the question names + while (host[0]) { + size_t label_len = strcspn(host, "."); + dns_append_name(p, host, label_len); + host += label_len + (host[label_len] == '.'); + } + + dns_append_byte(p, 0); + + // fill out question footer + if (version == NSAPI_IPv4) { + dns_append_word(p, 1); // qtype = ipv4 + } else { + dns_append_word(p, 28); // qtype = ipv6 + } + dns_append_word(p, 1); // qclass = 1 +} + +static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned addr_count) +{ + // scan header + uint16_t id = dns_scan_word(p); + uint16_t flags = dns_scan_word(p); + bool qr = 0x1 & (flags >> 15); + uint8_t opcode = 0xf & (flags >> 11); + uint8_t rcode = 0xf & (flags >> 0); + + uint16_t qdcount = dns_scan_word(p); // qdcount + uint16_t ancount = dns_scan_word(p); // ancount + dns_scan_word(p); // nscount + dns_scan_word(p); // arcount + + // verify header is response to query + if (!(id == 1 && qr && opcode == 0 && rcode == 0)) { + return 0; + } + + // skip questions + for (int i = 0; i < qdcount; i++) { + while (true) { + uint8_t len = dns_scan_byte(p); + if (len == 0) { + break; + } + + *p += len; + } + + dns_scan_word(p); // qtype + dns_scan_word(p); // qclass + } + + // scan each response + unsigned count = 0; + + for (int i = 0; i < ancount && count < addr_count; i++) { + while (true) { + uint8_t len = dns_scan_byte(p); + if (len == 0) { + break; + } else if (len & 0xc0) { // this is link + dns_scan_byte(p); + break; + } + + *p += len; + } + + uint16_t rtype = dns_scan_word(p); // rtype + uint16_t rclass = dns_scan_word(p); // rclass + *p += 4; // ttl + uint16_t rdlength = dns_scan_word(p); // rdlength + + if (rtype == 1 && rclass == 1 && rdlength == NSAPI_IPv4_BYTES) { + // accept A record + addr->version = NSAPI_IPv4; + for (int i = 0; i < NSAPI_IPv4_BYTES; i++) { + addr->bytes[i] = dns_scan_byte(p); + } + + addr += 1; + count += 1; + } else if (rtype == 28 && rclass == 1 && rdlength == NSAPI_IPv6_BYTES) { + // accept AAAA record + addr->version = NSAPI_IPv6; + for (int i = 0; i < NSAPI_IPv6_BYTES; i++) { + addr->bytes[i] = dns_scan_byte(p); + } + + addr += 1; + count += 1; + } else { + // skip unrecognized records + *p += rdlength; + } + } + + return count; +} + +// 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) +{ + // check for valid host name + int host_len = host ? strlen(host) : 0; + if (host_len > 128 || host_len == 0) { + return NSAPI_ERROR_PARAMETER; + } + + // create a udp socket + UDPSocket socket; + int err = socket.open(stack); + if (err) { + return err; + } + + socket.set_timeout(DNS_TIMEOUT); + + // create network packet + uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE); + if (!packet) { + return NSAPI_ERROR_NO_MEMORY; + } + + int result = NSAPI_ERROR_DNS_FAILURE; + + // check against each dns server + for (unsigned i = 0; i < DNS_SERVERS_SIZE; i++) { + // send the question + uint8_t *p = packet; + dns_append_question(&p, host, version); + + err = socket.sendto(SocketAddress(dns_servers[i], 53), packet, DNS_BUFFER_SIZE); + if (err == NSAPI_ERROR_WOULD_BLOCK) { + continue; + } else if (err < 0) { + result = err; + break; + } + + // recv the response + err = socket.recvfrom(NULL, packet, DNS_BUFFER_SIZE); + if (err == NSAPI_ERROR_WOULD_BLOCK) { + continue; + } else if (err < 0) { + result = err; + break; + } + + p = packet; + int found = dns_scan_response((const uint8_t **)&p, addr, addr_count); + if (found) { + result = found; + break; + } + } + + // clean up packet + free(packet); + + // clean up udp + err = socket.close(); + if (err) { + return err; + } + + // return result + return result; +} + +// 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) +{ + NetworkStack *nstack = nsapi_create_stack(stack); + return nsapi_dns_query_multiple(nstack, addr, addr_count, host, version); +} + +int nsapi_dns_query_multiple(NetworkStack *stack, + SocketAddress *addresses, unsigned addr_count, + const char *host, 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); + + if (result > 0) { + for (int i = 0; i < result; i++) { + addresses[i].set_addr(addrs[i]); + } + } + + delete[] addrs; + return result; +} + +extern "C" int nsapi_dns_query(nsapi_stack_t *stack, + nsapi_addr_t *addr, const char *host, nsapi_version_t version) +{ + NetworkStack *nstack = nsapi_create_stack(stack); + int result = nsapi_dns_query_multiple(nstack, addr, 1, host, version); + return (result > 0) ? 0 : result; +} + +int nsapi_dns_query(NetworkStack *stack, + SocketAddress *address, const char *host, nsapi_version_t version) +{ + nsapi_addr_t addr; + int result = nsapi_dns_query_multiple(stack, &addr, 1, host, 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 new file mode 100644 index 00000000000..e9a16855559 --- /dev/null +++ b/features/net/network-socket/nsapi_dns.h @@ -0,0 +1,182 @@ +/* nsapi_dns.h + * Original work Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) + * Modified work Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NSAPI_DNS_H +#define NSAPI_DNS_H + +#include "nsapi_types.h" +#ifdef __cplusplus +#include "network-socket/NetworkStack.h" +#endif + +#ifndef __cplusplus + + +/** 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 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); + +/** Query a domain name server for multiple IP address of a given hostname + * + * @param stack Network stack as target for DNS query + * @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); + +/** 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 nsapi_dns_add_server(nsapi_addr_t addr); + + +#else + + +/** 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 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); + +/** 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 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); + +/** 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 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) +{ + return nsapi_dns_query(nsapi_create_stack(stack), addr, host, version); +} + +/** Query a domain name server for multiple IP address of a given hostname + * + * @param stack Network stack as target for DNS query + * @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); + +/** Query a domain name server for multiple IP address of a given hostname + * + * @param stack Network stack as target for DNS query + * @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); + +/** Query a domain name server for multiple IP address of a given hostname + * + * @param stack Network stack as target for DNS query + * @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) +{ + return nsapi_dns_query_multiple(nsapi_create_stack(stack), + addr, addr_count, host, 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 + */ +extern "C" int nsapi_dns_add_server(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 + */ +static inline int nsapi_dns_add_server(const SocketAddress &address) +{ + return nsapi_dns_add_server(address.get_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 + */ +static inline int nsapi_dns_add_server(const char *address) +{ + return nsapi_dns_add_server(SocketAddress(address)); +} + + +#endif + +#endif