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