Line data Source code
1 1 : /*
2 : * Copyright (c) 2023 Basalte bv
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /** @file
8 : * @brief CoAP Service API
9 : *
10 : * An API for applications to respond to CoAP requests
11 : */
12 :
13 : #ifndef ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_
14 : #define ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_
15 :
16 : #include <zephyr/net/coap.h>
17 : #include <zephyr/sys/iterable_sections.h>
18 : #include <zephyr/net/tls_credentials.h>
19 :
20 : #ifdef __cplusplus
21 : extern "C" {
22 : #endif
23 :
24 : /**
25 : * @brief CoAP Service API
26 : * @defgroup coap_service CoAP service API
27 : * @since 3.6
28 : * @version 0.1.0
29 : * @ingroup networking
30 : * @{
31 : */
32 :
33 : /**
34 : * @name CoAP Service configuration flags
35 : * @anchor COAP_SERVICE_FLAGS
36 : * @{
37 : */
38 :
39 : /** Start the service on boot. */
40 1 : #define COAP_SERVICE_AUTOSTART BIT(0)
41 :
42 : /** @} */
43 :
44 : /** @cond INTERNAL_HIDDEN */
45 :
46 : struct coap_service_data {
47 : int sock_fd;
48 : struct coap_observer observers[CONFIG_COAP_SERVICE_OBSERVERS];
49 : struct coap_pending pending[CONFIG_COAP_SERVICE_PENDING_MESSAGES];
50 : };
51 :
52 : struct coap_service {
53 : const char *name;
54 : const char *host;
55 : uint16_t *port;
56 : uint8_t flags;
57 : struct coap_resource *res_begin;
58 : struct coap_resource *res_end;
59 : struct coap_service_data *data;
60 : #if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS)
61 : const sec_tag_t *sec_tag_list;
62 : size_t sec_tag_list_size;
63 : #endif
64 : };
65 :
66 : #if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS)
67 : #define __z_coap_service_secure(_sec_tag_list, _sec_tag_list_size) \
68 : .sec_tag_list = _sec_tag_list, \
69 : .sec_tag_list_size = _sec_tag_list_size,
70 : #else
71 : #define __z_coap_service_secure(...)
72 : #endif
73 :
74 : #define __z_coap_service_define(_name, _host, _port, _flags, _res_begin, _res_end, \
75 : _sec_tag_list, _sec_tag_list_size) \
76 : static struct coap_service_data _CONCAT(coap_service_data_, _name) = { \
77 : .sock_fd = -1, \
78 : }; \
79 : const STRUCT_SECTION_ITERABLE(coap_service, _name) = { \
80 : .name = STRINGIFY(_name), \
81 : .host = _host, \
82 : .port = (uint16_t *)(_port), \
83 : .flags = _flags, \
84 : .res_begin = (_res_begin), \
85 : .res_end = (_res_end), \
86 : .data = &_CONCAT(coap_service_data_, _name), \
87 : __z_coap_service_secure(_sec_tag_list, _sec_tag_list_size) \
88 : }
89 :
90 : /** @endcond */
91 :
92 : /**
93 : * @brief Define a static CoAP resource owned by the service named @p _service .
94 : *
95 : * @note The handlers registered with the resource can return a CoAP response code to reply with
96 : * an acknowledge without any payload, nothing is sent if the return value is 0 or negative.
97 : * As seen in the example.
98 : *
99 : * @code{.c}
100 : * static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
101 : *
102 : * static int led_put(struct coap_resource *resource, struct coap_packet *request,
103 : * struct sockaddr *addr, socklen_t addr_len)
104 : * {
105 : * const uint8_t *payload;
106 : * uint16_t payload_len;
107 : *
108 : * payload = coap_packet_get_payload(request, &payload_len);
109 : * if (payload_len != 1) {
110 : * return COAP_RESPONSE_CODE_BAD_REQUEST;
111 : * }
112 : *
113 : * if (gpio_pin_set_dt(&led, payload[0]) < 0) {
114 : * return COAP_RESPONSE_CODE_INTERNAL_ERROR;
115 : * }
116 : *
117 : * return COAP_RESPONSE_CODE_CHANGED;
118 : * }
119 : *
120 : * COAP_RESOURCE_DEFINE(my_resource, my_service, {
121 : * .put = led_put,
122 : * });
123 : * @endcode
124 : *
125 : * @param _name Name of the resource.
126 : * @param _service Name of the associated service.
127 : */
128 1 : #define COAP_RESOURCE_DEFINE(_name, _service, ...) \
129 : STRUCT_SECTION_ITERABLE_ALTERNATE(_CONCAT(coap_resource_, _service), coap_resource, \
130 : _name) = __VA_ARGS__
131 :
132 : /**
133 : * @brief Define a CoAP service with static resources.
134 : *
135 : * @note The @p _host parameter can be `NULL`. If not, it is used to specify an IP address either in
136 : * IPv4 or IPv6 format a fully-qualified hostname or a virtual host, otherwise the any address is
137 : * used.
138 : *
139 : * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
140 : * number to use for the service. If the specified port number is zero, then an ephemeral port
141 : * number will be used and the actual port number assigned will be written back to memory. For
142 : * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
143 : *
144 : * @param _name Name of the service.
145 : * @param _host IP address or hostname associated with the service.
146 : * @param[inout] _port Pointer to port associated with the service.
147 : * @param _flags Configuration flags @see @ref COAP_SERVICE_FLAGS.
148 : */
149 1 : #define COAP_SERVICE_DEFINE(_name, _host, _port, _flags) \
150 : extern struct coap_resource _CONCAT(_CONCAT(_coap_resource_, _name), _list_start)[]; \
151 : extern struct coap_resource _CONCAT(_CONCAT(_coap_resource_, _name), _list_end)[]; \
152 : __z_coap_service_define(_name, _host, _port, _flags, \
153 : &_CONCAT(_CONCAT(_coap_resource_, _name), _list_start)[0], \
154 : &_CONCAT(_CONCAT(_coap_resource_, _name), _list_end)[0], \
155 : NULL, 0)
156 :
157 : /**
158 : * @brief Define a CoAP secure service with static resources.
159 : *
160 : * @note The @p _host parameter can be `NULL`. If not, it is used to specify an IP address either in
161 : * IPv4 or IPv6 format a fully-qualified hostname or a virtual host, otherwise the any address is
162 : * used.
163 : *
164 : * @note The @p _port parameter must be non-`NULL`. It points to a location that specifies the port
165 : * number to use for the service. If the specified port number is zero, then an ephemeral port
166 : * number will be used and the actual port number assigned will be written back to memory. For
167 : * ephemeral port numbers, the memory pointed to by @p _port must be writeable.
168 : *
169 : * @note @kconfig{CONFIG_NET_SOCKETS_ENABLE_DTLS} has to be enabled for CoAP secure support.
170 : *
171 : * @param _name Name of the service.
172 : * @param _host IP address or hostname associated with the service.
173 : * @param[inout] _port Pointer to port associated with the service.
174 : * @param _flags Configuration flags @see @ref COAP_SERVICE_FLAGS.
175 : * @param _sec_tag_list DTLS security tag list used to setup a COAPS socket.
176 : * @param _sec_tag_list_size DTLS security tag list size used to setup a COAPS socket.
177 : */
178 1 : #define COAPS_SERVICE_DEFINE(_name, _host, _port, _flags, _sec_tag_list, _sec_tag_list_size) \
179 : BUILD_ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_ENABLE_DTLS), \
180 : "DTLS is required for CoAP secure (CONFIG_NET_SOCKETS_ENABLE_DTLS)"); \
181 : extern struct coap_resource _CONCAT(_CONCAT(_coap_resource_, _name), _list_start)[]; \
182 : extern struct coap_resource _CONCAT(_CONCAT(_coap_resource_, _name), _list_end)[]; \
183 : __z_coap_service_define(_name, _host, _port, _flags, \
184 : &_CONCAT(_CONCAT(_coap_resource_, _name), _list_start)[0], \
185 : &_CONCAT(_CONCAT(_coap_resource_, _name), _list_end)[0], \
186 : _sec_tag_list, _sec_tag_list_size)
187 :
188 : /**
189 : * @brief Count the number of CoAP services.
190 : *
191 : * @param[out] _dst Pointer to location where result is written.
192 : */
193 1 : #define COAP_SERVICE_COUNT(_dst) STRUCT_SECTION_COUNT(coap_service, _dst)
194 :
195 : /**
196 : * @brief Count CoAP service static resources.
197 : *
198 : * @param _service Pointer to a service.
199 : */
200 1 : #define COAP_SERVICE_RESOURCE_COUNT(_service) ((_service)->res_end - (_service)->res_begin)
201 :
202 : /**
203 : * @brief Check if service has the specified resource.
204 : *
205 : * @param _service Pointer to a service.
206 : * @param _resource Pointer to a resource.
207 : */
208 1 : #define COAP_SERVICE_HAS_RESOURCE(_service, _resource) \
209 : ((_service)->res_begin <= _resource && _resource < (_service)->res_end)
210 :
211 : /**
212 : * @brief Iterate over all CoAP services.
213 : *
214 : * @param _it Name of iterator (of type @ref coap_service)
215 : */
216 1 : #define COAP_SERVICE_FOREACH(_it) STRUCT_SECTION_FOREACH(coap_service, _it)
217 :
218 : /**
219 : * @brief Iterate over static CoAP resources associated with a given @p _service.
220 : *
221 : * @note This macro requires that @p _service is defined with @ref COAP_SERVICE_DEFINE.
222 : *
223 : * @param _service Name of CoAP service
224 : * @param _it Name of iterator (of type @ref coap_resource)
225 : */
226 1 : #define COAP_RESOURCE_FOREACH(_service, _it) \
227 : STRUCT_SECTION_FOREACH_ALTERNATE(_CONCAT(coap_resource_, _service), coap_resource, _it)
228 :
229 : /**
230 : * @brief Iterate over all static resources associated with @p _service .
231 : *
232 : * @note This macro is suitable for a @p _service defined with @ref COAP_SERVICE_DEFINE.
233 : *
234 : * @param _service Pointer to COAP service
235 : * @param _it Name of iterator (of type @ref coap_resource)
236 : */
237 1 : #define COAP_SERVICE_FOREACH_RESOURCE(_service, _it) \
238 : for (struct coap_resource *_it = (_service)->res_begin; ({ \
239 : __ASSERT(_it <= (_service)->res_end, "unexpected list end location"); \
240 : _it < (_service)->res_end; \
241 : }); _it++)
242 :
243 : /**
244 : * @brief Start the provided @p service .
245 : *
246 : * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE.
247 : *
248 : * @param service Pointer to CoAP service
249 : * @retval 0 in case of success.
250 : * @retval -EALREADY in case of an already running service.
251 : * @retval -ENOTSUP in case the server has no valid host and port configuration.
252 : */
253 1 : int coap_service_start(const struct coap_service *service);
254 :
255 : /**
256 : * @brief Stop the provided @p service .
257 : *
258 : * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE.
259 : *
260 : * @param service Pointer to CoAP service
261 : * @retval 0 in case of success.
262 : * @retval -EALREADY in case the service isn't running.
263 : */
264 1 : int coap_service_stop(const struct coap_service *service);
265 :
266 : /**
267 : * @brief Query the provided @p service running state.
268 : *
269 : * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE.
270 : *
271 : * @param service Pointer to CoAP service
272 : * @retval 1 if the service is running
273 : * @retval 0 if the service is stopped
274 : * @retval negative in case of an error.
275 : */
276 1 : int coap_service_is_running(const struct coap_service *service);
277 :
278 : /**
279 : * @brief Send a CoAP message from the provided @p service .
280 : *
281 : * @note This function is suitable for a @p service defined with @ref COAP_SERVICE_DEFINE.
282 : *
283 : * @param service Pointer to CoAP service
284 : * @param cpkt CoAP Packet to send
285 : * @param addr Peer address
286 : * @param addr_len Peer address length
287 : * @param params Pointer to transmission parameters structure or NULL to use default values.
288 : * @return 0 in case of success or negative in case of error.
289 : */
290 1 : int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt,
291 : const struct sockaddr *addr, socklen_t addr_len,
292 : const struct coap_transmission_parameters *params);
293 :
294 : /**
295 : * @brief Send a CoAP message from the provided @p resource .
296 : *
297 : * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE.
298 : *
299 : * @param resource Pointer to CoAP resource
300 : * @param cpkt CoAP Packet to send
301 : * @param addr Peer address
302 : * @param addr_len Peer address length
303 : * @param params Pointer to transmission parameters structure or NULL to use default values.
304 : * @return 0 in case of success or negative in case of error.
305 : */
306 1 : int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt,
307 : const struct sockaddr *addr, socklen_t addr_len,
308 : const struct coap_transmission_parameters *params);
309 :
310 : /**
311 : * @brief Parse a CoAP observe request for the provided @p resource .
312 : *
313 : * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE.
314 : *
315 : * If the observe option value is equal to 0, an observer will be added, if the value is equal
316 : * to 1, an existing observer will be removed.
317 : *
318 : * @param resource Pointer to CoAP resource
319 : * @param request CoAP request to parse
320 : * @param addr Peer address
321 : * @return the observe option value in case of success or negative in case of error.
322 : */
323 1 : int coap_resource_parse_observe(struct coap_resource *resource, const struct coap_packet *request,
324 : const struct sockaddr *addr);
325 :
326 : /**
327 : * @brief Lookup an observer by address and remove it from the @p resource .
328 : *
329 : * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE.
330 : *
331 : * @param resource Pointer to CoAP resource
332 : * @param addr Peer address
333 : * @return 0 in case of success or negative in case of error.
334 : */
335 1 : int coap_resource_remove_observer_by_addr(struct coap_resource *resource,
336 : const struct sockaddr *addr);
337 :
338 : /**
339 : * @brief Lookup an observer by token and remove it from the @p resource .
340 : *
341 : * @note This function is suitable for a @p resource defined with @ref COAP_RESOURCE_DEFINE.
342 : *
343 : * @param resource Pointer to CoAP resource
344 : * @param token Pointer to the token
345 : * @param token_len Length of valid bytes in the token
346 : * @return 0 in case of success or negative in case of error.
347 : */
348 1 : int coap_resource_remove_observer_by_token(struct coap_resource *resource,
349 : const uint8_t *token, uint8_t token_len);
350 :
351 : /**
352 : * @}
353 : */
354 :
355 : #ifdef __cplusplus
356 : }
357 : #endif
358 :
359 : #endif /* ZEPHYR_INCLUDE_NET_COAP_SERVICE_H_ */
|