Skip to content

Add non-blocking DNS functionality to network interface #6751

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 4 commits into from
May 17, 2018
Merged

Add non-blocking DNS functionality to network interface #6751

merged 4 commits into from
May 17, 2018

Conversation

mikaleppanen
Copy link

Description

  • Added non-blocking DNS interface to network interface and network stack.
  • Added caching of DNS replies.
  • Added a network stack function to get DNS addresses from stack.
  • Added call and call_in hooks to onboard network stack to allow calling functions from onboard stack context.
  • Added support to call and call_in functions to LWIP and Nanostack.
  • Disabled LWIP DNS translator with the exception of DNS address storage used in DNS address get.

Pull request type

[ ] Fix
[ ] Refactor
[ ] New target
[X] Feature
[ ] Breaking change

@mikaleppanen
Copy link
Author

@kjbracey-arm @SeppoTakalo Please review

@0xc0170 0xc0170 requested review from kjbracey and SeppoTakalo April 26, 2018 09:40
@0xc0170 0xc0170 changed the title Added non-blocking DNS functionality to network interface Add non-blocking DNS functionality to network interface Apr 26, 2018
@0xc0170
Copy link
Contributor

0xc0170 commented Apr 26, 2018

Please review jenkins CI (undefined functions that are being added here?)


bool sys_tcpip_thread_check(void)
{
osThreadId_t thread_id = osThreadGetId();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm very anti-verbosity, so I would have written this as one line:

return osThreadGetId() == lwip_tcpip_thread_id;

Maybe not to your taste.

Copy link
Author

Choose a reason for hiding this comment

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

Corrected.

@@ -484,6 +484,24 @@ void sys_msleep(u32_t ms) {
osDelay(ms);
}

osThreadId_t lwip_tcpip_thread_id = 0;

bool sys_tcpip_thread_set(void)
Copy link
Contributor

Choose a reason for hiding this comment

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

void return

return NSAPI_ERROR_OK ;
}

static nsapi_error_t nsapi_dns_call_in_default(int delay, mbed::Callback<void()> func)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion - these become the base implementation of NetworkStack::call, and then the logic below becomes if (dns_call) { custom} else { stack->call }.

/** Call a callback
*
* Call a callback from the network stack context. If returns error
* callback will not be called.
Copy link
Contributor

Choose a reason for hiding this comment

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

We need a bit of text about what you can/can't do from here. Don't take significant time, and specify that of the network calls, only non-blocking UDP/datagram calls can be used.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a strange API for a network stack.

Why not expose an event queue by pointer and return NULL if there isn't one used.

Then the user could choose a timer or eventqueue based on their needs.

But also +1 for mentioning that long functions could mess with the network stack.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually thinking about it more this just seems like the wrong direction?

See below


// Allocates in case entry is free, otherwise reuses
if (!dns_cache[index]) {
dns_cache[index] = new DNS_CACHE;
Copy link
Contributor

Choose a reason for hiding this comment

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

This will explode on allocation failure - probably want new (nothrow) DNS_CACHE here with a null check.

* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
*/
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
NetworkStack::hostbyname_cb_t callback, void *data, nsapi_version_t version = NSAPI_IPv4);
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be a Callback - that's slightly more flexible.

See https://os.mbed.com/docs/v5.7/reference/platform.html#callbacks

Copy link
Contributor

Choose a reason for hiding this comment

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

Keep in mind this layer also supports C. But it would be useful to have a C++ overload. The callback class has a thunk member function that can be used when passing to C layer:

void hi(void (*cb)(void *data, int arg), void *data);

Callback<void(int)> cb = function_here;
hi(&Callback<void(int)>::thunk, &cb);

return;
}

nsapi_addr_t *addrs = new nsapi_addr_t[query->addr_count];
Copy link
Contributor

Choose a reason for hiding this comment

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

Mixing C/C++ allocator types is a bit odd. Not going to rule it out, but these C++ ones should probably be nothrow with null checks.

nsapi_addr_t *addrs = new nsapi_addr_t[query->addr_count];

uint32_t ttl;
int count = dns_scan_response((const uint8_t *) packet, id, &ttl, addrs, query->addr_count);
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary cast?

}

// gets id from response to associate with correct query
uint16_t id = (*packet << 8) | *(packet + 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

style nit - I think (packet[0] << 8) | packet[1] is nicer.

* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, void *data,
nsapi_version_t version = NSAPI_UNSPEC);
Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed, drop the data as callback object can already encapsulate it for you.

Other than that +1 for the API.

return NSAPI_ERROR_DNS_FAILURE;
}

return NSAPI_ERROR_OK;
Copy link
Contributor

Choose a reason for hiding this comment

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

Did I miss something?
SocketAddress address is local object.
And you return with NSAPI_ERROR_OK but where do you actually call the callback with this new address, if it was in fact numeric and conversion was OK.

Copy link
Author

Choose a reason for hiding this comment

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

Corrected.

* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, void *data,
nsapi_version_t version = NSAPI_UNSPEC);
Copy link
Contributor

Choose a reason for hiding this comment

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

API is identical with NetworkInterface and NetworkStack so can you move these both to one pure virtual class that both can inherit.

Copy link
Contributor

Choose a reason for hiding this comment

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

If/when the callback can be called synchronously during the gethostbyname_async(), could it be documented here too? Just to avoid surprises.

Copy link
Author

Choose a reason for hiding this comment

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

I'll add note about that.

@kjbracey
Copy link
Contributor

I'd also like @geky and @c1728p9 to cast an eye over this.

@0xc0170 0xc0170 requested review from geky and c1728p9 April 27, 2018 09:06
@geky
Copy link
Contributor

geky commented Apr 27, 2018

@kjbracey-arm, be careful what you ask for : )

@kjbracey
Copy link
Contributor

I'm confident @mikaleppanen's work can withstand the scrutiny. Pretty happy that this is good, just want to make sure it's perfect. Pretty important bit of API.

* @param address On success, destination for the host SocketAddress
* @param data Caller defined data
*/
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address, void *data)> hostbyname_cb_t;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think callback already handles data for you?

nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address)
{
return nsapi_dns_add_server(address);
}

nsapi_error_t NetworkStack::get_dns_server(int index, SocketAddress *address)
{
return NSAPI_ERROR_UNSUPPORTED;
Copy link
Contributor

Choose a reason for hiding this comment

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

Couldn't the default list of dns servers go here?

Copy link
Author

Choose a reason for hiding this comment

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

This is only to return stack specific addresses from DHCP/PPP for network stacks that support those (only LWIP at the moment).

*
* @return Null-terminated representation of the local IP address
* or null if not yet connected
*/
MBED_DEPRECATED_SINCE("mbed-os-5.7",
"Use NetworkInterface::get_ip_address()")
virtual const char *get_ip_address();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this being undeprecated?

Copy link
Contributor

Choose a reason for hiding this comment

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

It actually never has been - that's a proposed deprecation on the feature-emac branch.

On reflection we've decided this is too useful as "get primary network address for this stack", which is what the DNS code among other wants to do to get hints for IPv6-ness, so we've decided not to deprecate.

Note that DNS is definitely a stack thing, but there's an issue that we've no way to get from stack to interface(s). If we were to add NetworkInterface *NetworkStack::get_default_interface() or NetworkInterface *NetworkStack::get_interface(int), we would be able to use those, rather than have these funny network stack calls that implicitly map to default interface.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I see 👍

/** Call a callback
*
* Call a callback from the network stack context. If returns error
* callback will not be called.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a strange API for a network stack.

Why not expose an event queue by pointer and return NULL if there isn't one used.

Then the user could choose a timer or eventqueue based on their needs.

But also +1 for mentioning that long functions could mess with the network stack.

* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
*/
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
NetworkStack::hostbyname_cb_t callback, void *data, nsapi_version_t version = NSAPI_IPv4);
Copy link
Contributor

Choose a reason for hiding this comment

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

Keep in mind this layer also supports C. But it would be useful to have a C++ overload. The callback class has a thunk member function that can be used when passing to C layer:

void hi(void (*cb)(void *data, int arg), void *data);

Callback<void(int)> cb = function_here;
hi(&Callback<void(int)>::thunk, &cb);

* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
*/
nsapi_size_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host,
NetworkStack::hostbyname_cb_t callback, void *data, nsapi_size_t addr_count, nsapi_version_t version = NSAPI_IPv4);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should there be a C verions of nsapi_dns_query_multiple_async? If so it'd need the extern "C" and stuff.

{
if (stack->onboardNetworkStack()) {
OnboardNetworkStack *onboard_stack = reinterpret_cast<OnboardNetworkStack *>(stack);
return onboard_stack->call(func);
Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about it more, I think this is just a bit too upside down. We're poking all these APIs through the network stack because we need them from an API that's called internally?

Why not just pass the necessary things to the more-or-less internal API?

If the dns_query_async API needs an event loop, just make that a necessary argument to the function?

Copy link
Contributor

Choose a reason for hiding this comment

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

The logic here is that we've hit a repeating requirement for network-related stuff to do little tasks. Things like PHY status monitoring in Ethernet drivers. Previously lwip/Nanostack drivers would use lwip/Nanostack event APIs to schedule those. In the EMAC world that's out, and they've been tending to switch to mbed global EventQueues.

Which isn't bad, but it is possible they end up being the only user of the global event queue. It will be the case in the smallest mini client.

So the thought is that we know any onboard network stack must have some sort of event-like mechanism, so this genericises the "run in stack context" drivers have historically used, and it remains the case that it will never spawn an extra thread. We were thinking of Ethernet drivers as much as DNS.

The need for this special API would be eliminated if we required OnboardNetworkStacks to be using EventQueue for their processing, but that's not the case for either LWIP or Nanostack at the moment.

Copy link
Contributor

Choose a reason for hiding this comment

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

But these all seem like things that are called from the network stack, so if the network stack has an event queue couldn't it just be passed to the ethernet drivers at call/init time?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, it effectively would be for drivers - we're not doing that yet. But it's not necessarily an mbed OS EventQueue.

For DNS API purposes the callback context for DNS completion can be API-user specified if they have special requirements for their own event system, or they can say "don't care", in which case they end up getting called in the network stack's context, or the global EventQueue which acts as the default for NetworkStack.

(The whole DNS state machine runs in a single context, so that user-specified context setting has to be global, not per query. They can always use a trampoline to bounce per call if necessary).

Certainly simplest thing for DNS async API would be to require an EventQueue to run on, and default to the global one. But that would mean an extra thread with LWIP and Nanostack, which is what we're trying to avoid. And we're not facing up to restructuring their respective event/thread model to use EventQueue.

Copy link
Contributor

@geky geky Apr 27, 2018

Choose a reason for hiding this comment

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

In that case, do you think we need an abstract EventQueue interface that could be backed by different event queue implementation? Then the DNS/EMAC apis could take in an "EventQueueHandle" that could be backed by the native nanostack event queue.

That may also be a good place to put all of the template madness for the event queue api.

(Name is a joke)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I was thinking something like that might be in order, and was pondering suggesting it. Maybe if we start unambitiously with just the call/call_in API and we can flesh it out later.

(Only reason I was hesitating suggesting it was possible delivery time impact for this PR)

Copy link
Contributor

@geky geky Apr 27, 2018

Choose a reason for hiding this comment

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

Yeah, it would probably take a while. Also not sure it's entirely possible to combine the virutal class with the templating inside the EventQueue.

Maybe you could just pass a pointer to the call_in function?

void emac_function(Callback<int(int ms, Callback<void()> cb)> call_in_cb);

(you could also use call_in(0, blah) for the call function without a timeout if you want one less argument)

Copy link
Author

Choose a reason for hiding this comment

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

I'll change the API so that network stack provides private method to get the callback and that is passed to DNS resolver. That way there will be no public call/call_in interface. Also EMAC can in future can use same kind of interface (as described above).

/** Call a callback
*
* Call a callback from the network stack context. If returns error
* callback will not be called.
Copy link
Contributor

Choose a reason for hiding this comment

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

Actually thinking about it more this just seems like the wrong direction?

See below

@@ -39,6 +39,8 @@ class OnboardNetworkStack : public NetworkStack {
*/
static OnboardNetworkStack &get_default_instance();

virtual OnboardNetworkStack *onboardNetworkStack() { return this; }
Copy link
Contributor

Choose a reason for hiding this comment

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

See below (or above, depending on GitHub ordering). I don't think we need this on this pr

@geky
Copy link
Contributor

geky commented Apr 27, 2018

I left a few comments, but honestly I can't keep up with fully review these prs. So don't let me block anything, and feel free to do whatever you want as long as you take responsibility for the code >: )

}

// Checks if already cached
if (nsapi_dns_cache_find(host, address->get_ip_version(), NULL) == NSAPI_ERROR_OK) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be inside the lock so the state reflects the return value of nsapi_dns_cache_find?

}

if (index < 0) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

You need an unlock here.

* @return 0 on success, negative error code on failure
* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
*/
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
Copy link
Contributor

Choose a reason for hiding this comment

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

There should probably be an abort function to go along with each of these async starts. That way objects using the async APIs can properly cleanup in their destructor if they are destroyed before the async operation has been completed.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree. The cancel needs to be added to this API.

Copy link
Author

Choose a reason for hiding this comment

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

I'll add cancel to the interface.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, with a cancel this PR is a dream come true to us.

continue;
}

// recv the response
err = socket.recvfrom(NULL, packet, DNS_BUFFER_SIZE);
if (err == NSAPI_ERROR_WOULD_BLOCK) {
if (!retry) {
// retries once
Copy link
Contributor

Choose a reason for hiding this comment

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

I've been experimenting with wifi on a bad connection and I often need to do multiple DNS lookups for it to go through. Would it be possible to make the retry number configurable and not fixed to one, please?

Copy link
Author

Choose a reason for hiding this comment

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

I'll add json configuration options about retries.

* @param address On success, destination for the host SocketAddress
* @param data Caller defined data
*/
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address, void *data)> hostbyname_cb_t;
Copy link
Contributor

Choose a reason for hiding this comment

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

As @kjbracey-arm mentioned elsewhere, the documentation of callback should state what can be done from it. I guess typical application would want to connect a socket on success case, or issue another DNS query on failure.

Copy link
Author

Choose a reason for hiding this comment

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

I'll add a note about limitations. Since this is always running from thread it is possible to do more than e.g. for socket sigio(). But thread stack size limits what can be initiated.

If stack sizes are configured larger (lwip, nanostack or global event queue thread) or if application provides callback using nsapi_dns_call_in_set(), at least non-blocking UDP operations and asynchronous DNS query are possible from callback.

* @param address On success, destination for the host SocketAddress
* @param data Caller defined data
*/
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address, void *data)> hostbyname_cb_t;
Copy link
Contributor

Choose a reason for hiding this comment

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

If the query returns multiple addresses, is there a way to iterate through all of them, just as with getaddrinfo() on POSIX?

Copy link
Author

Choose a reason for hiding this comment

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

Like previous blocking interface, multiple addresses are not supported. That might be done later as a new extension to interface.


struct DNS_CACHE {
SocketAddress address;
char host[128];
Copy link
Contributor

Choose a reason for hiding this comment

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

If RFC 1035 states that full DNS name can be 255 bytes, could this non-standard limitation be specified by some configuration option. I have no objection for limiting this by default, but if the max length was exposed via a public define, the client application could use it for its own buffers too. And a space limited application might try to tune the max name length and cache size.

Copy link
Author

Choose a reason for hiding this comment

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

I'll add configuration options to json for both name length and number of entries in cache.

Copy link
Contributor

Choose a reason for hiding this comment

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

We have hit problems with very long Amazon server names - not sure what limit was being breached there. Maybe 64 characters in the ESP8266?

I'd like the default to be the standard if it possibly fits. For a cache with your own internal structures, maybe claw some back by using the nsapi_addr_t, skipping the string literal representation?

Copy link
Author

Choose a reason for hiding this comment

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

Changed limit to 255 and changed storage to use dynamic memory for host name.

}
} else {
if (eventOS_event_send(&event) < 0) {
return NSAPI_ERROR_NO_MEMORY;
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't the cb be deleted on these error cases to avoid memory leaks?

@mikaleppanen
Copy link
Author

Pushed a commit that contains fixes for review defects. Please review the corrections.

* @param callback Callback that is called for result
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
* @return 0 on success, negative error code on failure or an unique id that
Copy link
Contributor

Choose a reason for hiding this comment

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

To pin it down a little: "immediate success"? "immediate failure"? "positive unique id"? Kind of obvious, but just to be utterly clear.

And given it's a 3-way split, maybe put it as 3 separate @return lines rather than 1 long run-on.

Copy link
Author

Choose a reason for hiding this comment

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

Corrected.

* represents the hostname translation operation and can be passed to
* cancel
*/
virtual nsapi_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
Copy link
Contributor

Choose a reason for hiding this comment

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

We have nsapi_size_or_error_t. Wondering if we should have something like that here rather than just using nsapi_error_t. Or maybe make it return int. Passing nsapi_error_t to cancel is weird - I'd like that to take int or some sort of nsapi_id_t. (int is probably fine)

Copy link
Author

Choose a reason for hiding this comment

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

Added new definition: nsapi_value_or_error_t

#define DNS_SERVERS_SIZE 5
#define DNS_RESPONSE_MIN_SIZE 12
#define DNS_MAX_TTL 604800
Copy link
Contributor

Choose a reason for hiding this comment

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

Would help to have this as an expression and comment to clarify the derivation. I gather it's (7*24*60*60) \\ 7 days in seconds.

Although, is there actually any requirement to have this clamp at the client end? Reference?

Copy link
Author

Choose a reason for hiding this comment

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

Removed that.


if (dns_cache[index]) {
dns_cache[index]->address = *address;
dns_cache[index]->host = (char *) malloc(strlen(host) + 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're being C++, new (nothrow) char[strlen(host) + 1]?

Copy link
Author

Choose a reason for hiding this comment

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

Changed to new

dns_cache[index]->host = (char *) malloc(strlen(host) + 1);
strcpy(dns_cache[index]->host, host);
uint64_t ms_count = rtos::Kernel::get_ms_count();
dns_cache[index]->expires = ms_count + ttl * 1000;
Copy link
Contributor

Choose a reason for hiding this comment

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

Technically (if you weren't clamping ttl), you'd want to do something to make sure you don't overflow a 32-bit multiply - (uint64_t) ttt or UINT64_C(1000). This is probably utterly pointless, of course.

Copy link
Author

Choose a reason for hiding this comment

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

Added casting.

"value": 3
},
"dns-retries": {
"help": "Number of DNS query retries that the DNS translator makes per server",
Copy link
Contributor

Choose a reason for hiding this comment

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

Whichever you decide for the previous, seems like it might be best to have the two settings phrased the same. I think this needs a bit more explanation - before moving on to the next server. Total retries/attempts is always limited by "dns-total-retries/attempts".

Copy link
Author

Choose a reason for hiding this comment

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

Updated the description.

static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl)
{
// RFC 1034: if TTL is zero, entry is not added to cache
if (!ttl) {
Copy link
Contributor

Choose a reason for hiding this comment

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

As this is a number, not a boolean, I prefer if (ttl == 0)

Copy link
Author

Choose a reason for hiding this comment

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

Corrected.

dns_cache_mutex.lock();

int index = -1;
uint64_t accessed = ~0;
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe UINT64_MAX? Don't feel strongly.

Copy link
Author

Choose a reason for hiding this comment

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

Corrected.

#define DNS_HOST_NAME_MAX_LEN 255

#ifndef MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME
#define MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME 5000
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need these defaults? I just helped someone out who was confusing himself by trying to change lines like these, rather than the JSON file, to no effect.

Copy link
Author

Choose a reason for hiding this comment

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

Removed those.

query->addrs = 0;
} else {
query->count = resp;
nsapi_dns_call_in(query->call_in_cb, 0, mbed::callback(nsapi_dns_query_async_response, reinterpret_cast<void *>(query->unique_id)));
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this cast necessary?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, seems that adding an int to callback is not possible.

Mika Leppänen added 3 commits May 14, 2018 11:12
- Added non-blocking DNS interface to network interface and
  network stack.
- Added caching of DNS replies.
- Added a network stack function to get DNS addresses from stack.
- Added call and call_in hooks to onboard network stack to
  allow calling functions from onboard stack context.
- Added support to call and call_in functions to LWIP and
  Nanostack.
- Disabled LWIP DNS translator with the exception of DNS
  address storage used in DNS address get.
- Changed call_in/call methods of the stack to callback provided by the stack
- Specified what are limitations for operations that are made in callback
- Added pure virtual class DNS that defines DNS operations
- Added cancel operation and unique ID to DNS request used in cancel
- Added DNS configuration options to netsocket/mbed_lib.json for retries,
  response wait time and cache size
- Changed host name to use dynamic memory in DNS query list and cache,
  set maximum length for the name to 255 bytes.
- Added mutex to asynchronous DNS
- Reworked retries: there is now total retry count and a server specific count
- Ignores invalid incoming UDP socket messages (DNS header is not valid), and retries DNS query
- Reworked DNS module asynchronous operation functions
- Corrected other review issues (nothrow new, missing free, missing mutex unlock etc.)
- Serialized the sending of multiple async DNS queries since limits on event
message box sizes
- Added timer function that supervises the total time used to make DNS query
and triggers socket timeouts
- Changed nsapi_error_t to new nsapi_value_or_error_t on interface headers
- Corrected wording of gethostbyname_async return values
- Clarified .json options
- Added a new data type for socket callback that can be used from interrupts
- Corrected variable limits to use INT32_MAX etc. defines
- Changed mallocs to new
- Optimized variable sizes on DNS_QUERY definition
@mikaleppanen
Copy link
Author

Corrected defects, please review.

@cmonr
Copy link
Contributor

cmonr commented May 14, 2018

/morph build

@mbed-ci
Copy link

mbed-ci commented May 14, 2018

Build : SUCCESS

Build number : 2009
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/6751/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build
/morph mbed2-build

@mbed-ci
Copy link

mbed-ci commented May 15, 2018

// Protects cache shared between blocking and asynchronous calls
static rtos::Mutex dns_cache_mutex;
// Protects from several threads running asynchronous DNS
static rtos::Mutex dns_mutex;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these be PlatformMutex:es instead to support non-RTOS compilation?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, they can be. Changed them into PlatformMutex:es.


nsapi_dns_query_async_resp(query, status, addresses);

if (addresses) {
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to check for NULL before calling operator delete.

Copy link
Author

Choose a reason for hiding this comment

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

Corrected.

Copy link
Contributor

@TeroJaasko TeroJaasko left a comment

Choose a reason for hiding this comment

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

+3

- Changed mutexes to platform mutexes
- Removed not needed null check from delete
- Changed nsapi_dns_call_in_set() to use call_in_callback_cb_t and
added prototype to header
@mbed-ci
Copy link

mbed-ci commented May 15, 2018

@cmonr
Copy link
Contributor

cmonr commented May 15, 2018

/morph export-build

@kjbracey kjbracey merged commit 21d21c5 into ARMmbed:feature-emac May 17, 2018
@cmonr
Copy link
Contributor

cmonr commented May 18, 2018

@kjbracey-arm Echoing an earlier question. Why are you assigning release-version tags to PRs going into the feature-emac branch?

@adbridge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants