Line data Source code
1 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 : #ifdef __cplusplus
28 : extern "C" {
29 : #endif
30 :
31 : /** Maximum size of a CoAP message */
32 1 : #define MAX_COAP_MSG_LEN (CONFIG_COAP_CLIENT_MESSAGE_HEADER_SIZE + \
33 : CONFIG_COAP_CLIENT_MESSAGE_SIZE)
34 :
35 : /**
36 : * @brief Representation for CoAP client response data.
37 : */
38 1 : struct coap_client_response_data {
39 : /**
40 : * Result code of the response. Negative if there was a failure in send.
41 : * @ref coap_response_code for positive.
42 : */
43 1 : int16_t result_code;
44 : /** A pointer to the response CoAP packet. NULL for error result. */
45 1 : const struct coap_packet *packet;
46 : /** Payload offset from the beginning of a blockwise transfer. */
47 1 : size_t offset;
48 : /** Buffer containing the payload from the response. NULL for empty payload. */
49 1 : const uint8_t *payload;
50 : /** Size of the payload. */
51 1 : size_t payload_len;
52 : /** Indicates the last block of the response. */
53 1 : bool last_block;
54 : };
55 :
56 : /**
57 : * @typedef coap_client_response_cb_t
58 : * @brief Callback for CoAP request.
59 : *
60 : * This callback is called for responses to CoAP client requests.
61 : * It is used to indicate errors, response codes from server or to deliver payload.
62 : * Blockwise transfers cause this callback to be called sequentially with increasing payload offset
63 : * and only partial content in buffer pointed by payload parameter.
64 : *
65 : * @param data The CoAP response data.
66 : * @param user_data User provided context.
67 : */
68 1 : typedef void (*coap_client_response_cb_t)(const struct coap_client_response_data *data,
69 : void *user_data);
70 :
71 : /**
72 : * @typedef coap_client_payload_cb_t
73 : * @brief Callback for providing a payload for the CoAP request.
74 : *
75 : * An optional callback for providing a payload for CoAP client requests. If set in
76 : * @ref coap_client_request, the CoAP client library will call this callback when
77 : * preparing a PUT/POST request.
78 : *
79 : * When called, the library provides the application with the current payload offset
80 : * for the transfer and the payload block size. In return, the application sets the
81 : * payload pointer, payload size and information whether more data blocks are expected.
82 : * Setting the @p last_block parameter to false on the initial callback call triggers
83 : * a block transfer upload. The library will keep calling the callback until the
84 : * @p last_block parameter is set to false.
85 : *
86 : * @note If block transfer is used, the application is expected to provide full blocks of
87 : * payload. Only the final block (i.e. when @p last_block is set to true) can be shorter
88 : * than the requested block size.
89 : *
90 : * @param offset Payload offset from the beginning of a blockwise transfer.
91 : * @param payload A pointer for the buffer containing the payload block.
92 : * @param len Requested (maximum) block size on input. The actual payload length on output.
93 : * @param last_block A pointer to the flag indicating whether more payload blocks are expected.
94 : * @param user_data User provided context.
95 : *
96 : * @return Zero on success, a negative error code to abort upload.
97 : */
98 1 : typedef int (*coap_client_payload_cb_t)(size_t offset, const uint8_t **payload,
99 : size_t *len, bool *last_block,
100 : void *user_data);
101 :
102 : /**
103 : * @brief Representation of extra options for the CoAP client request
104 : */
105 1 : struct coap_client_option {
106 : /** Option code */
107 1 : uint16_t code;
108 : #if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN)
109 : /** Option len */
110 : uint16_t len;
111 : /** Buffer for the length */
112 : uint8_t value[CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE];
113 : #else
114 : /** Option len */
115 1 : uint8_t len;
116 : /** Buffer for the length */
117 1 : uint8_t value[12];
118 : #endif
119 : };
120 :
121 : /** @cond INTERNAL_HIDDEN */
122 : #define MAX_PATH_SIZE (CONFIG_COAP_CLIENT_MAX_PATH_LENGTH + 1)
123 : #define MAX_EXTRA_OPTIONS CONFIG_COAP_CLIENT_MAX_EXTRA_OPTIONS
124 : /** @endcond */
125 :
126 : /**
127 : * @brief Representation of a CoAP client request.
128 : */
129 1 : struct coap_client_request {
130 1 : enum coap_method method; /**< Method of the request */
131 1 : bool confirmable; /**< CoAP Confirmable/Non-confirmable message */
132 1 : char path[MAX_PATH_SIZE]; /**< Path of the requested resource */
133 1 : enum coap_content_format fmt; /**< Content format to be used */
134 1 : const uint8_t *payload; /**< User allocated buffer for send request */
135 1 : size_t len; /**< Length of the payload */
136 1 : coap_client_payload_cb_t payload_cb; /**< Optional payload callback */
137 1 : coap_client_response_cb_t cb; /**< Callback when response received */
138 : struct coap_client_option
139 1 : options[MAX_EXTRA_OPTIONS]; /**< Extra options to be added to request */
140 1 : uint8_t num_options; /**< Number of extra options */
141 1 : void *user_data; /**< User provided context */
142 : };
143 :
144 : /** @cond INTERNAL_HIDDEN */
145 : struct coap_client_internal_request {
146 : uint8_t request_token[COAP_TOKEN_MAX_LEN];
147 : uint32_t offset;
148 : uint16_t last_id;
149 : uint8_t request_tkl;
150 : bool request_ongoing;
151 : atomic_t in_callback;
152 : struct coap_block_context recv_blk_ctx;
153 : struct coap_block_context send_blk_ctx;
154 : struct coap_pending pending;
155 : struct coap_client_request coap_request;
156 : struct coap_packet request;
157 : uint8_t request_tag[COAP_TOKEN_MAX_LEN];
158 : uint8_t send_buf[MAX_COAP_MSG_LEN];
159 :
160 : /* For GETs with observe option set */
161 : bool is_observe;
162 : int last_response_id;
163 : };
164 :
165 : struct coap_client {
166 : int fd;
167 : struct sockaddr address;
168 : socklen_t socklen;
169 : struct k_mutex lock;
170 : uint8_t recv_buf[MAX_COAP_MSG_LEN];
171 : struct coap_client_internal_request requests[CONFIG_COAP_CLIENT_MAX_REQUESTS];
172 : struct coap_option echo_option;
173 : bool send_echo;
174 : };
175 : /** @endcond */
176 :
177 : /**
178 : * @brief Initialize the CoAP client.
179 : *
180 : * @param[in] client Client instance.
181 : * @param[in] info Name for the receiving thread of the client. Setting this NULL will result as
182 : * default name of "coap_client".
183 : *
184 : * @return int Zero on success, otherwise a negative error code.
185 : */
186 1 : int coap_client_init(struct coap_client *client, const char *info);
187 :
188 : /**
189 : * @brief Send CoAP request
190 : *
191 : * Operation is handled asynchronously using a background thread.
192 : * If the socket isn't connected to a destination address, user must provide a destination address,
193 : * otherwise the address should be set as NULL.
194 : * Once the callback is called with last block set as true, socket can be closed or
195 : * used for another query.
196 : *
197 : * @note If block transfer is used, the @p payload pointer provided in @p req parameter has to
198 : * remain valid throughout the transaction (i.e. until the last block or an error is reported).
199 : * The library will need to access the payload pointer when sending consecutive payload blocks.
200 : *
201 : * @param client Client instance.
202 : * @param sock Open socket file descriptor.
203 : * @param addr the destination address of the request, NULL if socket is already connected.
204 : * @param req CoAP request structure
205 : * @param params Pointer to transmission parameters structure or NULL to use default values.
206 : * @return zero when operation started successfully or negative error code otherwise.
207 : */
208 :
209 1 : int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr,
210 : struct coap_client_request *req, struct coap_transmission_parameters *params);
211 :
212 : /**
213 : * @brief Cancel all current requests.
214 : *
215 : * This is intended for canceling long-running requests (e.g. GETs with the OBSERVE option set)
216 : * which has gone stale for some reason.
217 : * The function should also be called before the corresponding client socket is closed,
218 : * to prevent the socket from being monitored by the internal polling thread.
219 : *
220 : * @param client Client instance.
221 : */
222 1 : void coap_client_cancel_requests(struct coap_client *client);
223 :
224 : /**
225 : * @brief Cancel matching requests.
226 : *
227 : * This function cancels all CoAP client request that matches the given request.
228 : * The request is matched based on the method, path, callback and user_data, if provided.
229 : * Any field set to NULL is considered a wildcard.
230 : *
231 : * (struct coap_client_request){0} cancels all requests.
232 : * (struct coap_client_request){.method = COAP_METHOD_GET} cancels all GET requests.
233 : *
234 : * @param client Pointer to the CoAP client instance.
235 : * @param req Pointer to the CoAP client request to be canceled.
236 : */
237 1 : void coap_client_cancel_request(struct coap_client *client, struct coap_client_request *req);
238 :
239 : /**
240 : * @brief Initialise a Block2 option to be added to a request
241 : *
242 : * If the application expects a request to require a blockwise transfer, it may pre-emptively
243 : * suggest a maximum block size to the server - see RFC7959 Figure 3: Block-Wise GET with Early
244 : * Negotiation.
245 : *
246 : * This helper function returns a Block2 option to send with the initial request.
247 : *
248 : * @return CoAP client initial Block2 option structure
249 : */
250 1 : struct coap_client_option coap_client_option_initial_block2(void);
251 :
252 : /**
253 : * @brief Check if client has ongoing exchange.
254 : *
255 : * @note Function not only considers ongoing requests, but also lifetime of completed requests
256 : * (which provides graceful duplicates handling).
257 : *
258 : * @note For socket handling.
259 : * Function does no consider a socket POLL that has started before this call,
260 : * therefore it is recommended to wait out POLL timeout before closing socket
261 : * (e.g. call coap_client_cancel_requests() which applies delay for timeout).
262 : *
263 : * @param client Pointer to the CoAP client instance.
264 : *
265 : * @return true if there is an ongoing exchange, false otherwise.
266 : */
267 1 : bool coap_client_has_ongoing_exchange(struct coap_client *client);
268 :
269 : #ifdef __cplusplus
270 : }
271 : #endif
272 :
273 : /**
274 : * @}
275 : */
276 :
277 : #endif /* ZEPHYR_INCLUDE_NET_COAP_CLIENT_H_ */
|