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