#ifndef COAP_HPP_
#define COAP_HPP_
#include "openthread-core-config.h"
#include <openthread/coap.h>
#include "coap/coap_message.hpp"
#include "common/debug.hpp"
#include "common/linked_list.hpp"
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/non_copyable.hpp"
#include "common/timer.hpp"
#include "net/ip6.hpp"
#include "net/netif.hpp"
#include "net/udp6.hpp"
namespace ot {
namespace Coap {
typedef otCoapResponseHandler ResponseHandler;
typedef otCoapRequestHandler RequestHandler;
class TxParameters : public otCoapTxParameters
{
friend class CoapBase;
friend class ResponsesQueue;
public:
static const TxParameters &From(const otCoapTxParameters *aTxParameters)
{
return aTxParameters ? *static_cast<const TxParameters *>(aTxParameters) : GetDefault();
}
bool IsValid(void) const;
static const TxParameters &GetDefault(void) { return static_cast<const TxParameters &>(kDefaultTxParameters); }
private:
enum
{
kDefaultAckTimeout = 2000, kDefaultAckRandomFactorNumerator = 3,
kDefaultAckRandomFactorDenominator = 2,
kDefaultMaxRetransmit = 4,
kDefaultMaxLatency = 100000, };
uint32_t CalculateInitialRetransmissionTimeout(void) const;
uint32_t CalculateExchangeLifetime(void) const;
uint32_t CalculateMaxTransmitWait(void) const;
uint32_t CalculateSpan(uint8_t aMaxRetx) const;
static const otCoapTxParameters kDefaultTxParameters;
};
class Resource : public otCoapResource, public LinkedListEntry<Resource>
{
friend class CoapBase;
public:
enum
{
kMaxReceivedUriPath = 32, };
Resource(const char *aUriPath, RequestHandler aHandler, void *aContext)
{
mUriPath = aUriPath;
mHandler = aHandler;
mContext = aContext;
mNext = NULL;
}
const char *GetUriPath(void) const { return mUriPath; }
private:
void HandleRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const
{
mHandler(mContext, &aMessage, &aMessageInfo);
}
};
class ResponsesQueue
{
public:
explicit ResponsesQueue(Instance &aInstance);
void EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const TxParameters &aTxParameters);
void DequeueAllResponses(void);
otError GetMatchedResponseCopy(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo, Message **aResponse);
const MessageQueue &GetResponses(void) const { return mQueue; }
private:
enum
{
kMaxCachedResponses = OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES,
};
struct ResponseMetadata
{
otError AppendTo(Message &aMessage) const { return aMessage.Append(this, sizeof(*this)); }
void ReadFrom(const Message &aMessage);
TimeMilli mDequeueTime;
Ip6::MessageInfo mMessageInfo;
};
const Message *FindMatchedResponse(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo) const;
void DequeueResponse(Message &aMessage);
void UpdateQueue(void);
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
MessageQueue mQueue;
TimerMilliContext mTimer;
};
class CoapBase : public InstanceLocator, private NonCopyable
{
friend class ResponsesQueue;
public:
typedef otError (*Interceptor)(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext);
void ClearRequestsAndResponses(void);
void ClearRequests(const Ip6::Address &aAddress);
void AddResource(Resource &aResource);
void RemoveResource(Resource &aResource);
void SetDefaultHandler(RequestHandler aHandler, void *aContext);
Message *NewMessage(const Message::Settings &aSettings = Message::Settings::GetDefault());
Message *NewPriorityMessage(void)
{
return NewMessage(Message::Settings(Message::kWithLinkSecurity, Message::kPriorityNet));
}
otError SendMessage(Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
const TxParameters & aTxParameters,
ResponseHandler aHandler = NULL,
void * aContext = NULL);
otError SendMessage(Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
ResponseHandler aHandler = NULL,
void * aContext = NULL);
otError SendReset(Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
otError SendHeaderResponse(Message::Code aCode, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
otError SendAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
otError SendEmptyAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
otError SendNotFound(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
otError AbortTransaction(ResponseHandler aHandler, void *aContext);
void SetInterceptor(Interceptor aInterceptor, void *aContext);
const MessageQueue &GetRequestMessages(void) const { return mPendingRequests; }
const MessageQueue &GetCachedResponses(void) const { return mResponsesQueue.GetResponses(); }
protected:
typedef otError (*Sender)(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
CoapBase(Instance &aInstance, Sender aSender);
void Receive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
private:
struct Metadata
{
otError AppendTo(Message &aMessage) const { return aMessage.Append(this, sizeof(*this)); }
void ReadFrom(const Message &aMessage);
int UpdateIn(Message &aMessage) const;
Ip6::Address mSourceAddress; Ip6::Address mDestinationAddress; uint16_t mDestinationPort; ResponseHandler mResponseHandler; void * mResponseContext; TimeMilli mNextTimerShot; uint32_t mRetransmissionTimeout; uint8_t mRetransmissionsRemaining; bool mAcknowledged : 1; bool mConfirmable : 1; #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
bool mObserve : 1; #endif
};
static void HandleRetransmissionTimer(Timer &aTimer);
void HandleRetransmissionTimer(void);
void ClearRequests(const Ip6::Address *aAddress);
Message *CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLength, const Metadata &aMetadata);
void DequeueMessage(Message &aMessage);
Message *FindRelatedRequest(const Message &aResponse, const Ip6::MessageInfo &aMessageInfo, Metadata &aMetadata);
void FinalizeCoapTransaction(Message & aRequest,
const Metadata & aMetadata,
Message * aResponse,
const Ip6::MessageInfo *aMessageInfo,
otError aResult);
void ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
otError SendEmptyMessage(Message::Type aType, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo);
otError Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
MessageQueue mPendingRequests;
uint16_t mMessageId;
TimerMilliContext mRetransmissionTimer;
LinkedList<Resource> mResources;
void * mContext;
Interceptor mInterceptor;
ResponsesQueue mResponsesQueue;
RequestHandler mDefaultHandler;
void * mDefaultHandlerContext;
const Sender mSender;
};
class Coap : public CoapBase
{
public:
explicit Coap(Instance &aInstance);
otError Start(uint16_t aPort);
otError Stop(void);
private:
static otError Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
otError Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
Ip6::UdpSocket mSocket;
};
} }
#endif