1 /** @file
2  * @brief CoAP client API
3  *
4  * An API for applications to do CoAP requests
5  */
6 
7 /*
8  * Copyright (c) 2023 Nordic Semiconductor ASA
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 #ifndef ZEPHYR_INCLUDE_NET_COAP_CLIENT_H_
13 #define ZEPHYR_INCLUDE_NET_COAP_CLIENT_H_
14 
15 /**
16  * @brief CoAP client API
17  * @defgroup coap_client CoAP client API
18  * @since 3.4
19  * @version 0.1.0
20  * @ingroup networking
21  * @{
22  */
23 
24 #include <zephyr/net/coap.h>
25 #include <zephyr/kernel.h>
26 
27 /** Maximum size of a CoAP message */
28 #define MAX_COAP_MSG_LEN (CONFIG_COAP_CLIENT_MESSAGE_HEADER_SIZE + \
29 			  CONFIG_COAP_CLIENT_MESSAGE_SIZE)
30 
31 /**
32  * @typedef coap_client_response_cb_t
33  * @brief Callback for CoAP request.
34  *
35  * This callback is called for responses to CoAP client requests.
36  * It is used to indicate errors, response codes from server or to deliver payload.
37  * Blockwise transfers cause this callback to be called sequentially with increasing payload offset
38  * and only partial content in buffer pointed by payload parameter.
39  *
40  * @param result_code Result code of the response. Negative if there was a failure in send.
41  *                    @ref coap_response_code for positive.
42  * @param offset Payload offset from the beginning of a blockwise transfer.
43  * @param payload Buffer containing the payload from the response. NULL for empty payload.
44  * @param len Size of the payload.
45  * @param last_block Indicates the last block of the response.
46  * @param user_data User provided context.
47  */
48 typedef void (*coap_client_response_cb_t)(int16_t result_code,
49 					  size_t offset, const uint8_t *payload, size_t len,
50 					  bool last_block, void *user_data);
51 
52 /**
53  * @brief Representation of a CoAP client request.
54  */
55 struct coap_client_request {
56 	enum coap_method method;                  /**< Method of the request */
57 	bool confirmable;                         /**< CoAP Confirmable/Non-confirmable message */
58 	const char *path;                         /**< Path of the requested resource */
59 	enum coap_content_format fmt;             /**< Content format to be used */
60 	const uint8_t *payload;                   /**< User allocated buffer for send request */
61 	size_t len;                               /**< Length of the payload */
62 	coap_client_response_cb_t cb;             /**< Callback when response received */
63 	const struct coap_client_option *options; /**< Extra options to be added to request */
64 	uint8_t num_options;                      /**< Number of extra options */
65 	void *user_data;                          /**< User provided context */
66 };
67 
68 /**
69  * @brief Representation of extra options for the CoAP client request
70  */
71 struct coap_client_option {
72 	/** Option code */
73 	uint16_t code;
74 #if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN)
75 	/** Option len */
76 	uint16_t len;
77 	/** Buffer for the length */
78 	uint8_t value[CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE];
79 #else
80 	/** Option len */
81 	uint8_t len;
82 	/** Buffer for the length */
83 	uint8_t value[12];
84 #endif
85 };
86 
87 /** @cond INTERNAL_HIDDEN */
88 struct coap_client_internal_request {
89 	uint8_t request_token[COAP_TOKEN_MAX_LEN];
90 	uint32_t offset;
91 	uint16_t last_id;
92 	uint8_t request_tkl;
93 	bool request_ongoing;
94 	atomic_t in_callback;
95 	struct coap_block_context recv_blk_ctx;
96 	struct coap_block_context send_blk_ctx;
97 	struct coap_pending pending;
98 	struct coap_client_request coap_request;
99 	struct coap_packet request;
100 	uint8_t request_tag[COAP_TOKEN_MAX_LEN];
101 
102 	/* For GETs with observe option set */
103 	bool is_observe;
104 	int last_response_id;
105 };
106 
107 struct coap_client {
108 	int fd;
109 	struct sockaddr address;
110 	socklen_t socklen;
111 	struct k_mutex lock;
112 	uint8_t send_buf[MAX_COAP_MSG_LEN];
113 	uint8_t recv_buf[MAX_COAP_MSG_LEN];
114 	struct coap_client_internal_request requests[CONFIG_COAP_CLIENT_MAX_REQUESTS];
115 	struct coap_option echo_option;
116 	bool send_echo;
117 };
118 /** @endcond */
119 
120 /**
121  * @brief Initialize the CoAP client.
122  *
123  * @param[in] client Client instance.
124  * @param[in] info Name for the receiving thread of the client. Setting this NULL will result as
125  *                 default name of "coap_client".
126  *
127  * @return int Zero on success, otherwise a negative error code.
128  */
129 int coap_client_init(struct coap_client *client, const char *info);
130 
131 /**
132  * @brief Send CoAP request
133  *
134  * Operation is handled asynchronously using a background thread.
135  * If the socket isn't connected to a destination address, user must provide a destination address,
136  * otherwise the address should be set as NULL.
137  * Once the callback is called with last block set as true, socket can be closed or
138  * used for another query.
139  *
140  * @param client Client instance.
141  * @param sock Open socket file descriptor.
142  * @param addr the destination address of the request, NULL if socket is already connected.
143  * @param req CoAP request structure
144  * @param params Pointer to transmission parameters structure or NULL to use default values.
145  * @return zero when operation started successfully or negative error code otherwise.
146  */
147 
148 int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr,
149 		    struct coap_client_request *req, struct coap_transmission_parameters *params);
150 
151 /**
152  * @brief Cancel all current requests.
153  *
154  * This is intended for canceling long-running requests (e.g. GETs with the OBSERVE option set)
155  * which has gone stale for some reason.
156  *
157  * @param client Client instance.
158  */
159 void coap_client_cancel_requests(struct coap_client *client);
160 
161 /**
162  * @brief Cancel matching requests.
163  *
164  * This function cancels all CoAP client request that matches the given request.
165  * The request is matched based on the method, path, callback and user_data, if provided.
166  * Any field set to NULL is considered a wildcard.
167  *
168  * (struct coap_client_request){0} cancels all requests.
169  * (struct coap_client_request){.method = COAP_METHOD_GET} cancels all GET requests.
170  *
171  * @param client Pointer to the CoAP client instance.
172  * @param req Pointer to the CoAP client request to be canceled.
173  */
174 void coap_client_cancel_request(struct coap_client *client, struct coap_client_request *req);
175 
176 /**
177  * @brief Initialise a Block2 option to be added to a request
178  *
179  * If the application expects a request to require a blockwise transfer, it may pre-emptively
180  * suggest a maximum block size to the server - see RFC7959 Figure 3: Block-Wise GET with Early
181  * Negotiation.
182  *
183  * This helper function returns a Block2 option to send with the initial request.
184  *
185  * @return CoAP client initial Block2 option structure
186  */
coap_client_option_initial_block2(void)187 static inline struct coap_client_option coap_client_option_initial_block2(void)
188 {
189 	struct coap_client_option block2 = {
190 		.code = COAP_OPTION_BLOCK2,
191 		.len = 1,
192 		.value[0] = coap_bytes_to_block_size(CONFIG_COAP_CLIENT_BLOCK_SIZE),
193 	};
194 
195 	return block2;
196 }
197 
198 /**
199  * @}
200  */
201 
202 #endif /* ZEPHYR_INCLUDE_NET_COAP_CLIENT_H_ */
203