blob: bac0d505548291cb4c32177727bd070030ebddd2 [file] [log] [blame]
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for the CoAP server.
*/
#ifndef COAP_SERVER_HPP_
#define COAP_SERVER_HPP_
#include "openthread/coap.h"
#include <coap/coap_base.hpp>
#include <coap/coap_header.hpp>
#include <common/debug.hpp>
#include <common/message.hpp>
#include <common/timer.hpp>
#include <net/ip6.hpp>
#include <net/udp6.hpp>
namespace ot {
namespace Coap {
/**
* @addtogroup core-coap
*
* @{
*
*/
/**
* This class implements CoAP resource handling.
*
*/
class Resource : public otCoapResource
{
friend class Server;
public:
enum
{
kMaxReceivedUriPath = 32, ///< Maximum supported URI path on received messages.
};
/**
* This constructor initializes the resource.
*
* @param[in] aUriPath A pointer to a NULL-terminated string for the Uri-Path.
* @param[in] aHandler A function pointer that is called when receiving a CoAP message for @p aUriPath.
* @param[in] aContext A pointer to arbitrary context information.
*/
Resource(const char *aUriPath, otCoapRequestHandler aHandler, void *aContext) {
mUriPath = aUriPath;
mHandler = aHandler;
mContext = aContext;
mNext = NULL;
}
/**
* This method returns a pointer to the next resource.
*
* @returns A Pointer to the next resource.
*
*/
Resource *GetNext(void) const { return static_cast<Resource *>(mNext); };
private:
void HandleRequest(Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) {
mHandler(mContext, &aHeader, &aMessage, &aMessageInfo);
}
};
/**
* This class implements metadata required for caching CoAP responses.
*
*/
class EnqueuedResponseHeader
{
public:
/**
* Default constructor creating empty object.
*
*/
EnqueuedResponseHeader(void): mDequeueTime(0), mMessageInfo() {}
/**
* Constructor creating object with valid dequeue time and message info.
*
* @param[in] aMessageInfo The message info containing source endpoint identification.
*
*/
EnqueuedResponseHeader(const Ip6::MessageInfo &aMessageInfo):
mDequeueTime(Timer::GetNow() + Timer::SecToMsec(kExchangeLifetime)),
mMessageInfo(aMessageInfo) {}
/**
* This method append metadata to the message.
*
* @param[in] aMessage A reference to the message.
*
* @retval kThreadError_None Successfully appended the bytes.
* @retval kThreadError_NoBufs Insufficient available buffers to grow the message.
*/
ThreadError AppendTo(Message &aMessage) const { return aMessage.Append(this, sizeof(*this)); }
/**
* This method reads request data from the message.
*
* @param[in] aMessage A reference to the message.
*
* @returns The number of bytes read.
*
*/
uint16_t ReadFrom(const Message &aMessage) {
return aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
}
/**
* This method removes metadata from the message.
*
* @param[in] aMessage A reference to the message.
*
*/
static void RemoveFrom(Message &aMessage) {
assert(aMessage.SetLength(aMessage.GetLength() - sizeof(EnqueuedResponseHeader)) == kThreadError_None);
}
/**
* This method checks if the message shall be sent before the given time.
*
* @param[in] aTime A time to compare.
*
* @retval TRUE If the message shall be sent before the given time.
* @retval FALSE Otherwise.
*
*/
bool IsEarlier(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mDequeueTime) > 0); }
/**
* This method returns number of milliseconds in which the message should be sent.
*
* @returns The number of milliseconds in which the message should be sent.
*
*/
uint32_t GetRemainingTime(void) const;
/**
* This method returns the message info of cached CoAP response.
*
* @returns The message info of the cached CoAP response.
*
*/
const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; }
private:
uint32_t mDequeueTime;
const Ip6::MessageInfo mMessageInfo;
};
/**
* This class caches CoAP responses to implement message deduplication.
*
*/
class ResponsesQueue
{
public:
/**
* Default class constructor.
*
* @param[in] aNetif A reference to the network interface that CoAP server should be assigned to.
*
*/
ResponsesQueue(Ip6::Netif &aNetif):
mTimer(aNetif.GetIp6().mTimerScheduler, &ResponsesQueue::HandleTimer, this) {}
/**
* Add given response to the cache.
*
* If matching response (the same Message ID, source endpoint address and port) exists in the cache given
* response is not added.
* The CoAP response is copied before it is added to the cache.
*
* @param[in] aMessage The CoAP response to add to the cache.
* @param[in] aMessageInfo The message info corresponding to @p aMessage.
*
*/
void EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
/**
* Remove the oldest response from the cache.
*
*/
void DequeueOldestResponse(void);
/**
* Remove all responses from the cache.
*
*/
void DequeueAllResponses(void);
/**
* Get a copy of CoAP response from the cache that matches given Message ID and source endpoint.
*
* @param[in] aHeader The CoAP message header containing Message ID.
* @param[in] aMessageInfo The message info containing source endpoint address and port.
* @param[out] aResponse A pointer to a copy of a cached CoAP response matching given arguments.
*
* @retval kThreadError_None Matching response found and successfully created a copy.
* @retval kThreadError_NoBufs Matching response found but there is not sufficient buffer to create a copy.
* @retval kThreadError_NotFound Matching response not found.
*
*/
ThreadError GetMatchedResponseCopy(const Header &aHeader,
const Ip6::MessageInfo &aMessageInfo,
Message **aResponse);
/**
* Get a copy of CoAP response from the cache that matches given Message ID and source endpoint.
*
* @param[in] aRequest The CoAP message containing Message ID.
* @param[in] aMessageInfo The message info containing source endpoint address and port.
* @param[out] aResponse A pointer to a copy of a cached CoAP response matching given arguments.
*
* @retval kThreadError_None Matching response found and successfully created a copy.
* @retval kThreadError_NoBufs Matching response found but there is not sufficient buffer to create a copy.
* @retval kThreadError_NotFound Matching response not found.
* @retval kThreadError_Parse Could not parse CoAP header in the request message.
*
*/
ThreadError GetMatchedResponseCopy(const Message &aRequest,
const Ip6::MessageInfo &aMessageInfo,
Message **aResponse);
/**
* Get a reference to the cached CoAP responses queue.
*
* @returns A reference to the cached CoAP responses queue.
*
*/
const MessageQueue &GetResponses(void) const { return mQueue; }
private:
enum
{
kMaxCachedResponses = OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES,
};
void DequeueResponse(Message &aMessage) { mQueue.Dequeue(aMessage); aMessage.Free(); }
MessageQueue mQueue;
Timer mTimer;
static void HandleTimer(void *aContext);
void HandleTimer(void);
};
/**
* This class implements the CoAP server.
*
*/
class Server : public CoapBase
{
public:
/**
* This constructor initializes the object.
*
* @param[in] aNetif A reference to the network interface that CoAP server should be assigned to.
* @param[in] aPort The port to listen on.
* @param[in] aSender A pointer to a function for sending messages.
* @param[in] aReceiver A pointer to a function for handling received messages.
*
*/
Server(Ip6::Netif &aNetif, uint16_t aPort, SenderFunction aSender = &Server::Send,
ReceiverFunction aReceiver = &Server::Receive);
/**
* This method starts the CoAP server.
*
* @retval kThreadError_None Successfully started the CoAP server.
*
*/
ThreadError Start(void);
/**
* This method stops the CoAP server.
*
* @retval kThreadError_None Successfully stopped the CoAP server.
*
*/
ThreadError Stop(void);
/**
* This method adds a resource to the CoAP server.
*
* @param[in] aResource A reference to the resource.
*
* @retval kThreadError_None Successfully added @p aResource.
* @retval kThreadError_Already The @p aResource was already added.
*
*/
ThreadError AddResource(Resource &aResource);
/**
* This method removes a resource from the CoAP server.
*
* @param[in] aResource A reference to the resource.
*
*/
void RemoveResource(Resource &aResource);
/**
* This method sends a CoAP response from the server.
*
* @param[in] aMessage The CoAP response to send.
* @param[in] aMessageInfo The message info corresponding to @p aMessage.
*
* @retval kThreadError_None Successfully enqueued the CoAP response message.
* @retval kThreadError_NoBufs Insufficient buffers available to send the CoAP response.
*
*/
ThreadError SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
/**
* This method sends a CoAP ACK message on which a dummy CoAP response is piggybacked.
*
* @param[in] aRequestHeader A reference to the CoAP Header that was used in CoAP request.
* @param[in] aMessageInfo The message info corresponding to the CoAP request.
*
* @retval kThreadError_None Successfully enqueued the CoAP response message.
* @retval kThreadError_NoBufs Insufficient buffers available to send the CoAP response.
* @retval kThreadError_InvalidArgs The @p aRequestHeader header is not of confirmable type.
*
*/
ThreadError SendEmptyAck(const Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo);
/**
* This method sets CoAP server's port number.
*
* @param[in] aPort A port number to set.
*
* @retval kThreadError_None Binding with a port succeeded.
*
*/
ThreadError SetPort(uint16_t aPort);
const MessageQueue &GetCachedResponses(void) const { return mResponsesQueue.GetResponses(); }
protected:
void ProcessReceivedMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
private:
static ThreadError Send(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) {
return (static_cast<Server *>(aContext))->mSocket.SendTo(aMessage, aMessageInfo);
}
static void Receive(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) {
(static_cast<Server *>(aContext))->ProcessReceivedMessage(aMessage, aMessageInfo);
}
uint16_t mPort;
Resource *mResources;
ResponsesQueue mResponsesQueue;
};
/**
* @}
*
*/
} // namespace Coap
} // namespace ot
#endif // COAP_SERVER_HPP_