1 /* 2 * Copyright (c) 2016, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef COAP_HPP_ 30 #define COAP_HPP_ 31 32 #include "openthread-core-config.h" 33 34 #include <openthread/coap.h> 35 36 #include "coap/coap_message.hpp" 37 #include "common/as_core_type.hpp" 38 #include "common/callback.hpp" 39 #include "common/debug.hpp" 40 #include "common/linked_list.hpp" 41 #include "common/locator.hpp" 42 #include "common/message.hpp" 43 #include "common/non_copyable.hpp" 44 #include "common/timer.hpp" 45 #include "net/ip6.hpp" 46 #include "net/netif.hpp" 47 #include "net/udp6.hpp" 48 #include "thread/uri_paths.hpp" 49 50 /** 51 * @file 52 * This file includes definitions for CoAP client and server functionality. 53 */ 54 55 namespace ot { 56 57 namespace Coap { 58 59 /** 60 * @addtogroup core-coap 61 * 62 * @{ 63 */ 64 65 /** 66 * Represents a function pointer which is called when a CoAP response is received or on the request timeout. 67 * 68 * Please see otCoapResponseHandler for details. 69 */ 70 typedef otCoapResponseHandler ResponseHandler; 71 72 /** 73 * Represents a function pointer which is called when a CoAP request associated with a given URI path is 74 * received. 75 * 76 * Please see otCoapRequestHandler for details. 77 */ 78 typedef otCoapRequestHandler RequestHandler; 79 80 /** 81 * Represents the CoAP transmission parameters. 82 */ 83 class TxParameters : public otCoapTxParameters 84 { 85 friend class CoapBase; 86 friend class ResponsesQueue; 87 88 public: 89 /** 90 * Converts a pointer to `otCoapTxParameters` to `Coap::TxParamters` 91 * 92 * If the pointer is `nullptr`, the default parameters are used instead. 93 * 94 * @param[in] aTxParameters A pointer to tx parameter. 95 * 96 * @returns A reference to corresponding `TxParamters` if @p aTxParameters is not `nullptr`, otherwise the default 97 * tx parameters. 98 */ From(const otCoapTxParameters * aTxParameters)99 static const TxParameters &From(const otCoapTxParameters *aTxParameters) 100 { 101 return aTxParameters ? *static_cast<const TxParameters *>(aTxParameters) : GetDefault(); 102 } 103 104 /** 105 * Validates whether the CoAP transmission parameters are valid. 106 * 107 * @returns Whether the parameters are valid. 108 */ 109 bool IsValid(void) const; 110 111 /** 112 * Returns default CoAP tx parameters. 113 * 114 * @returns The default tx parameters. 115 */ GetDefault(void)116 static const TxParameters &GetDefault(void) { return static_cast<const TxParameters &>(kDefaultTxParameters); } 117 118 private: 119 static constexpr uint32_t kDefaultAckTimeout = 2000; // in msec 120 static constexpr uint8_t kDefaultAckRandomFactorNumerator = 3; 121 static constexpr uint8_t kDefaultAckRandomFactorDenominator = 2; 122 static constexpr uint8_t kDefaultMaxRetransmit = 4; 123 static constexpr uint32_t kDefaultMaxLatency = 100000; // in msec 124 125 uint32_t CalculateInitialRetransmissionTimeout(void) const; 126 uint32_t CalculateExchangeLifetime(void) const; 127 uint32_t CalculateMaxTransmitWait(void) const; 128 uint32_t CalculateSpan(uint8_t aMaxRetx) const; 129 130 static const otCoapTxParameters kDefaultTxParameters; 131 }; 132 133 /** 134 * Implements CoAP resource handling. 135 */ 136 class Resource : public otCoapResource, public LinkedListEntry<Resource> 137 { 138 friend class CoapBase; 139 140 public: 141 /** 142 * Initializes the resource. 143 * 144 * @param[in] aUriPath A pointer to a null-terminated string for the URI path. 145 * @param[in] aHandler A function pointer that is called when receiving a CoAP message for @p aUriPath. 146 * @param[in] aContext A pointer to arbitrary context information. 147 */ 148 Resource(const char *aUriPath, RequestHandler aHandler, void *aContext); 149 150 /** 151 * Initializes the resource. 152 * 153 * @param[in] aUri A Thread URI. 154 * @param[in] aHandler A function pointer that is called when receiving a CoAP message for the URI. 155 * @param[in] aContext A pointer to arbitrary context information. 156 */ 157 Resource(Uri aUri, RequestHandler aHandler, void *aContext); 158 159 /** 160 * Returns a pointer to the URI path. 161 * 162 * @returns A pointer to the URI path. 163 */ GetUriPath(void) const164 const char *GetUriPath(void) const { return mUriPath; } 165 166 protected: HandleRequest(Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const167 void HandleRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const 168 { 169 mHandler(mContext, &aMessage, &aMessageInfo); 170 } 171 }; 172 173 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 174 /** 175 * Implements CoAP block-wise resource handling. 176 */ 177 class ResourceBlockWise : public otCoapBlockwiseResource 178 { 179 friend class CoapBase; 180 181 public: 182 /** 183 * Initializes the resource. 184 * 185 * @param[in] aUriPath A pointer to a NULL-terminated string for the Uri-Path. 186 * @param[in] aHandler A function pointer that is called when receiving a CoAP message for @p aUriPath. 187 * @param[in] aContext A pointer to arbitrary context information. 188 * @param[in] aReceiveHook A function pointer that is called when receiving a CoAP block message for @p 189 * aUriPath. 190 * @param[in] aTransmitHook A function pointer that is called when transmitting a CoAP block message from @p 191 * aUriPath. 192 */ ResourceBlockWise(const char * aUriPath,otCoapRequestHandler aHandler,void * aContext,otCoapBlockwiseReceiveHook aReceiveHook,otCoapBlockwiseTransmitHook aTransmitHook)193 ResourceBlockWise(const char *aUriPath, 194 otCoapRequestHandler aHandler, 195 void *aContext, 196 otCoapBlockwiseReceiveHook aReceiveHook, 197 otCoapBlockwiseTransmitHook aTransmitHook) 198 { 199 mUriPath = aUriPath; 200 mHandler = aHandler; 201 mContext = aContext; 202 mReceiveHook = aReceiveHook; 203 mTransmitHook = aTransmitHook; 204 mNext = nullptr; 205 } 206 HandleBlockReceive(const uint8_t * aBlock,uint32_t aPosition,uint16_t aBlockLength,bool aMore,uint32_t aTotalLength) const207 Error HandleBlockReceive(const uint8_t *aBlock, 208 uint32_t aPosition, 209 uint16_t aBlockLength, 210 bool aMore, 211 uint32_t aTotalLength) const 212 { 213 return mReceiveHook(otCoapBlockwiseResource::mContext, aBlock, aPosition, aBlockLength, aMore, aTotalLength); 214 } 215 HandleBlockTransmit(uint8_t * aBlock,uint32_t aPosition,uint16_t * aBlockLength,bool * aMore) const216 Error HandleBlockTransmit(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore) const 217 { 218 return mTransmitHook(otCoapBlockwiseResource::mContext, aBlock, aPosition, aBlockLength, aMore); 219 } 220 221 /** 222 * Gets the next entry in the linked list. 223 * 224 * @returns A pointer to the next entry in the linked list or `nullptr` if at the end of the list. 225 */ GetNext(void) const226 const ResourceBlockWise *GetNext(void) const 227 { 228 return static_cast<const ResourceBlockWise *>(static_cast<const ResourceBlockWise *>(this)->mNext); 229 } 230 231 /** 232 * Gets the next entry in the linked list. 233 * 234 * @returns A pointer to the next entry in the linked list or `nullptr` if at the end of the list. 235 */ GetNext(void)236 ResourceBlockWise *GetNext(void) 237 { 238 return static_cast<ResourceBlockWise *>(static_cast<ResourceBlockWise *>(this)->mNext); 239 } 240 241 /** 242 * Sets the next pointer on the entry. 243 * 244 * @param[in] aNext A pointer to the next entry. 245 */ SetNext(ResourceBlockWise * aNext)246 void SetNext(ResourceBlockWise *aNext) { static_cast<ResourceBlockWise *>(this)->mNext = aNext; } 247 248 /** 249 * Returns a pointer to the URI path. 250 * 251 * @returns A pointer to the URI path. 252 */ GetUriPath(void) const253 const char *GetUriPath(void) const { return mUriPath; } 254 255 protected: HandleRequest(Message & aMessage,const Ip6::MessageInfo & aMessageInfo) const256 void HandleRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const 257 { 258 mHandler(mContext, &aMessage, &aMessageInfo); 259 } 260 }; 261 #endif 262 263 /** 264 * Caches CoAP responses to implement message deduplication. 265 */ 266 class ResponsesQueue 267 { 268 public: 269 /** 270 * Default class constructor. 271 * 272 * @param[in] aInstance A reference to the OpenThread instance. 273 */ 274 explicit ResponsesQueue(Instance &aInstance); 275 276 /** 277 * Adds a given response to the cache. 278 * 279 * If matching response (the same Message ID, source endpoint address and port) exists in the cache given 280 * response is not added. 281 * 282 * The CoAP response is copied before it is added to the cache. 283 * 284 * @param[in] aMessage The CoAP response to add to the cache. 285 * @param[in] aMessageInfo The message info corresponding to @p aMessage. 286 * @param[in] aTxParameters Transmission parameters. 287 */ 288 void EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const TxParameters &aTxParameters); 289 290 /** 291 * Removes all responses from the cache. 292 */ 293 void DequeueAllResponses(void); 294 295 /** 296 * Gets a copy of CoAP response from the cache that matches a given Message ID and source endpoint. 297 * 298 * @param[in] aRequest The CoAP message containing Message ID. 299 * @param[in] aMessageInfo The message info containing source endpoint address and port. 300 * @param[out] aResponse A pointer to return a copy of a cached CoAP response matching given arguments. 301 * 302 * @retval kErrorNone Matching response found and successfully created a copy. 303 * @retval kErrorNoBufs Matching response found but there is not sufficient buffer to create a copy. 304 * @retval kErrorNotFound Matching response not found. 305 */ 306 Error GetMatchedResponseCopy(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo, Message **aResponse); 307 308 /** 309 * Gets a reference to the cached CoAP responses queue. 310 * 311 * @returns A reference to the cached CoAP responses queue. 312 */ GetResponses(void) const313 const MessageQueue &GetResponses(void) const { return mQueue; } 314 315 private: 316 static constexpr uint16_t kMaxCachedResponses = OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES; 317 318 struct ResponseMetadata : public Message::FooterData<ResponseMetadata> 319 { 320 TimeMilli mDequeueTime; 321 Ip6::MessageInfo mMessageInfo; 322 }; 323 324 const Message *FindMatchedResponse(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo) const; 325 void DequeueResponse(Message &aMessage); 326 void UpdateQueue(void); 327 328 static void HandleTimer(Timer &aTimer); 329 void HandleTimer(void); 330 331 MessageQueue mQueue; 332 TimerMilliContext mTimer; 333 }; 334 335 /** 336 * Implements the CoAP client and server. 337 */ 338 class CoapBase : public InstanceLocator, private NonCopyable 339 { 340 friend class ResponsesQueue; 341 342 public: 343 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 344 static constexpr uint16_t kMaxBlockLength = OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH; 345 #endif 346 347 /** 348 * Pointer is called before CoAP server processing a CoAP message. 349 * 350 * @param[in] aMessage A reference to the message. 351 @ @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 352 * @param[in] aContext A pointer to arbitrary context information. 353 * 354 * @retval kErrorNone Server should continue processing this message, other return values indicates the 355 * server should stop processing this message. 356 * @retval kErrorNotTmf The message is not a TMF message. 357 */ 358 typedef Error (*Interceptor)(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext); 359 360 /** 361 * Clears all requests and responses used by this CoAP agent and stops all timers. 362 */ 363 void ClearAllRequestsAndResponses(void); 364 365 /** 366 * Clears requests with specified source address used by this CoAP agent. 367 * 368 * @param[in] aAddress A reference to the specified address. 369 */ 370 void ClearRequests(const Ip6::Address &aAddress); 371 372 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 373 374 /** 375 * Adds a block-wise resource to the CoAP server. 376 * 377 * @param[in] aResource A reference to the resource. 378 */ 379 void AddBlockWiseResource(ResourceBlockWise &aResource); 380 381 /** 382 * Removes a block-wise resource from the CoAP server. 383 * 384 * @param[in] aResource A reference to the resource. 385 */ 386 void RemoveBlockWiseResource(ResourceBlockWise &aResource); 387 #endif 388 389 /** 390 * Adds a resource to the CoAP server. 391 * 392 * @param[in] aResource A reference to the resource. 393 */ 394 void AddResource(Resource &aResource); 395 396 /** 397 * Removes a resource from the CoAP server. 398 * 399 * @param[in] aResource A reference to the resource. 400 */ 401 void RemoveResource(Resource &aResource); 402 403 /* Sets the default handler for unhandled CoAP requests. 404 * 405 * @param[in] aHandler A function pointer that shall be called when an unhandled request arrives. 406 * @param[in] aContext A pointer to arbitrary context information. May be `nullptr` if not used. 407 */ SetDefaultHandler(RequestHandler aHandler,void * aContext)408 void SetDefaultHandler(RequestHandler aHandler, void *aContext) { mDefaultHandler.Set(aHandler, aContext); } 409 410 /** 411 * Allocates a new message with a CoAP header. 412 * 413 * @param[in] aSettings The message settings. 414 * 415 * @returns A pointer to the message or `nullptr` if failed to allocate message. 416 */ 417 Message *NewMessage(const Message::Settings &aSettings); 418 419 /** 420 * Allocates a new message with a CoAP header with default settings. 421 * 422 * @returns A pointer to the message or `nullptr` if failed to allocate message. 423 */ 424 Message *NewMessage(void); 425 426 /** 427 * Allocates a new message with a CoAP header that has Network Control priority level. 428 * 429 * @returns A pointer to the message or `nullptr` if failed to allocate message. 430 */ 431 Message *NewPriorityMessage(void); 432 433 /** 434 * Allocates and initializes a new CoAP Confirmable Post message with Network Control priority level. 435 * 436 * The CoAP header is initialized as `kTypeConfirmable` and `kCodePost` with a given URI path and a randomly 437 * generated token (of default length). This method also sets the payload marker (`SetPayloadMarker()` on message. 438 * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and 439 * remove the payload marker when there is no payload. 440 * 441 * @param[in] aUri The URI. 442 * 443 * @returns A pointer to the message or `nullptr` if failed to allocate message. 444 */ 445 Message *NewPriorityConfirmablePostMessage(Uri aUri); 446 447 /** 448 * Allocates and initializes a new CoAP Confirmable Post message with normal priority level. 449 * 450 * The CoAP header is initialized as `kTypeConfirmable` and `kCodePost` with a given URI and a randomly 451 * generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`). 452 * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and 453 * remove the payload marker when there is no payload. 454 * 455 * @param[in] aUri The URI. 456 * 457 * @returns A pointer to the message or `nullptr` if failed to allocate message. 458 */ 459 Message *NewConfirmablePostMessage(Uri aUri); 460 461 /** 462 * Allocates and initializes a new CoAP Non-confirmable Post message with Network Control priority 463 * level. 464 * 465 * The CoAP header is initialized as `kTypeNonConfirmable` and `kCodePost` with a given URI and a randomly 466 * generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`). 467 * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and 468 * remove the payload marker when there is no payload. 469 * 470 * @param[in] aUri The URI. 471 * 472 * @returns A pointer to the message or `nullptr` if failed to allocate message. 473 */ 474 Message *NewPriorityNonConfirmablePostMessage(Uri aUri); 475 476 /** 477 * Allocates and initializes a new CoAP Non-confirmable Post message with normal priority level. 478 * 479 * The CoAP header is initialized as `kTypeNonConfirmable` and `kCodePost` with a given URI and a randomly 480 * generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`). 481 * Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and 482 * remove the payload marker when there is no payload. 483 * 484 * @param[in] aUri The URI. 485 * 486 * @returns A pointer to the message or `nullptr` if failed to allocate message. 487 */ 488 Message *NewNonConfirmablePostMessage(Uri aUri); 489 490 /** 491 * Allocates and initializes a new CoAP response message with Network Control priority level for a 492 * given request message. 493 * 494 * The CoAP header is initialized as `kTypeAck` with `kCodeChanged`. The token and message ID is copied from 495 * @p aRequest. This method also sets the payload marker (calling `SetPayloadMarker()`). Even if message has 496 * no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload 497 * marker when there is no payload. 498 * 499 * @returns A pointer to the message or `nullptr` if failed to allocate message. 500 */ 501 Message *NewPriorityResponseMessage(const Message &aRequest); 502 503 /** 504 * Allocates and initializes a new CoAP response message with regular priority level for a given 505 * request message. 506 * 507 * The CoAP header is initialized as `kTypeAck` with `kCodeChanged`. The token and message ID is copied from 508 * @p aRequest. This method also sets the payload marker (calling `SetPayloadMarker()`). Even if message has 509 * no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload 510 * marker when there is no payload. 511 * 512 * @returns A pointer to the message or `nullptr` if failed to allocate message. 513 */ 514 Message *NewResponseMessage(const Message &aRequest); 515 516 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 517 /** 518 * Sends a CoAP message block-wise with custom transmission parameters. 519 * 520 * If a response for a request is expected, respective function and context information should be provided. 521 * If no response is expected, these arguments should be NULL pointers. 522 * If Message ID was not set in the header (equal to 0), this method will assign unique Message ID to the message. 523 * 524 * @param[in] aMessage A reference to the message to send. 525 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 526 * @param[in] aTxParameters A reference to transmission parameters for this message. 527 * @param[in] aHandler A function pointer that shall be called on response reception or time-out. 528 * @param[in] aContext A pointer to arbitrary context information. 529 * @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer. 530 * @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer. 531 * 532 * @retval kErrorNone Successfully sent CoAP message. 533 * @retval kErrorNoBufs Failed to allocate retransmission data. 534 */ 535 Error SendMessage(Message &aMessage, 536 const Ip6::MessageInfo &aMessageInfo, 537 const TxParameters &aTxParameters, 538 otCoapResponseHandler aHandler = nullptr, 539 void *aContext = nullptr, 540 otCoapBlockwiseTransmitHook aTransmitHook = nullptr, 541 otCoapBlockwiseReceiveHook aReceiveHook = nullptr); 542 #else // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 543 544 /** 545 * Sends a CoAP message with custom transmission parameters. 546 * 547 * If a response for a request is expected, respective function and context information should be provided. 548 * If no response is expected, these arguments should be `nullptr` pointers. 549 * If Message ID was not set in the header (equal to 0), this method will assign unique Message ID to the message. 550 * 551 * @param[in] aMessage A reference to the message to send. 552 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 553 * @param[in] aTxParameters A reference to transmission parameters for this message. 554 * @param[in] aHandler A function pointer that shall be called on response reception or time-out. 555 * @param[in] aContext A pointer to arbitrary context information. 556 * 557 * @retval kErrorNone Successfully sent CoAP message. 558 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP message. 559 */ 560 Error SendMessage(Message &aMessage, 561 const Ip6::MessageInfo &aMessageInfo, 562 const TxParameters &aTxParameters, 563 ResponseHandler aHandler, 564 void *aContext); 565 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 566 567 /** 568 * Sends a CoAP message with custom transmission parameters. 569 * 570 * If Message ID was not set in the header (equal to 0), this method will assign unique Message ID to the message. 571 * 572 * @param[in] aMessage A reference to the message to send. 573 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 574 * @param[in] aTxParameters A reference to transmission parameters for this message. 575 * 576 * @retval kErrorNone Successfully sent CoAP message. 577 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP message. 578 */ 579 Error SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const TxParameters &aTxParameters); 580 /** 581 * Sends a CoAP message with default transmission parameters. 582 * 583 * If Message ID was not set in the header (equal to 0), this method will assign unique Message ID to the message. 584 * 585 * @param[in] aMessage A reference to the message to send. 586 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 587 * @param[in] aHandler A function pointer that shall be called on response reception or time-out. 588 * @param[in] aContext A pointer to arbitrary context information. 589 * 590 * @retval kErrorNone Successfully sent CoAP message. 591 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 592 */ 593 Error SendMessage(Message &aMessage, 594 const Ip6::MessageInfo &aMessageInfo, 595 ResponseHandler aHandler, 596 void *aContext); 597 598 /** 599 * Sends a CoAP message with default transmission parameters. 600 * 601 * If Message ID was not set in the header (equal to 0), this method will assign unique Message ID to the message. 602 * 603 * @param[in] aMessage A reference to the message to send. 604 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 605 * 606 * @retval kErrorNone Successfully sent CoAP message. 607 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 608 */ 609 Error SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 610 611 /** 612 * Sends a CoAP reset message. 613 * 614 * @param[in] aRequest A reference to the CoAP Message that was used in CoAP request. 615 * @param[in] aMessageInfo The message info corresponding to the CoAP request. 616 * 617 * @retval kErrorNone Successfully enqueued the CoAP response message. 618 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 619 * @retval kErrorInvalidArgs The @p aRequest is not of confirmable type. 620 */ 621 Error SendReset(Message &aRequest, const Ip6::MessageInfo &aMessageInfo); 622 623 /** 624 * Sends header-only CoAP response message. 625 * 626 * @param[in] aCode The CoAP code of this response. 627 * @param[in] aRequest A reference to the CoAP Message that was used in CoAP request. 628 * @param[in] aMessageInfo The message info corresponding to the CoAP request. 629 * 630 * @retval kErrorNone Successfully enqueued the CoAP response message. 631 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 632 * @retval kErrorInvalidArgs The @p aRequest header is not of confirmable type. 633 */ 634 Error SendHeaderResponse(Message::Code aCode, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo); 635 636 /** 637 * Sends a CoAP ACK empty message which is used in Separate Response for confirmable requests. 638 * 639 * @param[in] aRequest A reference to the CoAP Message that was used in CoAP request. 640 * @param[in] aMessageInfo The message info corresponding to the CoAP request. 641 * 642 * @retval kErrorNone Successfully enqueued the CoAP response message. 643 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 644 * @retval kErrorInvalidArgs The @p aRequest header is not of confirmable type. 645 */ 646 Error SendAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo); 647 648 /** 649 * Sends a CoAP ACK message on which a dummy CoAP response is piggybacked. 650 * 651 * @param[in] aRequest A reference to the CoAP Message that was used in CoAP request. 652 * @param[in] aMessageInfo The message info corresponding to the CoAP request. 653 * @param[in] aCode The CoAP code of the dummy CoAP response. 654 * 655 * @retval kErrorNone Successfully enqueued the CoAP response message. 656 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 657 * @retval kErrorInvalidArgs The @p aRequest header is not of confirmable type. 658 */ 659 Error SendEmptyAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo, Code aCode); 660 661 /** 662 * Sends a CoAP ACK message on which a dummy CoAP response is piggybacked. 663 * 664 * @param[in] aRequest A reference to the CoAP Message that was used in CoAP request. 665 * @param[in] aMessageInfo The message info corresponding to the CoAP request. 666 * 667 * @retval kErrorNone Successfully enqueued the CoAP response message. 668 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 669 * @retval kErrorInvalidArgs The @p aRequest header is not of confirmable type. 670 */ 671 Error SendEmptyAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo); 672 673 /** 674 * Sends a header-only CoAP message to indicate no resource matched for the request. 675 * 676 * @param[in] aRequest A reference to the CoAP Message that was used in CoAP request. 677 * @param[in] aMessageInfo The message info corresponding to the CoAP request. 678 * 679 * @retval kErrorNone Successfully enqueued the CoAP response message. 680 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 681 */ 682 Error SendNotFound(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo); 683 684 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 685 /** 686 * Sends a header-only CoAP message to indicate not all blocks have been sent or 687 * were sent out of order. 688 * 689 * @param[in] aRequest A reference to the CoAP Message that was used in CoAP request. 690 * @param[in] aMessageInfo The message info corresponding to the CoAP request. 691 * 692 * @retval kErrorNone Successfully enqueued the CoAP response message. 693 * @retval kErrorNoBufs Insufficient buffers available to send the CoAP response. 694 */ SendRequestEntityIncomplete(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)695 Error SendRequestEntityIncomplete(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo) 696 { 697 return SendHeaderResponse(kCodeRequestIncomplete, aRequest, aMessageInfo); 698 } 699 #endif 700 701 /** 702 * Aborts CoAP transactions associated with given handler and context. 703 * 704 * The associated response handler will be called with kErrorAbort. 705 * 706 * @param[in] aHandler A function pointer that should be called when the transaction ends. 707 * @param[in] aContext A pointer to arbitrary context information. 708 * 709 * @retval kErrorNone Successfully aborted CoAP transactions. 710 * @retval kErrorNotFound CoAP transaction associated with given handler was not found. 711 */ 712 Error AbortTransaction(ResponseHandler aHandler, void *aContext); 713 714 /** 715 * Sets interceptor to be called before processing a CoAP packet. 716 * 717 * @param[in] aInterceptor A pointer to the interceptor. 718 * @param[in] aContext A pointer to arbitrary context information. 719 */ SetInterceptor(Interceptor aInterceptor,void * aContext)720 void SetInterceptor(Interceptor aInterceptor, void *aContext) { mInterceptor.Set(aInterceptor, aContext); } 721 722 /** 723 * Returns a reference to the request message list. 724 * 725 * @returns A reference to the request message list. 726 */ GetRequestMessages(void) const727 const MessageQueue &GetRequestMessages(void) const { return mPendingRequests; } 728 729 /** 730 * Returns a reference to the cached response list. 731 * 732 * @returns A reference to the cached response list. 733 */ GetCachedResponses(void) const734 const MessageQueue &GetCachedResponses(void) const { return mResponsesQueue.GetResponses(); } 735 736 protected: 737 /** 738 * Defines function pointer to handle a CoAP resource. 739 * 740 * When processing a received request, this handler is called first with the URI path before checking the list of 741 * added `Resource` entries to match against the URI path. 742 * 743 * @param[in] aCoapBase A reference the CoAP agent. 744 * @param[in] aUriPath The URI Path string. 745 * @param[in] aMessage The received message. 746 * @param[in] aMessageInfo The message info associated with @p aMessage. 747 * 748 * @retval TRUE Indicates that the URI path was known and the message was processed by the handler. 749 * @retval FALSE Indicates that URI path was not known and the message was not processed by the handler. 750 */ 751 typedef bool (*ResourceHandler)(CoapBase &aCoapBase, 752 const char *aUriPath, 753 Message &aMessage, 754 const Ip6::MessageInfo &aMessageInfo); 755 756 /** 757 * Pointer is called to send a CoAP message. 758 * 759 * @param[in] aCoapBase A reference to the CoAP agent. 760 * @param[in] aMessage A reference to the message to send. 761 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 762 * 763 * @retval kErrorNone Successfully sent CoAP message. 764 * @retval kErrorNoBufs Failed to allocate retransmission data. 765 */ 766 typedef Error (*Sender)(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 767 768 /** 769 * Initializes the object. 770 * 771 * @param[in] aInstance A reference to the OpenThread instance. 772 * @param[in] aSender A function pointer to send CoAP message, which SHOULD be a static 773 * member method of a descendant of this class. 774 */ 775 CoapBase(Instance &aInstance, Sender aSender); 776 777 /** 778 * Receives a CoAP message. 779 * 780 * @param[in] aMessage A reference to the received message. 781 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 782 */ 783 void Receive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 784 785 /** 786 * Sets the resource handler function. 787 * 788 * @param[in] aHandler The resource handler function pointer. 789 */ SetResourceHandler(ResourceHandler aHandler)790 void SetResourceHandler(ResourceHandler aHandler) { mResourceHandler = aHandler; } 791 792 private: 793 struct Metadata : public Message::FooterData<Metadata> 794 { 795 Ip6::Address mSourceAddress; // IPv6 address of the message source. 796 Ip6::Address mDestinationAddress; // IPv6 address of the message destination. 797 uint16_t mDestinationPort; // UDP port of the message destination. 798 ResponseHandler mResponseHandler; // A function pointer that is called on response reception. 799 void *mResponseContext; // A pointer to arbitrary context information. 800 TimeMilli mNextTimerShot; // Time when the timer should shoot for this message. 801 uint32_t mRetransmissionTimeout; // Delay that is applied to next retransmission. 802 uint8_t mRetransmissionsRemaining; // Number of retransmissions remaining. 803 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE 804 uint8_t mHopLimit; // The hop limit. 805 #endif 806 bool mAcknowledged : 1; // Information that request was acknowledged. 807 bool mConfirmable : 1; // Information that message is confirmable. 808 bool mMulticastLoop : 1; // Information that multicast loop is enabled. 809 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE 810 bool mIsHostInterface : 1; // TRUE if packets sent/received via host interface, FALSE otherwise. 811 #endif 812 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE 813 bool mObserve : 1; // Information that this request involves Observations. 814 #endif 815 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 816 otCoapBlockwiseReceiveHook mBlockwiseReceiveHook; // Function pointer called on Block2 response reception. 817 otCoapBlockwiseTransmitHook mBlockwiseTransmitHook; // Function pointer called on Block1 response reception. 818 #endif 819 }; 820 821 Message *InitMessage(Message *aMessage, Type aType, Uri aUri); 822 Message *InitResponse(Message *aMessage, const Message &aRequest); 823 824 static void HandleRetransmissionTimer(Timer &aTimer); 825 void HandleRetransmissionTimer(void); 826 827 void ClearRequests(const Ip6::Address *aAddress); 828 Message *CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLength, const Metadata &aMetadata); 829 void DequeueMessage(Message &aMessage); 830 Message *FindRelatedRequest(const Message &aResponse, const Ip6::MessageInfo &aMessageInfo, Metadata &aMetadata); 831 void FinalizeCoapTransaction(Message &aRequest, 832 const Metadata &aMetadata, 833 Message *aResponse, 834 const Ip6::MessageInfo *aMessageInfo, 835 Error aResult); 836 837 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 838 void FreeLastBlockResponse(void); 839 Error CacheLastBlockResponse(Message *aResponse); 840 841 Error PrepareNextBlockRequest(Message::BlockType aType, 842 bool aMoreBlocks, 843 Message &aRequestOld, 844 Message &aRequest, 845 Message &aMessage); 846 Error ProcessBlock1Request(Message &aMessage, 847 const Ip6::MessageInfo &aMessageInfo, 848 const ResourceBlockWise &aResource, 849 uint32_t aTotalLength); 850 Error ProcessBlock2Request(Message &aMessage, 851 const Ip6::MessageInfo &aMessageInfo, 852 const ResourceBlockWise &aResource); 853 #endif 854 void ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 855 void ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 856 857 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 858 Error SendNextBlock1Request(Message &aRequest, 859 Message &aMessage, 860 const Ip6::MessageInfo &aMessageInfo, 861 const Metadata &aCoapMetadata); 862 Error SendNextBlock2Request(Message &aRequest, 863 Message &aMessage, 864 const Ip6::MessageInfo &aMessageInfo, 865 const Metadata &aCoapMetadata, 866 uint32_t aTotalLength, 867 bool aBeginBlock1Transfer); 868 #endif 869 void SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 870 Error SendEmptyMessage(Type aType, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo); 871 872 Error Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 873 874 MessageQueue mPendingRequests; 875 uint16_t mMessageId; 876 TimerMilliContext mRetransmissionTimer; 877 878 LinkedList<Resource> mResources; 879 880 Callback<Interceptor> mInterceptor; 881 ResponsesQueue mResponsesQueue; 882 883 Callback<RequestHandler> mDefaultHandler; 884 885 ResourceHandler mResourceHandler; 886 887 const Sender mSender; 888 889 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 890 LinkedList<ResourceBlockWise> mBlockWiseResources; 891 Message *mLastResponse; 892 #endif 893 }; 894 895 /** 896 * Implements the CoAP client and server. 897 */ 898 class Coap : public CoapBase 899 { 900 public: 901 /** 902 * Initializes the object. 903 * 904 * @param[in] aInstance A reference to the OpenThread instance. 905 */ 906 explicit Coap(Instance &aInstance); 907 908 /** 909 * Starts the CoAP service. 910 * 911 * @param[in] aPort The local UDP port to bind to. 912 * @param[in] aNetifIdentifier The network interface identifier to bind. 913 * 914 * @retval kErrorNone Successfully started the CoAP service. 915 * @retval kErrorFailed Failed to start CoAP agent. 916 */ 917 Error Start(uint16_t aPort, Ip6::NetifIdentifier aNetifIdentifier = Ip6::kNetifUnspecified); 918 919 /** 920 * Stops the CoAP service. 921 * 922 * @retval kErrorNone Successfully stopped the CoAP service. 923 * @retval kErrorFailed Failed to stop CoAP agent. 924 */ 925 Error Stop(void); 926 927 protected: 928 void HandleUdpReceive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 929 930 using CoapSocket = Ip6::Udp::SocketIn<Coap, &Coap::HandleUdpReceive>; 931 932 CoapSocket mSocket; 933 934 private: 935 static Error Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 936 Error Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 937 }; 938 939 } // namespace Coap 940 941 DefineCoreType(otCoapTxParameters, Coap::TxParameters); 942 DefineCoreType(otCoapResource, Coap::Resource); 943 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE 944 DefineCoreType(otCoapBlockwiseResource, Coap::ResourceBlockWise); 945 #endif 946 947 } // namespace ot 948 949 #endif // COAP_HPP_ 950