samples: net: sockets: coap_client: Make use of CoAP APIs for observe
The sample oversimplified the observe mechanism a bit - instead of
making use of CoAP APIs to verify the packets received (if they are
actually notifications for the observe) it blindly assumed that any
received packet was a notification. This could be misleading for
potential users of the CoAP library, as the sample had little use as
a reference for the Observer functionality.
Fix this by making use of `coap_reply` structure and a corresponding
`coap_response_received()` function.
Additionally, make the observe cancellation compliant with the CoAP
specification - it should be either an empty Reset message, or a GET
request with Observe option set to 1. The sample used invalid
construct of a Reset message with Observe option. For the purpose of
the sample, use the latter option.
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
diff --git a/samples/net/sockets/coap_client/src/coap-client.c b/samples/net/sockets/coap_client/src/coap-client.c
index 79e2794..9dbaf70 100644
--- a/samples/net/sockets/coap_client/src/coap-client.c
+++ b/samples/net/sockets/coap_client/src/coap-client.c
@@ -388,7 +388,7 @@
return 0;
}
-static int send_obs_reply_ack(uint16_t id)
+static void send_obs_reply_ack(uint16_t id)
{
struct coap_packet request;
uint8_t *data;
@@ -396,7 +396,7 @@
data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN);
if (!data) {
- return -ENOMEM;
+ return;
}
r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN,
@@ -406,21 +406,42 @@
goto end;
}
- net_hexdump("Request", request.data, request.offset);
+ net_hexdump("ACK", request.data, request.offset);
r = send(sock, request.data, request.offset, 0);
+ if (r < 0) {
+ LOG_ERR("Failed to send CoAP ACK");
+ }
end:
k_free(data);
-
- return r;
}
-static int process_obs_coap_reply(void)
+
+static int obs_notification_cb(const struct coap_packet *response,
+ struct coap_reply *reply,
+ const struct sockaddr *from)
{
- struct coap_packet reply;
- uint16_t id;
+ uint16_t id = coap_header_get_id(response);
+ uint8_t type = coap_header_get_type(response);
+ uint8_t *counter = (uint8_t *)reply->user_data;
+
+ ARG_UNUSED(from);
+
+ printk("\nCoAP OBS Notification\n");
+
+ (*counter)++;
+
+ if (type == COAP_TYPE_CON) {
+ send_obs_reply_ack(id);
+ }
+
+ return 0;
+}
+
+static int process_obs_coap_reply(struct coap_reply *reply)
+{
+ struct coap_packet reply_msg;
uint8_t *data;
- uint8_t type;
int rcvd;
int ret;
@@ -449,27 +470,23 @@
net_hexdump("Response", data, rcvd);
- ret = coap_packet_parse(&reply, data, rcvd, NULL, 0);
+ ret = coap_packet_parse(&reply_msg, data, rcvd, NULL, 0);
if (ret < 0) {
LOG_ERR("Invalid data received");
goto end;
}
- id = coap_header_get_id(&reply);
-
- type = coap_header_get_type(&reply);
- if (type == COAP_TYPE_ACK) {
- ret = 0;
- } else if (type == COAP_TYPE_CON) {
- ret = send_obs_reply_ack(id);
+ if (coap_response_received(&reply_msg, NULL, reply, 1) == NULL) {
+ printk("\nOther response received\n");
}
+
end:
k_free(data);
return ret;
}
-static int send_obs_coap_request(void)
+static int send_obs_coap_request(struct coap_reply *reply, void *user_data)
{
struct coap_packet request;
const char * const *p;
@@ -507,6 +524,10 @@
net_hexdump("Request", request.data, request.offset);
+ coap_reply_init(reply, &request);
+ reply->reply = obs_notification_cb;
+ reply->user_data = user_data;
+
r = send(sock, request.data, request.offset, 0);
end:
@@ -515,7 +536,7 @@
return r;
}
-static int send_obs_reset_coap_request(void)
+static int send_obs_reset_coap_request(struct coap_reply *reply)
{
struct coap_packet request;
const char * const *p;
@@ -528,15 +549,15 @@
}
r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN,
- COAP_VERSION_1, COAP_TYPE_RESET,
- COAP_TOKEN_MAX_LEN, coap_next_token(),
- 0, coap_next_id());
+ COAP_VERSION_1, COAP_TYPE_CON,
+ reply->tkl, reply->token,
+ COAP_METHOD_GET, coap_next_id());
if (r < 0) {
LOG_ERR("Failed to init CoAP message");
goto end;
}
- r = coap_append_option_int(&request, COAP_OPTION_OBSERVE, 0);
+ r = coap_append_option_int(&request, COAP_OPTION_OBSERVE, 1);
if (r < 0) {
LOG_ERR("Failed to append Observe option");
goto end;
@@ -563,36 +584,40 @@
static int register_observer(void)
{
- uint8_t counter = 0U;
+ struct coap_reply reply;
+ uint8_t counter = 0;
int r;
- while (1) {
- /* Test CoAP OBS GET method */
- if (!counter) {
- printk("\nCoAP client OBS GET\n");
- r = send_obs_coap_request();
- if (r < 0) {
- return r;
- }
- } else {
- printk("\nCoAP OBS Notification\n");
- }
+ printk("\nCoAP client OBS GET\n");
+ r = send_obs_coap_request(&reply, &counter);
+ if (r < 0) {
+ return r;
+ }
- r = process_obs_coap_reply();
+ while (1) {
+ r = process_obs_coap_reply(&reply);
if (r < 0) {
return r;
}
- counter++;
-
- /* Unregister */
- if (counter == 5U) {
+ if (counter >= 5) {
/* TODO: Functionality can be verified byt waiting for
* some time and make sure client shouldn't receive
* any notifications. If client still receives
* notifications means, Observer is not removed.
*/
- return send_obs_reset_coap_request();
+ r = send_obs_reset_coap_request(&reply);
+ if (r < 0) {
+ return r;
+ }
+
+ /* Wait for the final ACK */
+ r = process_obs_coap_reply(&reply);
+ if (r < 0) {
+ return r;
+ }
+
+ break;
}
}