-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Conversation
* @param host Hostname to resolve | ||
* @return 0 on success, negative error code on failure | ||
*/ | ||
virtual int gethostbyname(const char *host, SocketAddress *address); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
i = 0; | ||
|
||
for (int count = 0; count < NSAPI_IPv4_BYTES; count++) { | ||
int scanned = sscanf(&host[i], "%hhu", &addr->bytes[count]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's a good idea to limit check the number that was scanned?
EDIT: no, sorry, that works fine.
I would add some new tests (at least for the new IPv4/IPv6 parsing functions). |
89fb30e
to
8c4ce18
Compare
I'm not sure why the NetworkStack is being hidden from users. That rather defeats the point of the separation, surely - you're having to add everything to the interface to reveal things that are stack-related, like this. We still have an utterly fundamental problem in that the resolution is blocking - we do need a parallel non-blocking API for client + Nanostack. Makes no sense to me that the DNS code has literal parsing. "DNS query" should mean DNS query. It's gethostbyname's job to first attempt local match (as numeric literal, or from table, or constants like "localhost"), then if that fails to call the DNS if present. If you, say, omitted DNS from the build, you still need gethostbyname to do the non-DNS work. And in the absence of the DNS non-blocking API it's critically important that there are APIs that are guaranteed to not attempt lookup. Which means retaining the SocketAddress APIs that have literal parsing only. (So why is the parsing code repeated here?). Basically, I massively favour the approach in #2767. |
Another thought - my feeling is that this sort of thing (gethostbyname) being a member function, either of NetworkStack or NetworkInterface, is a design error. It is not really functionality of either a stack or an interface. It is a utility library call, which may benefit from specification of a stack. It has no need for access to stack internals. The attempted "hiding" of NetworkStack would be less problematic if resolved by overloads for, say, mbed::gethostbyname(NetworkStack *) and mbed::gethostbyname(NetworkInterface *). You wouldn't have to extend the NetworkInterface class for every single call that really wanted to act on a NetworkStack. You'd just add the necessary overloads to convert Interface to Stack for each non-member functions. (Or maybe define an implicit Interface->Stack conversion operator? Not sure if that's good practice.) But I can see that maybe there's some concern about not defining non-member functions because of the namespace "using mbed" problems (cf mbed::callback). |
Thanks for adopting most of the other approach. Still seems wrong to have the DNS query call contain a literal check. It's just not the conventional way the parts are assembled. Gethostbyname predates DNS, and was always "number conversion or hosts.txt lookup". The DNS resolver is an extension to that original functionality - a third approach called by gethostbyname. It logically should be possible to configure out DNS from the build so that "nsapi_dns_query" is a dummy error-returning macro, and leaving the system working. (Or at least it should be structured like that so it's in principle possible). |
// check for simple ip addresses | ||
SocketAddress address; | ||
if (address.set_ip_address(host) && address.get_ip_version() == version) { | ||
*addr = address.get_addr(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's a valid literal but the version doesn't match, it should return an error rather than proceed to try to resolve it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable 👍
Initially the NetworkStack was kept hidden since the full scope of the class and how it interacts with the NetworkInterface was unclear. You're right that with the NetworkStack hidden, the scope of NetworkInterface and NetworkStack starts to merge. We've been looking into the benefits of both NetworkInterface and NetworkStack class in the user API, but the separation simply doesn't add much and adds to the boilerplate code for setting up networks. We determined the best path forward would be to combine NetworkStack and NetworkInterface into NetworkInterface, which simply provides a base class for network devices that provide socket-related functions. @c1728p9 was looking into a user-facing NetworkStack class that extends the NetworkInterface and provides stack-related functions (such as registering emacs). This is currently in work on a separate pr (https://github.com/geky/mbed/tree/nsapi-no-stack, dependent on this and #2664). |
This should probably be a separate issue/pr. Does this API limit an asynchronous that could be introduced in the future? |
f5f9ef6
to
faf663a
Compare
In regards to how gethostbyname/dns_query is organized
Looking back based on these requirements, I think you're right that there isn't really a need for the literal-parsing behaviour to exist in in dns-query. I'll move it up into the default gethostbyname. With the merge of NetworkInterface/NetworkStack, is there much reason to have gethostbyname an external function? It is really a behaviour provided by the NetworkThing, not necessarily an operation on the NetworkThing. At this point it boils down to |
faf663a
to
d0db597
Compare
I'm doubtful about removing the stack/interface separation. (Unsurprisingly, as I was the one who originally insisted on it). I'm wary you're looking at "smoothing out" single-interface systems at the expense of potentially making multiple-interface (but single-stack) systems a mess. How many multiple-interface examples do you have? But that's for later discussion. The blocking thing isn't related to this PR - just highlighting it for awareness. (Would have been relevant on previous PR). The nsapi->stack API is exceptional here in that it is a blocking call to the stack, unlike all the socket calls. However, unlike sockets, I think it's more likely that a stack may only provide blocking resolution :( Will probably need twin APIs to the stack. The member function thing isn't that big a deal - no terribly strong view on it. See that link earlier for general discussion of the pros and cons - it's not a given that just because it's C++ a member function is to be preferred. So +2 to this is as it stands now. |
Cool : ) The stack/interface separation should probably be a separate discussion (probably on the pr once dependencies are merged). Does this pr limit our ability to reintroduce the stack/interface separation if need be? If we find that the gethostbyname would be better structured a different way based on the future NetworkStack class, it seems resonable to move via deprecation. This current model fits well with the single NetworkInterface interface. |
You can always preserve the implicit interface->stack handover to keep it working, regardless of what happens. The interface object must always know its stack object. |
/morph test |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: 939 All builds and test passed! |
@geky needs a rebase and conflicts resolved |
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.
Updated to match prior conventions - netconn_gethostbyname - gethostbyname_r - gethostbyname2_r - gethostbyaddr_r
Merged duplicated logic into the SocketAddress class. Based on parallel work by @mkaleppanen and @kjbracey-arm. Also added small ipv6 parsing fix by @mikaleppanen
- Not inherently a dns operation - Able to reuse SocketAddress provided to the NetworkInterface
29aa023
to
4f7b10f
Compare
@sg- should be rebased |
Currently in the network-socket API, DNS resolution can only be performed implicitly through functions such as
TCPSocket::connect
,UDPSocket::sendto
, and construction of theSocketAddress
which is limited, returns no errors, requires an unintuitive stack parameter, and as a constructor does not imply a heavy operation.Previously, the network-socket API provided
gethostbyname
in the NetworkInterface, but this was removed when theNetworkStack
class was split out and hidden from users.This pr proposes adding back the
gethostbyname
function with IPv4 and IPv6 support to the NetworkInterface as well asdns_add_server
to allow users to add custom DNS servers and work around limited stacks.These additions do not require changs to NetworkInterface implementations which rely on the network-socket API's dns_query by default.
cc @sg-, @sarahmarshy, @c1728p9