Skip to content

nsapi - Add explicit DNS interface to the network socket API #2652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion features/net/FEATURE_IPV4/lwip-interface/lwip_stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
18 changes: 18 additions & 0 deletions features/net/network-socket/NetworkInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
*/

#include "network-socket/NetworkInterface.h"
#include "network-socket/NetworkStack.h"
#include <string.h>


// Default network-interface state
const char *NetworkInterface::get_mac_address()
{
return 0;
Expand Down Expand Up @@ -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);
}

37 changes: 37 additions & 0 deletions features/net/network-socket/NetworkInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define NETWORK_INTERFACE_H

#include "network-socket/nsapi_types.h"
#include "network-socket/SocketAddress.h"

// Predeclared class
class NetworkStack;
Expand Down Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to make this virtual? In what case would gethostbyname be overridden by an interface?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought probably it probably doesn't hurt to have it match the rest of the files.

Copy link
Contributor Author

@geky geky Sep 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be useful if a network interface wants to override the gethostbyname implementation for an interface-specific feature.


/** 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;
Expand Down
43 changes: 38 additions & 5 deletions features/net/network-socket/NetworkStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
36 changes: 29 additions & 7 deletions features/net/network-socket/NetworkStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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);
};

Expand Down
14 changes: 11 additions & 3 deletions features/net/network-socket/SocketAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,21 @@ 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') &&
!(addr[i] >= 'A' && addr[i] <= 'F') &&
addr[i] != ':') {
return false;
}
if (addr[i] == ':') {
colons++;
}
}

return true;
return colons >= 2;
}

static void ipv4_from_address(uint8_t *bytes, const char *addr)
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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();
Expand Down
10 changes: 9 additions & 1 deletion features/net/network-socket/SocketAddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename S>
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);
Expand Down Expand Up @@ -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
*
Expand Down
7 changes: 5 additions & 2 deletions features/net/network-socket/TCPSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
7 changes: 5 additions & 2 deletions features/net/network-socket/UDPSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Loading