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 #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 #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 #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 #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 #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 #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 #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 #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 #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 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 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 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 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 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 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 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 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_ */ 313