diff --git a/TESTS/netsocket/dns/asynchronous_dns_cancel.cpp b/TESTS/netsocket/dns/asynchronous_dns_cancel.cpp index 1f9c6f8436..0cc0a8a218 100644 --- a/TESTS/netsocket/dns/asynchronous_dns_cancel.cpp +++ b/TESTS/netsocket/dns/asynchronous_dns_cancel.cpp @@ -35,15 +35,15 @@ void ASYNCHRONOUS_DNS_CANCEL() data[i].semaphore = &semaphore; data[i].req_result = get_interface()->gethostbyname_async(dns_test_hosts[i], mbed::Callback(hostbyname_cb, (void *) &data[i])); - TEST_ASSERT(data[i].req_result >= 0 || data[i].req_result == NSAPI_ERROR_NO_MEMORY); + TEST_ASSERT(data[i].req_result >= 0 || data[i].req_result == NSAPI_ERROR_NO_MEMORY || data[i].req_result == NSAPI_ERROR_BUSY); if (data[i].req_result >= 0) { // Callback will be called count++; } else { // No memory to initiate DNS query, callback will not be called - printf("Error: No memory to initiate DNS query for %s\n", dns_test_hosts[i]); - data[i].result = NSAPI_ERROR_NO_MEMORY; + printf("Error: No resources to initiate DNS query for %s\n", dns_test_hosts[i]); + data[i].result = data[i].req_result; data[i].value_set = true; } } @@ -66,7 +66,7 @@ void ASYNCHRONOUS_DNS_CANCEL() printf("DNS: query \"%s\" => cancel\n", dns_test_hosts[i]); continue; } - TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT); + TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT); if (data[i].result == NSAPI_ERROR_OK) { printf("DNS: query \"%s\" => \"%s\"\n", dns_test_hosts[i], data[i].addr.get_ip_address()); @@ -76,6 +76,8 @@ void ASYNCHRONOUS_DNS_CANCEL() printf("DNS: query \"%s\" => timeout\n", dns_test_hosts[i]); } else if (data[i].result == NSAPI_ERROR_NO_MEMORY) { printf("DNS: query \"%s\" => no memory\n", dns_test_hosts[i]); + } else if (data[i].result == NSAPI_ERROR_BUSY) { + printf("DNS: query \"%s\" => busy\n", dns_test_hosts[i]); } } diff --git a/TESTS/netsocket/dns/dns_tests.h b/TESTS/netsocket/dns/dns_tests.h index 383f0aeabe..aaec1cd458 100644 --- a/TESTS/netsocket/dns/dns_tests.h +++ b/TESTS/netsocket/dns/dns_tests.h @@ -19,8 +19,12 @@ #define DNS_TESTS_H #ifndef MBED_CONF_APP_DNS_SIMULT_QUERIES +#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES +#define MBED_CONF_APP_DNS_SIMULT_QUERIES MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES +#else #define MBED_CONF_APP_DNS_SIMULT_QUERIES 5 #endif +#endif #ifndef MBED_CONF_NSAPI_DNS_CACHE_SIZE #define MBED_CONF_NSAPI_DNS_CACHE_SIZE 3 diff --git a/TESTS/netsocket/dns/main.cpp b/TESTS/netsocket/dns/main.cpp index 20e594885a..62da4e71d1 100644 --- a/TESTS/netsocket/dns/main.cpp +++ b/TESTS/netsocket/dns/main.cpp @@ -70,13 +70,13 @@ void do_asynchronous_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsign for (unsigned int i = 0; i < op_count; i++) { data[i].semaphore = &semaphore; nsapi_error_t err = net->gethostbyname_async(hosts[i], mbed::Callback(hostbyname_cb, (void *) &data[i])); - TEST_ASSERT(err >= 0 || err == NSAPI_ERROR_NO_MEMORY); + TEST_ASSERT(err >= 0 || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_BUSY); if (err >= 0) { // Callback will be called count++; } else { // No memory to initiate DNS query, callback will not be called - data[i].result = NSAPI_ERROR_NO_MEMORY; + data[i].result = err; } } @@ -87,7 +87,7 @@ void do_asynchronous_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsign // Print result for (unsigned int i = 0; i < op_count; i++) { - TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT); + TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT); if (data[i].result == NSAPI_ERROR_OK) { (*exp_ok)++; printf("DNS: query \"%s\" => \"%s\"\n", @@ -101,6 +101,9 @@ void do_asynchronous_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsign } else if (data[i].result == NSAPI_ERROR_NO_MEMORY) { (*exp_no_mem)++; printf("DNS: query \"%s\" => no memory\n", hosts[i]); + } else if (data[i].result == NSAPI_ERROR_BUSY) { + (*exp_no_mem)++; + printf("DNS: query \"%s\" => busy\n", hosts[i]); } } @@ -135,9 +138,12 @@ void do_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsigned int op_cou } else if (err == NSAPI_ERROR_NO_MEMORY) { (*exp_no_mem)++; printf("DNS: query \"%s\" => no memory\n", hosts[i]); + } else if (err == NSAPI_ERROR_BUSY) { + (*exp_no_mem)++; + printf("DNS: query \"%s\" => busy\n", hosts[i]); } else { printf("DNS: query \"%s\" => %d, unexpected answer\n", hosts[i], err); - TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_DNS_FAILURE || err == NSAPI_ERROR_TIMEOUT); + TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_BUSY || err == NSAPI_ERROR_DNS_FAILURE || err == NSAPI_ERROR_TIMEOUT); } } } @@ -181,12 +187,18 @@ Case cases[] = { Case("ASYNCHRONOUS_DNS", ASYNCHRONOUS_DNS), Case("ASYNCHRONOUS_DNS_SIMULTANEOUS", ASYNCHRONOUS_DNS_SIMULTANEOUS), Case("ASYNCHRONOUS_DNS_SIMULTANEOUS_CACHE", ASYNCHRONOUS_DNS_SIMULTANEOUS_CACHE), +#ifndef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES Case("ASYNCHRONOUS_DNS_CACHE", ASYNCHRONOUS_DNS_CACHE), +#endif +#if !defined MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES || MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES > MBED_CONF_APP_DNS_TEST_HOSTS_NUM Case("ASYNCHRONOUS_DNS_NON_ASYNC_AND_ASYNC", ASYNCHRONOUS_DNS_NON_ASYNC_AND_ASYNC), +#endif Case("ASYNCHRONOUS_DNS_CANCEL", ASYNCHRONOUS_DNS_CANCEL), +#ifndef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES Case("ASYNCHRONOUS_DNS_EXTERNAL_EVENT_QUEUE", ASYNCHRONOUS_DNS_EXTERNAL_EVENT_QUEUE), Case("ASYNCHRONOUS_DNS_INVALID_HOST", ASYNCHRONOUS_DNS_INVALID_HOST), Case("ASYNCHRONOUS_DNS_TIMEOUTS", ASYNCHRONOUS_DNS_TIMEOUTS), +#endif Case("ASYNCHRONOUS_DNS_SIMULTANEOUS_REPEAT", ASYNCHRONOUS_DNS_SIMULTANEOUS_REPEAT), Case("SYNCHRONOUS_DNS", SYNCHRONOUS_DNS), Case("SYNCHRONOUS_DNS_MULTIPLE", SYNCHRONOUS_DNS_MULTIPLE), diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp index ddaf6fe786..db181f5286 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp @@ -21,9 +21,15 @@ using namespace mbed; QUECTEL_BG96_CellularStack::QUECTEL_BG96_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type) +#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES + , _dns_callback(NULL), _dns_version(NSAPI_UNSPEC) +#endif { _at.set_urc_handler("+QIURC: \"recv", mbed::Callback(this, &QUECTEL_BG96_CellularStack::urc_qiurc_recv)); _at.set_urc_handler("+QIURC: \"close", mbed::Callback(this, &QUECTEL_BG96_CellularStack::urc_qiurc_closed)); +#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES + _at.set_urc_handler("+QIURC: \"dnsgip\",", mbed::Callback(this, &QUECTEL_BG96_CellularStack::urc_qiurc_dnsgip)); +#endif } QUECTEL_BG96_CellularStack::~QUECTEL_BG96_CellularStack() @@ -102,6 +108,41 @@ void QUECTEL_BG96_CellularStack::urc_qiurc_closed() urc_qiurc(URC_CLOSED); } +#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES +bool QUECTEL_BG96_CellularStack::read_dnsgip(SocketAddress &address, nsapi_version_t _dns_version) +{ + if (_at.read_int() == 0) { + int count = _at.read_int(); + _at.skip_param(); + for (; count > 0; count--) { + _at.resp_start("+QIURC: \"dnsgip\","); + char ipAddress[NSAPI_IP_SIZE]; + _at.read_string(ipAddress, sizeof(ipAddress)); + if (address.set_ip_address(ipAddress)) { + if (_dns_version == NSAPI_UNSPEC || _dns_version == address.get_ip_version()) { + return true; + } + } + } + } + return false; +} + +void QUECTEL_BG96_CellularStack::urc_qiurc_dnsgip() +{ + if (!_dns_callback) { + return; + } + SocketAddress address; + if (read_dnsgip(address, _dns_version)) { + _dns_callback(NSAPI_ERROR_OK, &address); + } else { + _dns_callback(NSAPI_ERROR_DNS_FAILURE, NULL); + } + _dns_callback = NULL; +} +#endif + void QUECTEL_BG96_CellularStack::urc_qiurc(urc_type_t urc_type) { _at.lock(); @@ -299,3 +340,64 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_recvfrom_impl(CellularS return recv_len; } + +#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES +nsapi_error_t QUECTEL_BG96_CellularStack::gethostbyname(const char *host, SocketAddress *address, + nsapi_version_t version, const char *interface_name) +{ + (void) interface_name; + MBED_ASSERT(host); + MBED_ASSERT(address); + + _at.lock(); + + if (_dns_callback) { + _at.unlock(); + return NSAPI_ERROR_BUSY; + } + + if (!address->set_ip_address(host)) { + _at.set_at_timeout(60 * 1000); // from BG96_TCP/IP_AT_Commands_Manual_V1.0 + _at.at_cmd_discard("+QIDNSGIP", "=", "%d%s", _cid, host); + _at.resp_start("+QIURC: \"dnsgip\","); + _at.restore_at_timeout(); + if (!read_dnsgip(*address, version)) { + _at.unlock(); + return NSAPI_ERROR_DNS_FAILURE; + } + } + + return _at.unlock_return_error(); +} + +nsapi_value_or_error_t QUECTEL_BG96_CellularStack::gethostbyname_async(const char *host, hostbyname_cb_t callback, + nsapi_version_t version, const char *interface_name) +{ + (void) interface_name; + MBED_ASSERT(host); + MBED_ASSERT(callback); + + _at.lock(); + + if (_dns_callback) { + _at.unlock(); + return NSAPI_ERROR_BUSY; + } + + _at.at_cmd_discard("+QIDNSGIP", "=", "%d%s", _cid, host); + if (!_at.get_last_error()) { + _dns_callback = callback; + _dns_version = version; + } + + return _at.unlock_return_error() ? NSAPI_ERROR_DNS_FAILURE : NSAPI_ERROR_OK; +} + +nsapi_error_t QUECTEL_BG96_CellularStack::gethostbyname_async_cancel(int id) +{ + _at.lock(); + _dns_callback = NULL; + _at.unlock(); + return NSAPI_ERROR_OK; +} +#endif diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.h b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.h index ae993ccbee..b89cc2ded4 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.h +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.h @@ -48,6 +48,13 @@ protected: // NetworkStack virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address); +#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES + virtual nsapi_error_t gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version, const char *interface_name); + virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC, + const char *interface_name = NULL); + virtual nsapi_error_t gethostbyname_async_cancel(int id); +#endif + protected: // AT_CellularStack virtual int get_max_socket_count(); @@ -73,6 +80,15 @@ private: void urc_qiurc_closed(); void handle_open_socket_response(int &modem_connect_id, int &err); + +#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES + // URC handler for DNS query + void urc_qiurc_dnsgip(); + // read DNS query result + bool read_dnsgip(SocketAddress &address, nsapi_version_t _dns_version); + hostbyname_cb_t _dns_callback; + nsapi_version_t _dns_version; +#endif }; } // namespace mbed #endif /* QUECTEL_BG96_CELLULARSTACK_H_ */ diff --git a/features/cellular/mbed_lib.json b/features/cellular/mbed_lib.json index 669521b1a2..bec9c8eaa8 100644 --- a/features/cellular/mbed_lib.json +++ b/features/cellular/mbed_lib.json @@ -20,6 +20,10 @@ "control-plane-opt": { "help": "Enables control plane CIoT EPS optimization", "value": false + }, + "offload-dns-queries" : { + "help": "Use modem IP stack for DNS queries, null or numeric simultaneous queries", + "value": null } } }