net: lib: coap_client: check poll() condition before retrying CoAP msg
Refactor the CoAP retry handling into the handle_poll() function, so that we only try to send retries if the socket reports POLLOUT. Also move the receiving into same loop, so when poll() reports POLLIN we recv() the message and handle it before proceeding to other sockets. Also fix tests to handle POLLOUT flag and add support for testing multiple clients. Signed-off-by: Seppo Takalo <seppo.takalo@nordicsemi.no>
This commit is contained in:
parent
46b7c84512
commit
4c6dd4c7b7
6 changed files with 194 additions and 147 deletions
|
@ -31,3 +31,4 @@ add_compile_definitions(CONFIG_COAP_CLIENT_MAX_REQUESTS=2)
|
|||
add_compile_definitions(CONFIG_COAP_CLIENT_MAX_INSTANCES=2)
|
||||
add_compile_definitions(CONFIG_COAP_MAX_RETRANSMIT=4)
|
||||
add_compile_definitions(CONFIG_COAP_BACKOFF_PERCENT=200)
|
||||
add_compile_definitions(CONFIG_COAP_LOG_LEVEL=4)
|
||||
|
|
|
@ -77,7 +77,7 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake(int sock, void *buf, size_t max
|
|||
|
||||
memcpy(buf, ack_data, sizeof(ack_data));
|
||||
|
||||
clear_socket_events();
|
||||
clear_socket_events(ZSOCK_POLLIN);
|
||||
|
||||
return sizeof(ack_data);
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake_response(int sock, void *buf, s
|
|||
|
||||
memcpy(buf, ack_data, sizeof(ack_data));
|
||||
|
||||
clear_socket_events();
|
||||
clear_socket_events(ZSOCK_POLLIN);
|
||||
|
||||
return sizeof(ack_data);
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake_unmatching(int sock, void *buf,
|
|||
|
||||
memcpy(buf, ack_data, sizeof(ack_data));
|
||||
|
||||
clear_socket_events();
|
||||
clear_socket_events(ZSOCK_POLLIN);
|
||||
|
||||
return sizeof(ack_data);
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake_echo(int sock, void *buf, size_
|
|||
z_impl_zsock_recvfrom_fake.custom_fake = z_impl_zsock_recvfrom_custom_fake_response;
|
||||
z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_custom_fake_echo;
|
||||
|
||||
clear_socket_events();
|
||||
clear_socket_events(ZSOCK_POLLIN);
|
||||
|
||||
return sizeof(ack_data);
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake_echo_next_req(int sock, void *b
|
|||
z_impl_zsock_recvfrom_fake.custom_fake = z_impl_zsock_recvfrom_custom_fake_response;
|
||||
z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_custom_fake_echo_next_req;
|
||||
|
||||
clear_socket_events();
|
||||
clear_socket_events(ZSOCK_POLLIN);
|
||||
|
||||
return sizeof(ack_data);
|
||||
}
|
||||
|
@ -335,6 +335,9 @@ void coap_callback(int16_t code, size_t offset, const uint8_t *payload, size_t l
|
|||
{
|
||||
LOG_INF("CoAP response callback, %d", code);
|
||||
last_response_code = code;
|
||||
if (user_data) {
|
||||
k_sem_give((struct k_sem *) user_data);
|
||||
}
|
||||
}
|
||||
|
||||
ZTEST_SUITE(coap_client, NULL, suite_setup, test_setup, NULL, NULL);
|
||||
|
@ -392,7 +395,7 @@ ZTEST(coap_client, test_resend_request)
|
|||
ret = coap_client_req(&client, 0, &address, &client_request, NULL);
|
||||
zassert_true(ret >= 0, "Sending request failed, %d", ret);
|
||||
k_sleep(K_MSEC(MORE_THAN_ACK_TIMEOUT_MS));
|
||||
set_socket_events(ZSOCK_POLLIN);
|
||||
set_socket_events(ZSOCK_POLLIN | ZSOCK_POLLOUT);
|
||||
|
||||
k_sleep(K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS));
|
||||
zassert_equal(last_response_code, COAP_RESPONSE_CODE_OK, "Unexpected response");
|
||||
|
@ -547,6 +550,7 @@ ZTEST(coap_client, test_no_response)
|
|||
client_request.len = strlen(short_payload);
|
||||
|
||||
z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_custom_fake_no_reply;
|
||||
set_socket_events(ZSOCK_POLLOUT);
|
||||
|
||||
k_sleep(K_MSEC(1));
|
||||
|
||||
|
@ -592,30 +596,35 @@ ZTEST(coap_client, test_multiple_requests)
|
|||
{
|
||||
int ret = 0;
|
||||
int retry = MORE_THAN_EXCHANGE_LIFETIME_MS;
|
||||
struct k_sem sem1, sem2;
|
||||
|
||||
struct sockaddr address = {0};
|
||||
struct coap_client_request client_request = {
|
||||
struct coap_client_request req1 = {
|
||||
.method = COAP_METHOD_GET,
|
||||
.confirmable = true,
|
||||
.path = test_path,
|
||||
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
|
||||
.cb = coap_callback,
|
||||
.payload = NULL,
|
||||
.len = 0
|
||||
.payload = short_payload,
|
||||
.len = strlen(short_payload),
|
||||
.user_data = &sem1
|
||||
};
|
||||
struct coap_client_request req2 = req1;
|
||||
|
||||
client_request.payload = short_payload;
|
||||
client_request.len = strlen(short_payload);
|
||||
req2.user_data = &sem2;
|
||||
|
||||
k_sem_init(&sem1, 0, 1);
|
||||
k_sem_init(&sem2, 0, 1);
|
||||
|
||||
z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_custom_fake_no_reply;
|
||||
|
||||
k_sleep(K_MSEC(1));
|
||||
|
||||
LOG_INF("Send request");
|
||||
ret = coap_client_req(&client, 0, &address, &client_request, NULL);
|
||||
ret = coap_client_req(&client, 0, &address, &req1, NULL);
|
||||
zassert_true(ret >= 0, "Sending request failed, %d", ret);
|
||||
|
||||
ret = coap_client_req(&client, 0, &address, &client_request, NULL);
|
||||
ret = coap_client_req(&client, 0, &address, &req2, NULL);
|
||||
zassert_true(ret >= 0, "Sending request failed, %d", ret);
|
||||
|
||||
set_socket_events(ZSOCK_POLLIN);
|
||||
|
@ -625,8 +634,10 @@ ZTEST(coap_client, test_multiple_requests)
|
|||
}
|
||||
zassert_equal(last_response_code, COAP_RESPONSE_CODE_OK, "Unexpected response");
|
||||
|
||||
last_response_code = 0;
|
||||
set_socket_events(ZSOCK_POLLIN);
|
||||
k_sleep(K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS));
|
||||
zassert_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
|
||||
zassert_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
|
||||
zassert_equal(last_response_code, COAP_RESPONSE_CODE_OK, "Unexpected response");
|
||||
}
|
||||
|
||||
|
@ -653,6 +664,7 @@ ZTEST(coap_client, test_unmatching_tokens)
|
|||
client_request.len = strlen(short_payload);
|
||||
|
||||
z_impl_zsock_recvfrom_fake.custom_fake = z_impl_zsock_recvfrom_custom_fake_unmatching;
|
||||
set_socket_events(ZSOCK_POLLIN | ZSOCK_POLLOUT);
|
||||
|
||||
k_sleep(K_MSEC(1));
|
||||
|
||||
|
@ -663,3 +675,57 @@ ZTEST(coap_client, test_unmatching_tokens)
|
|||
k_sleep(K_MSEC(MORE_THAN_LONG_EXCHANGE_LIFETIME_MS));
|
||||
zassert_equal(last_response_code, -ETIMEDOUT, "Unexpected response");
|
||||
}
|
||||
|
||||
ZTEST(coap_client, test_multiple_clients)
|
||||
{
|
||||
int ret;
|
||||
int retry = MORE_THAN_EXCHANGE_LIFETIME_MS;
|
||||
static struct coap_client client2 = {
|
||||
.fd = 2,
|
||||
};
|
||||
struct k_sem sem1, sem2;
|
||||
struct sockaddr address = {0};
|
||||
struct coap_client_request req1 = {
|
||||
.method = COAP_METHOD_GET,
|
||||
.confirmable = true,
|
||||
.path = test_path,
|
||||
.fmt = COAP_CONTENT_FORMAT_TEXT_PLAIN,
|
||||
.cb = coap_callback,
|
||||
.payload = short_payload,
|
||||
.len = strlen(short_payload),
|
||||
.user_data = &sem1
|
||||
};
|
||||
struct coap_client_request req2 = req1;
|
||||
|
||||
req2.user_data = &sem2;
|
||||
req2.payload = long_payload;
|
||||
req2.len = strlen(long_payload);
|
||||
|
||||
zassert_ok(k_sem_init(&sem1, 0, 1));
|
||||
zassert_ok(k_sem_init(&sem2, 0, 1));
|
||||
|
||||
zassert_ok(coap_client_init(&client2, NULL));
|
||||
|
||||
k_sleep(K_MSEC(1));
|
||||
|
||||
LOG_INF("Sending requests");
|
||||
ret = coap_client_req(&client, 1, &address, &req1, NULL);
|
||||
zassert_true(ret >= 0, "Sending request failed, %d", ret);
|
||||
|
||||
ret = coap_client_req(&client2, 2, &address, &req2, NULL);
|
||||
zassert_true(ret >= 0, "Sending request failed, %d", ret);
|
||||
|
||||
while (last_response_code == 0 && retry > 0) {
|
||||
retry--;
|
||||
k_sleep(K_MSEC(1));
|
||||
}
|
||||
set_socket_events(ZSOCK_POLLIN);
|
||||
|
||||
k_sleep(K_SECONDS(1));
|
||||
|
||||
/* ensure we got both responses */
|
||||
zassert_ok(k_sem_take(&sem1, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
|
||||
zassert_ok(k_sem_take(&sem2, K_MSEC(MORE_THAN_EXCHANGE_LIFETIME_MS)));
|
||||
zassert_equal(last_response_code, COAP_RESPONSE_CODE_OK, "Unexpected response");
|
||||
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ void set_socket_events(short events)
|
|||
my_events |= events;
|
||||
}
|
||||
|
||||
void clear_socket_events(void)
|
||||
void clear_socket_events(short events)
|
||||
{
|
||||
my_events = 0;
|
||||
my_events &= ~events;
|
||||
}
|
||||
|
||||
int z_impl_zsock_socket(int family, int type, int proto)
|
||||
|
@ -41,13 +41,14 @@ int z_impl_zsock_socket(int family, int type, int proto)
|
|||
|
||||
int z_impl_zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout)
|
||||
{
|
||||
LOG_INF("Polling, events %d", my_events);
|
||||
int events = 0;
|
||||
k_sleep(K_MSEC(1));
|
||||
fds->revents = my_events;
|
||||
|
||||
if (my_events) {
|
||||
return 1;
|
||||
for (int i = 0; i < nfds; i++) {
|
||||
fds[i].revents = my_events & (fds[i].events | ZSOCK_POLLERR | ZSOCK_POLLHUP);
|
||||
if (fds[i].revents) {
|
||||
events++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return events;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,30 @@
|
|||
|
||||
#include <zephyr/net/coap_client.h>
|
||||
|
||||
#define ZSOCK_POLLIN 1
|
||||
|
||||
/* Copy from zephyr/include/zephyr/net/socket.h */
|
||||
/**
|
||||
* @name Options for poll()
|
||||
* @{
|
||||
*/
|
||||
/* ZSOCK_POLL* values are compatible with Linux */
|
||||
/** zsock_poll: Poll for readability */
|
||||
#define ZSOCK_POLLIN 1
|
||||
/** zsock_poll: Poll for exceptional condition */
|
||||
#define ZSOCK_POLLPRI 2
|
||||
/** zsock_poll: Poll for writability */
|
||||
#define ZSOCK_POLLOUT 4
|
||||
/** zsock_poll: Poll results in error condition (output value only) */
|
||||
#define ZSOCK_POLLERR 8
|
||||
/** zsock_poll: Poll detected closed connection (output value only) */
|
||||
#define ZSOCK_POLLHUP 0x10
|
||||
/** zsock_poll: Invalid socket (output value only) */
|
||||
#define ZSOCK_POLLNVAL 0x20
|
||||
/** @} */
|
||||
|
||||
|
||||
void set_socket_events(short events);
|
||||
void clear_socket_events(void);
|
||||
void clear_socket_events(short events);
|
||||
|
||||
DECLARE_FAKE_VALUE_FUNC(uint32_t, z_impl_sys_rand32_get);
|
||||
DECLARE_FAKE_VOID_FUNC(z_impl_sys_rand_get, void *, size_t);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue