Skip to content

Commit 3858a13

Browse files
committed
nsapi - Added access to gethostbyname and add_dns_server
For performing DNS resolution explicitly through the network-socket user API. This interface does not require implementation changes and can rely entirely on the dns query library in the network-socket API.
1 parent 9803047 commit 3858a13

File tree

9 files changed

+242
-10
lines changed

9 files changed

+242
-10
lines changed

features/net/network-socket/NetworkInterface.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
*/
1616

1717
#include "network-socket/NetworkInterface.h"
18+
#include "network-socket/NetworkStack.h"
1819
#include <string.h>
1920

2021

22+
// Default network-interface state
2123
const char *NetworkInterface::get_mac_address()
2224
{
2325
return 0;
@@ -52,3 +54,19 @@ int NetworkInterface::set_dhcp(bool dhcp)
5254
}
5355
}
5456

57+
// DNS operations go through the underlying stack by default
58+
int NetworkInterface::gethostbyname(SocketAddress *address, const char *name)
59+
{
60+
return get_stack()->gethostbyname(address, name);
61+
}
62+
63+
int NetworkInterface::gethostbyname(SocketAddress *address, const char *name, nsapi_version_t version)
64+
{
65+
return get_stack()->gethostbyname(address, name, version);
66+
}
67+
68+
int NetworkInterface::add_dns_server(const SocketAddress &address)
69+
{
70+
return get_stack()->add_dns_server(address);
71+
}
72+

features/net/network-socket/NetworkInterface.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define NETWORK_INTERFACE_H
1919

2020
#include "network-socket/nsapi_types.h"
21+
#include "network-socket/SocketAddress.h"
2122

2223
// Predeclared class
2324
class NetworkStack;
@@ -99,6 +100,42 @@ class NetworkInterface {
99100
*/
100101
virtual int disconnect() = 0;
101102

103+
/** Translates a hostname to an IP address
104+
*
105+
* The hostname may be either a domain name or an IP address. If the
106+
* hostname is an IP address, no network transactions will be performed.
107+
*
108+
* If no stack-specific DNS resolution is provided, the hostname
109+
* will be resolve using a UDP socket on the stack.
110+
*
111+
* @param host Hostname to resolve
112+
* @param address Destination for the host SocketAddress
113+
* @return 0 on success, negative error code on failure
114+
*/
115+
virtual int gethostbyname(SocketAddress *address, const char *host);
116+
117+
/** Translates a hostname to an IP address with specific version
118+
*
119+
* The hostname may be either a domain name or an IP address. If the
120+
* hostname is an IP address, no network transactions will be performed.
121+
*
122+
* If no stack-specific DNS resolution is provided, the hostname
123+
* will be resolve using a UDP socket on the stack.
124+
*
125+
* @param address Destination for the host SocketAddress
126+
* @param host Hostname to resolve
127+
* @param version IP version of address to resolve
128+
* @return 0 on success, negative error code on failure
129+
*/
130+
virtual int gethostbyname(SocketAddress *address, const char *host, nsapi_version_t version);
131+
132+
/** Add a domain name server to list of servers to query
133+
*
134+
* @param addr Destination for the host address
135+
* @return 0 on success, negative error code on failure
136+
*/
137+
virtual int add_dns_server(const SocketAddress &address);
138+
102139
protected:
103140
friend class Socket;
104141
friend class UDPSocket;

features/net/network-socket/NetworkStack.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ int NetworkStack::gethostbyname(SocketAddress *address, const char *name)
2727
return nsapi_dns_query(this, address, name);
2828
}
2929

30+
int NetworkStack::gethostbyname(SocketAddress *address, const char *name, nsapi_version_t version)
31+
{
32+
return nsapi_dns_query(this, address, name, version);
33+
}
34+
35+
int NetworkStack::add_dns_server(const SocketAddress &address)
36+
{
37+
return nsapi_dns_add_server(address);
38+
}
39+
3040
int NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen)
3141
{
3242
return NSAPI_ERROR_UNSUPPORTED;
@@ -88,6 +98,15 @@ class NetworkStackWrapper : public NetworkStack
8898
return err;
8999
}
90100

101+
virtual int add_dns_server(const SocketAddress &address)
102+
{
103+
if (!_stack_api()->add_dns_server) {
104+
return NetworkStack::add_dns_server(address);
105+
}
106+
107+
return _stack_api()->add_dns_server(_stack(), address.get_addr());
108+
}
109+
91110
virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen)
92111
{
93112
if (!_stack_api()->setstackopt) {

features/net/network-socket/NetworkStack.h

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,38 @@ class NetworkStack
4545
*
4646
* The hostname may be either a domain name or an IP address. If the
4747
* hostname is an IP address, no network transactions will be performed.
48-
*
48+
*
4949
* If no stack-specific DNS resolution is provided, the hostname
50-
* will be resolve using a UDP socket on the stack.
50+
* will be resolve using a UDP socket on the stack.
5151
*
5252
* @param address Destination for the host SocketAddress
5353
* @param host Hostname to resolve
5454
* @return 0 on success, negative error code on failure
5555
*/
5656
virtual int gethostbyname(SocketAddress *address, const char *host);
5757

58+
/** Translates a hostname to an IP address with specific version
59+
*
60+
* The hostname may be either a domain name or an IP address. If the
61+
* hostname is an IP address, no network transactions will be performed.
62+
*
63+
* If no stack-specific DNS resolution is provided, the hostname
64+
* will be resolve using a UDP socket on the stack.
65+
*
66+
* @param host Hostname to resolve
67+
* @param address Destination for the host SocketAddress
68+
* @param version IP version of address to resolve
69+
* @return 0 on success, negative error code on failure
70+
*/
71+
virtual int gethostbyname(SocketAddress *address, const char *host, nsapi_version_t version);
72+
73+
/** Add a domain name server to list of servers to query
74+
*
75+
* @param addr Destination for the host address
76+
* @return 0 on success, negative error code on failure
77+
*/
78+
virtual int add_dns_server(const SocketAddress &address);
79+
5880
/* Set stack-specific stack options
5981
*
6082
* The setstackopt allow an application to pass stack-specific hints
@@ -66,7 +88,7 @@ class NetworkStack
6688
* @param optval Option value
6789
* @param optlen Length of the option value
6890
* @return 0 on success, negative error code on failure
69-
*/
91+
*/
7092
virtual int setstackopt(int level, int optname, const void *optval, unsigned optlen);
7193

7294
/* Get stack-specific stack options
@@ -80,7 +102,7 @@ class NetworkStack
80102
* @param optval Destination for option value
81103
* @param optlen Length of the option value
82104
* @return 0 on success, negative error code on failure
83-
*/
105+
*/
84106
virtual int getstackopt(int level, int optname, void *optval, unsigned *optlen);
85107

86108
protected:
@@ -260,7 +282,7 @@ class NetworkStack
260282
* @param optval Option value
261283
* @param optlen Length of the option value
262284
* @return 0 on success, negative error code on failure
263-
*/
285+
*/
264286
virtual int setsockopt(nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen);
265287

266288
/* Get stack-specific socket options
@@ -275,7 +297,7 @@ class NetworkStack
275297
* @param optval Destination for option value
276298
* @param optlen Length of the option value
277299
* @return 0 on success, negative error code on failure
278-
*/
300+
*/
279301
virtual int getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen);
280302
};
281303

features/net/network-socket/SocketAddress.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,14 @@ class SocketAddress {
4141
* @param stack Network stack to use for DNS resolution
4242
* @param host Hostname to resolve
4343
* @param port Optional 16-bit port
44+
* @deprecated
45+
* Constructors hide possible errors. Replaced by
46+
* NetworkInterface::gethostbyname.
4447
*/
4548
template <typename S>
49+
MBED_DEPRECATED_SINCE("mbed-os-5.1.3",
50+
"Constructors hide possible errors. Replaced by "
51+
"NetworkInterface::gethostbyname.")
4652
SocketAddress(S *stack, const char *host, uint16_t port = 0)
4753
{
4854
_SocketAddress(nsapi_create_stack(stack), host, port);

features/net/network-socket/TCPSocket.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,14 @@ int TCPSocket::connect(const SocketAddress &address)
5151

5252
int TCPSocket::connect(const char *host, uint16_t port)
5353
{
54-
SocketAddress address(_stack, host, port);
55-
if (!address) {
54+
SocketAddress address;
55+
int err = _stack->gethostbyname(&address, host);
56+
if (err) {
5657
return NSAPI_ERROR_DNS_FAILURE;
5758
}
5859

60+
address.set_port(port);
61+
5962
// connect is thread safe
6063
return connect(address);
6164
}

features/net/network-socket/UDPSocket.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,14 @@ nsapi_protocol_t UDPSocket::get_proto()
3636

3737
int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size)
3838
{
39-
SocketAddress address(_stack, host, port);
40-
if (!address) {
39+
SocketAddress address;
40+
int err = _stack->gethostbyname(&address, host);
41+
if (err) {
4142
return NSAPI_ERROR_DNS_FAILURE;
4243
}
4344

45+
address.set_port(port);
46+
4447
// sendto is thread safe
4548
return sendto(address, data, size);
4649
}

features/net/network-socket/nsapi_dns.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "network-socket/UDPSocket.h"
1919
#include <string.h>
2020
#include <stdlib.h>
21+
#include <stdio.h>
2122

2223

2324
// DNS options
@@ -44,6 +45,111 @@ extern "C" int nsapi_dns_add_server(nsapi_addr_t addr)
4445
return 0;
4546
}
4647

48+
// IP parsing
49+
static bool dns_parse_ipv4(const char *host, nsapi_addr_t *addr)
50+
{
51+
int i = 0;
52+
53+
// Check each digit for [0-9.]
54+
for (; host[i]; i++) {
55+
if (!(host[i] >= '0' && host[i] <= '9') && host[i] != '.') {
56+
return false;
57+
}
58+
}
59+
60+
// Ending with '.' garuntees host
61+
if (i > 0 && host[i-1] == '.') {
62+
return false;
63+
}
64+
65+
// Build up the ip address
66+
addr->version = NSAPI_IPv4;
67+
i = 0;
68+
69+
for (int count = 0; count < NSAPI_IPv4_BYTES; count++) {
70+
int scanned = sscanf(&host[i], "%hhu", &addr->bytes[count]);
71+
if (scanned < 1) {
72+
return true;
73+
}
74+
75+
for (; host[i] != '.'; i++) {
76+
if (!host[i]) {
77+
return true;
78+
}
79+
}
80+
81+
i++;
82+
}
83+
84+
return true;
85+
}
86+
87+
static int dns_parse_ipv6_chunk(const char *chunk, uint16_t *shorts) {
88+
int count = 0;
89+
int i = 0;
90+
91+
for (; count < NSAPI_IPv6_BYTES/2; count++) {
92+
int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
93+
if (scanned < 1) {
94+
return count;
95+
}
96+
97+
for (; chunk[i] != ':'; i++) {
98+
if (!chunk[i]) {
99+
return count+1;
100+
}
101+
}
102+
103+
i++;
104+
}
105+
106+
return count;
107+
}
108+
109+
static bool dns_parse_ipv6(const char *host, nsapi_addr_t *addr)
110+
{
111+
// Check each digit for [0-9a-fA-F:]
112+
for (int i = 0; host[i]; i++) {
113+
if (!(host[i] >= '0' && host[i] <= '9') &&
114+
!(host[i] >= 'a' && host[i] <= 'f') &&
115+
!(host[i] >= 'A' && host[i] <= 'F') &&
116+
host[i] != ':') {
117+
return false;
118+
}
119+
}
120+
121+
// Build up address
122+
addr->version = NSAPI_IPv6;
123+
124+
// Start with zeroed address
125+
uint16_t shorts[NSAPI_IPv6_BYTES/2];
126+
memset(shorts, 0, sizeof shorts);
127+
128+
int suffix = 0;
129+
130+
// Find double colons and scan suffix
131+
for (int i = 0; host[i]; i++) {
132+
if (host[i] == ':' && host[i+1] == ':') {
133+
suffix = dns_parse_ipv6_chunk(&host[i+2], shorts);
134+
break;
135+
}
136+
}
137+
138+
// Move suffix to end
139+
memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
140+
suffix*sizeof(uint16_t));
141+
142+
// Scan prefix
143+
dns_parse_ipv6_chunk(&host[0], shorts);
144+
145+
// Flip bytes
146+
for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
147+
addr->bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
148+
addr->bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
149+
}
150+
151+
return true;
152+
}
47153

48154
// DNS packet parsing
49155
static void dns_append_byte(uint8_t **p, uint8_t byte)
@@ -199,6 +305,17 @@ static int nsapi_dns_query_multiple(NetworkStack *stack,
199305
return NSAPI_ERROR_PARAMETER;
200306
}
201307

308+
// check for simple ip addresses
309+
if (version == NSAPI_IPv4) {
310+
if (dns_parse_ipv4(host, addr)) {
311+
return 0;
312+
}
313+
} else if (version == NSAPI_IPv6) {
314+
if (dns_parse_ipv6(host, addr)) {
315+
return 0;
316+
}
317+
}
318+
202319
// create a udp socket
203320
UDPSocket socket;
204321
int err = socket.open(stack);

features/net/network-socket/nsapi_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ typedef struct nsapi_stack_api
201201
*/
202202
int (*gethostbyname)(nsapi_stack_t *stack, nsapi_addr_t *addr, const char *host);
203203

204+
/** Add a domain name server to list of servers to query
205+
*
206+
* @param addr Destination for the host address
207+
* @return 0 on success, negative error code on failure
208+
*/
209+
int (*add_dns_server)(nsapi_stack_t *stack, nsapi_addr_t addr);
210+
204211
/* Set stack-specific stack options
205212
*
206213
* The setstackopt allow an application to pass stack-specific hints

0 commit comments

Comments
 (0)