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