mirror of
https://github.com/espressif/openthread.git
synced 2026-08-10 04:37:47 +00:00
CoAP: Implement CoAP client (#829)
* CoAP Client implementation * CoAP update in MleRouter and AddressResolver * Add CoAP client to Windows project files
This commit is contained in:
committed by
Jonathan Hui
parent
4538dafd3d
commit
be73d98e0b
@@ -19,6 +19,7 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\core\coap\coap_client.cpp" />
|
||||
<ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
|
||||
<ClCompile Include="..\..\src\core\coap\coap_server.cpp" />
|
||||
<ClCompile Include="..\..\src\core\common\crc16.cpp" />
|
||||
@@ -78,6 +79,7 @@
|
||||
<ClCompile Include="..\..\src\core\utils\global_address.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\core\coap\coap_client.hpp" />
|
||||
<ClInclude Include="..\..\src\core\coap\coap_header.hpp" />
|
||||
<ClInclude Include="..\..\src\core\coap\coap_server.hpp" />
|
||||
<ClInclude Include="..\..\src\core\common\code_utils.hpp" />
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\core\coap\coap_client.cpp">
|
||||
<Filter>Source Files\coap</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\coap\coap_header.cpp">
|
||||
<Filter>Source Files\coap</Filter>
|
||||
</ClCompile>
|
||||
@@ -233,6 +236,9 @@
|
||||
<ClInclude Include="..\..\src\core\openthread-core-config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\coap\coap_client.hpp">
|
||||
<Filter>Header Files\coap</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\coap\coap_header.hpp">
|
||||
<Filter>Header Files\coap</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\core\coap\coap_client.cpp" />
|
||||
<ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
|
||||
<ClCompile Include="..\..\src\core\coap\coap_server.cpp" />
|
||||
<ClCompile Include="..\..\src\core\common\crc16.cpp" />
|
||||
@@ -76,6 +77,7 @@
|
||||
<ClCompile Include="..\..\src\core\utils\global_address.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\core\coap\coap_client.hpp" />
|
||||
<ClInclude Include="..\..\src\core\coap\coap_header.hpp" />
|
||||
<ClInclude Include="..\..\src\core\coap\coap_server.hpp" />
|
||||
<ClInclude Include="..\..\src\core\common\code_utils.hpp" />
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\core\coap\coap_client.cpp">
|
||||
<Filter>Source Files\coap</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\core\coap\coap_header.cpp">
|
||||
<Filter>Source Files\coap</Filter>
|
||||
</ClCompile>
|
||||
@@ -230,6 +233,9 @@
|
||||
<ClInclude Include="..\..\src\core\openthread-core-config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\coap\coap_client.hpp">
|
||||
<Filter>Header Files\coap</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\core\coap\coap_header.hpp">
|
||||
<Filter>Header Files\coap</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -59,6 +59,7 @@ include_HEADERS = \
|
||||
openthread.h \
|
||||
openthread-diag.h \
|
||||
openthread-types.h \
|
||||
openthread-coap.h \
|
||||
$(NULL)
|
||||
|
||||
install-headers: install-includeHEADERS
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* 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
|
||||
* @brief
|
||||
* This file defines the top-level functions for the OpenThread CoAP implementation.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_COAP_H_
|
||||
#define OPENTHREAD_COAP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread-types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup coap CoAP
|
||||
*
|
||||
* @brief
|
||||
* This module includes functions that control CoAP communication.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* CoAP Type values.
|
||||
*
|
||||
*/
|
||||
typedef enum otCoapType
|
||||
{
|
||||
kCoapTypeConfirmable = 0x00, ///< Confirmable
|
||||
kCoapTypeNonConfirmable = 0x10, ///< Non-confirmable
|
||||
kCoapTypeAcknowledgment = 0x20, ///< Acknowledgment
|
||||
kCoapTypeReset = 0x30, ///< Reset
|
||||
} otCoapType;
|
||||
|
||||
/**
|
||||
* CoAP Code values.
|
||||
*
|
||||
*/
|
||||
typedef enum otCoapCode
|
||||
{
|
||||
kCoapRequestGet = 0x01, ///< Get
|
||||
kCoapRequestPost = 0x02, ///< Post
|
||||
kCoapRequestPut = 0x03, ///< Put
|
||||
kCoapRequestDelete = 0x04, ///< Delete
|
||||
kCoapResponseChanged = 0x44, ///< Changed
|
||||
kCoapResponseContent = 0x45, ///< Content
|
||||
} otCoapCode;
|
||||
|
||||
/**
|
||||
* CoAP Option Numbers
|
||||
*/
|
||||
typedef enum otCoapOptionType
|
||||
{
|
||||
kCoapOptionUriPath = 11, ///< Uri-Path
|
||||
kCoapOptionContentFormat = 12, ///< Content-Format
|
||||
} otCoapOptionType;
|
||||
|
||||
/**
|
||||
* This structure represents a CoAP option.
|
||||
*
|
||||
*/
|
||||
typedef struct otCoapOption
|
||||
{
|
||||
uint16_t mNumber; ///< Option Number
|
||||
uint16_t mLength; ///< Option Length
|
||||
const uint8_t *mValue; ///< A pointer to the Option Value
|
||||
} otCoapOption;
|
||||
|
||||
#define OT_COAP_HEADER_MAX_LENGTH 128 ///< Max CoAP header length (bytes)
|
||||
|
||||
/**
|
||||
* This structure represents a CoAP header.
|
||||
*
|
||||
*/
|
||||
typedef struct otCoapHeader
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t mVersionTypeToken;
|
||||
uint8_t mCode;
|
||||
uint16_t mMessageId;
|
||||
} mFields;
|
||||
uint8_t mBytes[OT_COAP_HEADER_MAX_LENGTH];
|
||||
} mHeader;
|
||||
uint8_t mHeaderLength;
|
||||
uint16_t mOptionLast;
|
||||
uint16_t mNextOptionOffset;
|
||||
otCoapOption mOption;
|
||||
} otCoapHeader;
|
||||
|
||||
/**
|
||||
* This function pointer is called when a CoAP response is received or on the request timeout.
|
||||
*
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
* @param[in[ aHeader A pointer to the received CoAP header. NULL if no response was received.
|
||||
* @param[in] aMessage A pointer to the message buffer containing the response. NULL if no response was received.
|
||||
* @param[in] aResult A result of the CoAP transaction.
|
||||
*
|
||||
* @retval kThreadError_None A response was received successfully.
|
||||
* @retval kThreadError_Abort A CoAP transaction was reseted by peer.
|
||||
* @retval kThreadError_ResponseTimeout No response or acknowledgment received during timeout period.
|
||||
*
|
||||
*/
|
||||
typedef void (*otCoapResponseHandler)(void *aContext, otCoapHeader *aHeader, otMessage aMessage,
|
||||
ThreadError aResult);
|
||||
|
||||
/**
|
||||
* This method initializes the CoAP header.
|
||||
*
|
||||
* @param[inout] aHeader A pointer to the CoAP header to initialize.
|
||||
* @param[in] aType CoAP message type.
|
||||
* @param[in] aCode CoAP message code.
|
||||
*
|
||||
*/
|
||||
void otCoapHeaderInit(otCoapHeader *aHeader, otCoapType aType, otCoapCode aCode);
|
||||
|
||||
/**
|
||||
* This method sets the Token value and length in a header.
|
||||
*
|
||||
* @param[inout] aHeader A pointer to the CoAP header.
|
||||
* @param[in] aToken A pointer to the Token value.
|
||||
* @param[in] aTokenLength The Length of @p aToken.
|
||||
*
|
||||
*/
|
||||
void otCoapHeaderSetToken(otCoapHeader *aHeader, const uint8_t *aToken, uint8_t aTokenLength);
|
||||
|
||||
/**
|
||||
* This method appends a CoAP option in a header.
|
||||
*
|
||||
* @param[inout] aHeader A pointer to the CoAP header.
|
||||
* @param[in] aOption A pointer to the CoAP option.
|
||||
*
|
||||
* @retval kThreadError_None Successfully appended the option.
|
||||
* @retval kThreadError_InvalidArgs The option type is not equal or greater than the last option type.
|
||||
* @retval kThreadError_NoBufs The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
ThreadError otCoapHeaderAppendOption(otCoapHeader *aHeader, const otCoapOption *aOption);
|
||||
|
||||
/**
|
||||
* This method adds Payload Marker indicating beginning of the payload to the CoAP header.
|
||||
*
|
||||
* @param[inout] aHeader A pointer to the CoAP header.
|
||||
*
|
||||
* @retval kThreadError_None Payload Marker successfully added.
|
||||
* @retval kThreadError_NoBufs Header Payload Marker exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
void otCoapHeaderSetPayloadMarker(otCoapHeader *aHeader);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the current option.
|
||||
*
|
||||
* @param[in] aHeader A pointer to the CoAP header.
|
||||
*
|
||||
* @returns A pointer to the current option. If no option is present NULL pointer is returned.
|
||||
*
|
||||
*/
|
||||
const otCoapOption *otCoapGetCurrentOption(const otCoapHeader *aHeader);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the next option.
|
||||
*
|
||||
* @param[in] aHeader A pointer to the CoAP header.
|
||||
*
|
||||
* @returns A pointer to the next option. If no more options are present NULL pointer is returned.
|
||||
*
|
||||
*/
|
||||
const otCoapOption *otCoapGetNextOption(otCoapHeader *aHeader);
|
||||
|
||||
/**
|
||||
* This method creates a new message with a CoAP header.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aHeader A pointer to a CoAP header that is used to create the message.
|
||||
*
|
||||
* @returns A pointer to the message or NULL if failed to allocate message.
|
||||
*
|
||||
*/
|
||||
otMessage otNewCoapMessage(otInstance *aInstance, const otCoapHeader *aHeader);
|
||||
|
||||
/**
|
||||
* This method sends a CoAP message.
|
||||
*
|
||||
* If a response for a request is expected, respective function and contex information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the message to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or timeout.
|
||||
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
|
||||
*
|
||||
* @retval kThreadError_None Successfully sent CoAP message.
|
||||
* @retval kThreadError_NoBufs Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
ThreadError otSendCoapMessage(otInstance *aInstance, otMessage aMessage, const otMessageInfo *aMessageInfo,
|
||||
otCoapResponseHandler aHandler, void *aContext);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* OPENTHREAD_COAP_H_ */
|
||||
@@ -162,6 +162,11 @@ typedef enum ThreadError
|
||||
*/
|
||||
kThreadError_NotCapable = 29,
|
||||
|
||||
/**
|
||||
* Coap response or acknowledgment not received.
|
||||
*/
|
||||
kThreadError_ResponseTimeout = 30,
|
||||
|
||||
kThreadError_Error = 255,
|
||||
} ThreadError;
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ extern "C" {
|
||||
* @defgroup messages Message Buffers
|
||||
* @defgroup ip6 IPv6
|
||||
* @defgroup udp UDP
|
||||
* @defgroup coap CoAP
|
||||
*
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -37,6 +37,7 @@ libopenthread_a_CPPFLAGS = \
|
||||
|
||||
libopenthread_a_SOURCES = \
|
||||
openthread.cpp \
|
||||
coap/coap_client.cpp \
|
||||
coap/coap_header.cpp \
|
||||
coap/coap_server.cpp \
|
||||
common/crc16.cpp \
|
||||
@@ -114,6 +115,7 @@ noinst_HEADERS = \
|
||||
openthread-core-config.h \
|
||||
openthread-core-default-config.h \
|
||||
openthread-instance.h \
|
||||
coap/coap_client.hpp \
|
||||
coap/coap_header.hpp \
|
||||
coap/coap_server.hpp \
|
||||
common/code_utils.hpp \
|
||||
|
||||
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <coap/coap_client.hpp>
|
||||
#include <common/debug.hpp>
|
||||
#include <common/code_utils.hpp>
|
||||
#include <net/ip6.hpp>
|
||||
#include <platform/random.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the CoAP client.
|
||||
*/
|
||||
|
||||
namespace Thread {
|
||||
namespace Coap {
|
||||
|
||||
Client::Client(Ip6::Netif &aNetif):
|
||||
mSocket(aNetif.GetIp6().mUdp),
|
||||
mRetransmissionTimer(aNetif.GetIp6().mTimerScheduler, &Client::HandleRetransmissionTimer, this)
|
||||
{
|
||||
mMessageId = static_cast<uint16_t>(otPlatRandomGet());
|
||||
}
|
||||
|
||||
ThreadError Client::Start()
|
||||
{
|
||||
return mSocket.Open(&Client::HandleUdpReceive, this);
|
||||
}
|
||||
|
||||
ThreadError Client::Stop()
|
||||
{
|
||||
Message *message = mPendingRequests.GetHead();
|
||||
Message *messageToRemove;
|
||||
RequestMetadata requestMetadata;
|
||||
|
||||
// Remove all pending messages.
|
||||
while (message != NULL)
|
||||
{
|
||||
messageToRemove = message;
|
||||
message = message->GetNext();
|
||||
|
||||
requestMetadata.ReadFrom(*messageToRemove);
|
||||
FinalizeCoapTransaction(*messageToRemove, requestMetadata, NULL, NULL, kThreadError_Abort);
|
||||
}
|
||||
|
||||
return mSocket.Close();
|
||||
}
|
||||
|
||||
Message *Client::NewMessage(const Header &aHeader)
|
||||
{
|
||||
Message *message = NULL;
|
||||
|
||||
// Ensure that header has minimum required length.
|
||||
VerifyOrExit(aHeader.GetLength() >= Header::kMinHeaderLength, ;);
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(aHeader.GetLength())) != NULL, ;);
|
||||
message->Prepend(aHeader.GetBytes(), aHeader.GetLength());
|
||||
message->SetOffset(0);
|
||||
|
||||
exit:
|
||||
return message;
|
||||
}
|
||||
|
||||
ThreadError Client::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
|
||||
otCoapResponseHandler aHandler, void *aContext)
|
||||
{
|
||||
ThreadError error;
|
||||
Header header;
|
||||
RequestMetadata requestMetadata;
|
||||
Message *storedCopy = NULL;
|
||||
uint16_t copyLength = 0;
|
||||
|
||||
SuccessOrExit(error = header.FromMessage(aMessage));
|
||||
|
||||
// Set Message Id if it was not already set.
|
||||
if (header.GetMessageId() == 0)
|
||||
{
|
||||
header.SetMessageId(mMessageId++);
|
||||
aMessage.Write(0, Header::kMinHeaderLength, header.GetBytes());
|
||||
}
|
||||
|
||||
if (header.IsConfirmable())
|
||||
{
|
||||
// Create a copy of entire message and enqueue it.
|
||||
copyLength = aMessage.GetLength();
|
||||
}
|
||||
else if (header.IsNonConfirmable() && header.IsRequest() && (aHandler != NULL))
|
||||
{
|
||||
// As we do not retransmit non confirmable messages, create a copy of header only, for token information.
|
||||
copyLength = header.GetLength();
|
||||
}
|
||||
|
||||
if (copyLength > 0)
|
||||
{
|
||||
requestMetadata = RequestMetadata(header.IsConfirmable(), aMessageInfo, aHandler, aContext);
|
||||
VerifyOrExit((storedCopy = CopyAndEnqueueMessage(aMessage, copyLength, requestMetadata)) != NULL,
|
||||
error = kThreadError_NoBufs);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = mSocket.SendTo(aMessage, aMessageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && storedCopy != NULL)
|
||||
{
|
||||
DequeueMessage(*storedCopy);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Message *Client::CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLength,
|
||||
const RequestMetadata &aRequestMetadata)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Message *messageCopy = NULL;
|
||||
uint32_t alarmFireTime;
|
||||
|
||||
// Create a message copy of requested size.
|
||||
VerifyOrExit((messageCopy = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = messageCopy->SetLength(aCopyLength));
|
||||
aMessage.CopyTo(0, 0, aCopyLength, *messageCopy);
|
||||
|
||||
// Append the copy with retransmission data.
|
||||
SuccessOrExit(error = aRequestMetadata.AppendTo(*messageCopy));
|
||||
|
||||
// Setup the timer.
|
||||
if (mRetransmissionTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
alarmFireTime = mRetransmissionTimer.Gett0() + mRetransmissionTimer.Getdt();
|
||||
|
||||
if (aRequestMetadata.IsEarlier(alarmFireTime))
|
||||
{
|
||||
mRetransmissionTimer.Start(aRequestMetadata.mRetransmissionTimeout);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mRetransmissionTimer.Start(aRequestMetadata.mRetransmissionTimeout);
|
||||
}
|
||||
|
||||
// Enqueue the message.
|
||||
mPendingRequests.Enqueue(*messageCopy);
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && messageCopy != NULL)
|
||||
{
|
||||
messageCopy->Free();
|
||||
messageCopy = NULL;
|
||||
}
|
||||
|
||||
return messageCopy;
|
||||
}
|
||||
|
||||
void Client::DequeueMessage(Message &aMessage)
|
||||
{
|
||||
mPendingRequests.Dequeue(aMessage);
|
||||
|
||||
if (mRetransmissionTimer.IsRunning() && (mPendingRequests.GetHead() == NULL))
|
||||
{
|
||||
// No more requests pending, stop the timer.
|
||||
mRetransmissionTimer.Stop();
|
||||
}
|
||||
|
||||
// Free the message memory.
|
||||
aMessage.Free();
|
||||
|
||||
// No need to worry that the earliest pending message was removed -
|
||||
// the timer would just shoot earlier and then it'd be setup again.
|
||||
}
|
||||
|
||||
ThreadError Client::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
ThreadError error;
|
||||
Message *messageCopy = NULL;
|
||||
|
||||
// Create a message copy for lower layers.
|
||||
VerifyOrExit((messageCopy = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = messageCopy->SetLength(aMessage.GetLength() - sizeof(RequestMetadata)));
|
||||
aMessage.CopyTo(0, 0, aMessage.GetLength() - sizeof(RequestMetadata), *messageCopy);
|
||||
|
||||
// Send the copy.
|
||||
SuccessOrExit(error = mSocket.SendTo(*messageCopy, aMessageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && messageCopy != NULL)
|
||||
{
|
||||
messageCopy->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void Client::SendEmptyMessage(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId, Header::Type aType)
|
||||
{
|
||||
Header header;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
Message *message;
|
||||
ThreadError error = kThreadError_None;
|
||||
|
||||
header.Init();
|
||||
header.SetType(aType);
|
||||
header.SetMessageId(aMessageId);
|
||||
|
||||
VerifyOrExit((message = NewMessage(header)) != NULL, ;);
|
||||
|
||||
memset(&messageInfo, 0, sizeof(messageInfo));
|
||||
messageInfo.GetPeerAddr() = aAddress;
|
||||
messageInfo.mPeerPort = aPort;
|
||||
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::HandleRetransmissionTimer(void *aContext)
|
||||
{
|
||||
static_cast<Client *>(aContext)->HandleRetransmissionTimer();
|
||||
}
|
||||
|
||||
void Client::HandleRetransmissionTimer(void)
|
||||
{
|
||||
uint32_t now = otPlatAlarmGetNow();
|
||||
uint32_t nextDelta = 0xffffffff;
|
||||
RequestMetadata requestMetadata;
|
||||
Message *message = mPendingRequests.GetHead();
|
||||
Message *nextMessage = NULL;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
nextMessage = message->GetNext();
|
||||
requestMetadata.ReadFrom(*message);
|
||||
|
||||
if (requestMetadata.IsLater(now))
|
||||
{
|
||||
// Calculate the next delay and choose the lowest.
|
||||
if (requestMetadata.mNextTimerShot - now < nextDelta)
|
||||
{
|
||||
nextDelta = requestMetadata.mNextTimerShot - now;
|
||||
}
|
||||
}
|
||||
else if ((requestMetadata.mConfirmable) &&
|
||||
(requestMetadata.mRetransmissionCount < kMaxRetransmit))
|
||||
{
|
||||
// Increment retransmission counter and timer.
|
||||
requestMetadata.mRetransmissionCount++;
|
||||
requestMetadata.mRetransmissionTimeout *= 2;
|
||||
requestMetadata.mNextTimerShot = now + requestMetadata.mRetransmissionTimeout;
|
||||
requestMetadata.UpdateIn(*message);
|
||||
|
||||
// Check if retransmission time is lower than current lowest.
|
||||
if (requestMetadata.mRetransmissionTimeout < nextDelta)
|
||||
{
|
||||
nextDelta = requestMetadata.mRetransmissionTimeout;
|
||||
}
|
||||
|
||||
// Retransmit
|
||||
if (!requestMetadata.mAcknowledged)
|
||||
{
|
||||
memset(&messageInfo, 0, sizeof(messageInfo));
|
||||
messageInfo.GetPeerAddr() = requestMetadata.mDestinationAddress;
|
||||
messageInfo.mPeerPort = requestMetadata.mDestinationPort;
|
||||
|
||||
SendCopy(*message, messageInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No expected response or acknowledgment.
|
||||
FinalizeCoapTransaction(*message, requestMetadata, NULL, NULL, kThreadError_ResponseTimeout);
|
||||
}
|
||||
|
||||
message = nextMessage;
|
||||
}
|
||||
|
||||
if (nextDelta != 0xffffffff)
|
||||
{
|
||||
mRetransmissionTimer.Start(nextDelta);
|
||||
}
|
||||
}
|
||||
|
||||
Message *Client::FindRelatedRequest(const Header &aResponseHeader, const Ip6::MessageInfo &aMessageInfo,
|
||||
Header &aRequestHeader, RequestMetadata &aRequestMetadata)
|
||||
{
|
||||
Message *message = mPendingRequests.GetHead();
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
aRequestMetadata.ReadFrom(*message);
|
||||
|
||||
if ((aRequestMetadata.mDestinationAddress == aMessageInfo.GetPeerAddr()) &&
|
||||
(aRequestMetadata.mDestinationPort == aMessageInfo.mPeerPort))
|
||||
{
|
||||
assert(aRequestHeader.FromMessage(*message) == kThreadError_None);
|
||||
|
||||
switch (aResponseHeader.GetType())
|
||||
{
|
||||
case Header::kTypeReset:
|
||||
case Header::kTypeAcknowledgment:
|
||||
if (aResponseHeader.GetMessageId() == aRequestHeader.GetMessageId())
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Header::kTypeConfirmable:
|
||||
case Header::kTypeNonConfirmable:
|
||||
if (aResponseHeader.IsTokenEqual(aRequestHeader))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
message = message->GetNext();
|
||||
}
|
||||
|
||||
exit:
|
||||
return message;
|
||||
}
|
||||
|
||||
void Client::FinalizeCoapTransaction(Message &aRequest, const RequestMetadata &aRequestMetadata,
|
||||
Header *aResponseHeader, Message *aResponse, ThreadError aResult)
|
||||
{
|
||||
DequeueMessage(aRequest);
|
||||
|
||||
if (aRequestMetadata.mResponseHandler != NULL)
|
||||
{
|
||||
aRequestMetadata.mResponseHandler(aRequestMetadata.mResponseContext, aResponseHeader,
|
||||
aResponse, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
static_cast<Client *>(aContext)->HandleUdpReceive(*static_cast<Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
|
||||
}
|
||||
|
||||
void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
Header responseHeader;
|
||||
Header requestHeader;
|
||||
RequestMetadata requestMetadata;
|
||||
Message *message = NULL;
|
||||
ThreadError error;
|
||||
|
||||
SuccessOrExit(error = responseHeader.FromMessage(aMessage));
|
||||
aMessage.MoveOffset(responseHeader.GetLength());
|
||||
|
||||
message = FindRelatedRequest(responseHeader, aMessageInfo, requestHeader, requestMetadata);
|
||||
|
||||
if (message == NULL)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
switch (responseHeader.GetType())
|
||||
{
|
||||
case Header::kTypeReset:
|
||||
if (responseHeader.IsEmpty())
|
||||
{
|
||||
FinalizeCoapTransaction(*message, requestMetadata, NULL, NULL, kThreadError_Abort);
|
||||
}
|
||||
|
||||
// Silently ignore non-empty reset messages (RFC 7252, p. 4.2).
|
||||
break;
|
||||
|
||||
case Header::kTypeAcknowledgment:
|
||||
if (responseHeader.IsEmpty())
|
||||
{
|
||||
// Empty acknowledgment.
|
||||
if (requestMetadata.mConfirmable)
|
||||
{
|
||||
requestMetadata.mAcknowledged = true;
|
||||
requestMetadata.UpdateIn(*message);
|
||||
}
|
||||
|
||||
// Remove the message if response is not expected, otherwise await response.
|
||||
if (requestMetadata.mResponseHandler == NULL)
|
||||
{
|
||||
DequeueMessage(*message);
|
||||
}
|
||||
}
|
||||
else if (responseHeader.IsResponse() && responseHeader.IsTokenEqual(requestHeader))
|
||||
{
|
||||
// Piggybacked response.
|
||||
FinalizeCoapTransaction(*message, requestMetadata, &responseHeader, &aMessage, kThreadError_None);
|
||||
}
|
||||
|
||||
// Silently ignore acknowledgments carrying requests (RFC 7252, p. 4.2)
|
||||
// or with no token match (RFC 7252, p. 5.3.2)
|
||||
break;
|
||||
|
||||
case Header::kTypeConfirmable:
|
||||
case Header::kTypeNonConfirmable:
|
||||
if (responseHeader.IsConfirmable())
|
||||
{
|
||||
// Send empty ACK if it is a CON message.
|
||||
SendEmptyAck(aMessageInfo.GetPeerAddr(), aMessageInfo.mPeerPort, responseHeader.GetMessageId());
|
||||
}
|
||||
|
||||
FinalizeCoapTransaction(*message, requestMetadata, &responseHeader, &aMessage, kThreadError_None);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (error == kThreadError_None && message == NULL)
|
||||
{
|
||||
if (responseHeader.IsConfirmable() || responseHeader.IsNonConfirmable())
|
||||
{
|
||||
// Successfully parsed a header but no matching request was found - reject the message by sending reset.
|
||||
SendReset(aMessageInfo.GetPeerAddr(), aMessageInfo.mPeerPort, responseHeader.GetMessageId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RequestMetadata::RequestMetadata(bool aConfirmable, const Ip6::MessageInfo &aMessageInfo,
|
||||
otCoapResponseHandler aHandler, void *aContext)
|
||||
{
|
||||
mDestinationPort = aMessageInfo.mPeerPort;
|
||||
mDestinationAddress = aMessageInfo.GetPeerAddr();
|
||||
mResponseHandler = aHandler;
|
||||
mResponseContext = aContext;
|
||||
mRetransmissionCount = 0;
|
||||
mRetransmissionTimeout = Timer::SecToMsec(kAckTimeout);
|
||||
mRetransmissionTimeout += otPlatRandomGet() %
|
||||
(Timer::SecToMsec(kAckTimeout) * kAckRandomFactorNumerator / kAckRandomFactorDenominator -
|
||||
Timer::SecToMsec(kAckTimeout) + 1);
|
||||
|
||||
if (aConfirmable)
|
||||
{
|
||||
// Set next retransmission timeout.
|
||||
mNextTimerShot = Timer::GetNow() + mRetransmissionTimeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set overall response timeout.
|
||||
mNextTimerShot = Timer::GetNow() + kMaxTransmitWait;
|
||||
}
|
||||
|
||||
mAcknowledged = false;
|
||||
mConfirmable = aConfirmable;
|
||||
}
|
||||
|
||||
} // namespace Coap
|
||||
} // namespace Thread
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COAP_CLIENT_HPP_
|
||||
#define COAP_CLIENT_HPP_
|
||||
|
||||
#include <openthread-types.h>
|
||||
#include <openthread-coap.h>
|
||||
#include <coap/coap_header.hpp>
|
||||
#include <common/message.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <net/netif.hpp>
|
||||
#include <net/udp6.hpp>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for the CoAP client.
|
||||
*/
|
||||
|
||||
namespace Thread {
|
||||
namespace Coap {
|
||||
|
||||
class Client;
|
||||
|
||||
/**
|
||||
* Protocol Constants (RFC 7252).
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kAckTimeout = OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT,
|
||||
kAckRandomFactorNumerator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR,
|
||||
kAckRandomFactorDenominator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR,
|
||||
kMaxRetransmit = OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT,
|
||||
kNStart = 1,
|
||||
kDefaultLeisure = 5,
|
||||
kProbingRate = 1,
|
||||
|
||||
// Note that 2 << (kMaxRetransmit - 1) is equal to kMaxRetransmit power of 2
|
||||
kMaxTransmitSpan = kAckTimeout * ((2 << (kMaxRetransmit - 1)) - 1) *
|
||||
kAckRandomFactorNumerator / kAckRandomFactorDenominator,
|
||||
kMaxTransmitWait = kAckTimeout * ((2 << kMaxRetransmit) - 1) *
|
||||
kAckRandomFactorNumerator / kAckRandomFactorDenominator,
|
||||
kMaxLatency = 100,
|
||||
kProcessingDelay = kAckTimeout,
|
||||
kMaxRtt = 2 * kMaxLatency + kProcessingDelay,
|
||||
kExchangeLifetime = kMaxTransmitSpan + 2 * (kMaxLatency) + kProcessingDelay,
|
||||
kNonLifetime = kMaxTransmitSpan + kMaxLatency
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements metadata required for CoAP retransmission.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class RequestMetadata
|
||||
{
|
||||
friend class Client;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor for the object.
|
||||
*
|
||||
*/
|
||||
RequestMetadata(void):
|
||||
mDestinationPort(0),
|
||||
mResponseHandler(NULL),
|
||||
mResponseContext(NULL),
|
||||
mNextTimerShot(0),
|
||||
mRetransmissionTimeout(0),
|
||||
mRetransmissionCount(0),
|
||||
mAcknowledged(false),
|
||||
mConfirmable(false) {};
|
||||
|
||||
/**
|
||||
* This constructor initializes the object with specific values.
|
||||
*
|
||||
* @param[in] aConfirmable Information if the request is confirmable or not.
|
||||
* @param[in] aMessageInfo Addressing information.
|
||||
* @param[in] aHandler Pointer to a handler function for the response.
|
||||
* @param[in] aContext Context for the handler function.
|
||||
*
|
||||
*/
|
||||
RequestMetadata(bool aConfirmable, const Ip6::MessageInfo &aMessageInfo,
|
||||
otCoapResponseHandler aHandler, void *aContext);
|
||||
|
||||
/**
|
||||
* This method appends request data 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 updates request data in the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @returns The number of bytes updated.
|
||||
*
|
||||
*/
|
||||
int UpdateIn(Message &aMessage) const {
|
||||
return aMessage.Write(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 - mNextTimerShot) > 0); };
|
||||
|
||||
/**
|
||||
* This method checks if the message shall be sent after the given time.
|
||||
*
|
||||
* @param[in] aTime A time to compare.
|
||||
*
|
||||
* @retval TRUE If the message shall be sent after the given time.
|
||||
* @retval FALSE Otherwise.
|
||||
*/
|
||||
bool IsLater(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mNextTimerShot) < 0); };
|
||||
|
||||
private:
|
||||
|
||||
Ip6::Address mDestinationAddress; ///< IPv6 address of the message destination.
|
||||
uint16_t mDestinationPort; ///< UDP port of the message destination.
|
||||
otCoapResponseHandler mResponseHandler; ///< A function pointer that is called on response reception.
|
||||
void *mResponseContext; ///< A pointer to arbitrary context information.
|
||||
uint32_t mNextTimerShot; ///< Time when the timer should shoot for this message.
|
||||
uint32_t mRetransmissionTimeout; ///< Delay that is applied to next retransmission.
|
||||
uint8_t mRetransmissionCount; ///< Number of retransmissions.
|
||||
bool mAcknowledged: 1; ///< Information that request was acknowledged.
|
||||
bool mConfirmable: 1; ///< Information that message is confirmable.
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements CoAP client.
|
||||
*
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* This constructor initializes the object.
|
||||
*
|
||||
* @param[in] aNetif A reference to the network interface that CoAP client should be assigned to.
|
||||
*
|
||||
*/
|
||||
Client(Ip6::Netif &aNetif);
|
||||
|
||||
/**
|
||||
* This method starts the CoAP client.
|
||||
*
|
||||
* @retval kThreadError_None Successfully started the CoAP client.
|
||||
*
|
||||
*/
|
||||
ThreadError Start(void);
|
||||
|
||||
/**
|
||||
* This method stops the CoAP client.
|
||||
*
|
||||
* @retval kThreadError_None Successfully stopped the CoAP client.
|
||||
*
|
||||
*/
|
||||
ThreadError Stop(void);
|
||||
|
||||
/**
|
||||
* This method creates a new message with a CoAP header.
|
||||
*
|
||||
* @param[in] aHeader A reference to a CoAP header that is used to create the message.
|
||||
*
|
||||
* @returns A pointer to the message or NULL if failed to allocate message.
|
||||
*
|
||||
*/
|
||||
Message *NewMessage(const Header &aHeader);
|
||||
|
||||
/**
|
||||
* This method sends a CoAP message.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
* If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to send.
|
||||
* @param[in] aMessageInfo A reference to the message info associated with @p aMessage.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
* @retval kThreadError_None Successfully sent CoAP message.
|
||||
* @retval kThreadError_NoBufs Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
ThreadError SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
|
||||
otCoapResponseHandler aHandler = NULL, void *aContext = NULL);
|
||||
|
||||
private:
|
||||
Message *CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLength,
|
||||
const RequestMetadata &aRequestMetadata);
|
||||
void DequeueMessage(Message &aMessage);
|
||||
Message *FindRelatedRequest(const Header &aResponseHeader, const Ip6::MessageInfo &aMessageInfo,
|
||||
Header &aRequestHeader, RequestMetadata &aRequestMetadata);
|
||||
void FinalizeCoapTransaction(Message &aRequest, const RequestMetadata &aRequestMetadata,
|
||||
Header *aResponseHeader, Message *aResponse, ThreadError aResult);
|
||||
|
||||
ThreadError SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
void SendEmptyMessage(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId, Header::Type aType);
|
||||
void SendReset(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId) {
|
||||
SendEmptyMessage(aAddress, aPort, aMessageId, Header::kTypeReset);
|
||||
};
|
||||
void SendEmptyAck(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId) {
|
||||
SendEmptyMessage(aAddress, aPort, aMessageId, Header::kTypeAcknowledgment);
|
||||
};
|
||||
|
||||
static void HandleRetransmissionTimer(void *aContext);
|
||||
void HandleRetransmissionTimer(void);
|
||||
|
||||
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
|
||||
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
Ip6::UdpSocket mSocket;
|
||||
MessageQueue mPendingRequests;
|
||||
uint16_t mMessageId;
|
||||
Timer mRetransmissionTimer;
|
||||
};
|
||||
|
||||
} // namespace Coap
|
||||
} // namespace Thread
|
||||
|
||||
#endif // COAP_CLIENT_HPP_
|
||||
@@ -32,8 +32,10 @@
|
||||
*/
|
||||
|
||||
#include <coap/coap_header.hpp>
|
||||
#include <common/debug.hpp>
|
||||
#include <common/code_utils.hpp>
|
||||
#include <common/encoding.hpp>
|
||||
#include <platform/random.h>
|
||||
|
||||
namespace Thread {
|
||||
namespace Coap {
|
||||
@@ -44,7 +46,7 @@ void Header::Init(void)
|
||||
mOptionLast = 0;
|
||||
mNextOptionOffset = 0;
|
||||
memset(&mOption, 0, sizeof(mOption));
|
||||
memset(mHeader, 0, sizeof(mHeader));
|
||||
memset(&mHeader, 0, sizeof(mHeader));
|
||||
SetVersion(kVersion1);
|
||||
}
|
||||
|
||||
@@ -59,7 +61,7 @@ ThreadError Header::FromMessage(const Message &aMessage)
|
||||
uint16_t optionLength;
|
||||
|
||||
VerifyOrExit(length >= kTokenOffset, error = kThreadError_Parse);
|
||||
aMessage.Read(offset, kTokenOffset, mHeader);
|
||||
aMessage.Read(offset, kTokenOffset, mHeader.mBytes);
|
||||
mHeaderLength = kTokenOffset;
|
||||
offset += kTokenOffset;
|
||||
length -= kTokenOffset;
|
||||
@@ -68,23 +70,23 @@ ThreadError Header::FromMessage(const Message &aMessage)
|
||||
|
||||
tokenLength = GetTokenLength();
|
||||
VerifyOrExit(tokenLength <= kMaxTokenLength && tokenLength < length, error = kThreadError_Parse);
|
||||
aMessage.Read(offset, tokenLength, mHeader + mHeaderLength);
|
||||
aMessage.Read(offset, tokenLength, mHeader.mBytes + mHeaderLength);
|
||||
mHeaderLength += tokenLength;
|
||||
offset += tokenLength;
|
||||
length -= tokenLength;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
aMessage.Read(offset, 5, mHeader + mHeaderLength);
|
||||
aMessage.Read(offset, kMaxOptionHeaderSize, mHeader.mBytes + mHeaderLength);
|
||||
|
||||
if (mHeader[mHeaderLength] == 0xff)
|
||||
if (mHeader.mBytes[mHeaderLength] == 0xff)
|
||||
{
|
||||
mHeaderLength += sizeof(uint8_t);
|
||||
ExitNow(error = kThreadError_None);
|
||||
}
|
||||
|
||||
optionDelta = mHeader[mHeaderLength] >> 4;
|
||||
optionLength = mHeader[mHeaderLength] & 0xf;
|
||||
optionDelta = mHeader.mBytes[mHeaderLength] >> 4;
|
||||
optionLength = mHeader.mBytes[mHeaderLength] & 0xf;
|
||||
mHeaderLength += sizeof(uint8_t);
|
||||
offset += sizeof(uint8_t);
|
||||
length -= sizeof(uint8_t);
|
||||
@@ -95,7 +97,7 @@ ThreadError Header::FromMessage(const Message &aMessage)
|
||||
}
|
||||
else if (optionDelta == kOption1ByteExtension)
|
||||
{
|
||||
optionDelta = kOption1ByteExtensionOffset + mHeader[mHeaderLength];
|
||||
optionDelta = kOption1ByteExtensionOffset + mHeader.mBytes[mHeaderLength];
|
||||
mHeaderLength += sizeof(uint8_t);
|
||||
offset += sizeof(uint8_t);
|
||||
length -= sizeof(uint8_t);
|
||||
@@ -103,7 +105,7 @@ ThreadError Header::FromMessage(const Message &aMessage)
|
||||
else if (optionDelta == kOption2ByteExtension)
|
||||
{
|
||||
optionDelta = kOption2ByteExtensionOffset +
|
||||
static_cast<uint16_t>((mHeader[mHeaderLength] << 8) | mHeader[mHeaderLength + 1]);
|
||||
static_cast<uint16_t>((mHeader.mBytes[mHeaderLength] << 8) | mHeader.mBytes[mHeaderLength + 1]);
|
||||
mHeaderLength += sizeof(uint16_t);
|
||||
offset += sizeof(uint16_t);
|
||||
length -= sizeof(uint16_t);
|
||||
@@ -119,7 +121,7 @@ ThreadError Header::FromMessage(const Message &aMessage)
|
||||
}
|
||||
else if (optionLength == kOption1ByteExtension)
|
||||
{
|
||||
optionLength = kOption1ByteExtensionOffset + mHeader[mHeaderLength];
|
||||
optionLength = kOption1ByteExtensionOffset + mHeader.mBytes[mHeaderLength];
|
||||
mHeaderLength += sizeof(uint8_t);
|
||||
offset += sizeof(uint8_t);
|
||||
length -= sizeof(uint8_t);
|
||||
@@ -127,7 +129,7 @@ ThreadError Header::FromMessage(const Message &aMessage)
|
||||
else if (optionLength == kOption2ByteExtension)
|
||||
{
|
||||
optionLength = kOption2ByteExtensionOffset +
|
||||
static_cast<uint16_t>((mHeader[mHeaderLength] << 8) | mHeader[mHeaderLength + 1]);
|
||||
static_cast<uint16_t>((mHeader.mBytes[mHeaderLength] << 8) | mHeader.mBytes[mHeaderLength + 1]);
|
||||
mHeaderLength += sizeof(uint16_t);
|
||||
offset += sizeof(uint16_t);
|
||||
length -= sizeof(uint16_t);
|
||||
@@ -141,13 +143,13 @@ ThreadError Header::FromMessage(const Message &aMessage)
|
||||
{
|
||||
mOption.mNumber = optionDelta;
|
||||
mOption.mLength = optionLength;
|
||||
mOption.mValue = mHeader + mHeaderLength;
|
||||
mOption.mValue = mHeader.mBytes + mHeaderLength;
|
||||
mNextOptionOffset = mHeaderLength + optionLength;
|
||||
firstOption = false;
|
||||
}
|
||||
|
||||
VerifyOrExit(optionLength <= length, error = kThreadError_Parse);
|
||||
aMessage.Read(offset, optionLength, mHeader + mHeaderLength);
|
||||
aMessage.Read(offset, optionLength, mHeader.mBytes + mHeaderLength);
|
||||
mHeaderLength += static_cast<uint8_t>(optionLength);
|
||||
offset += optionLength;
|
||||
length -= optionLength;
|
||||
@@ -159,11 +161,24 @@ exit:
|
||||
|
||||
ThreadError Header::AppendOption(const Option &aOption)
|
||||
{
|
||||
uint8_t *buf = mHeader + mHeaderLength;
|
||||
ThreadError error = kThreadError_None;
|
||||
uint8_t *buf = mHeader.mBytes + mHeaderLength;
|
||||
uint8_t *cur = buf + 1;
|
||||
uint16_t optionDelta = aOption.mNumber - mOptionLast;
|
||||
uint16_t optionLength;
|
||||
|
||||
// Assure that no option is inserted out of order.
|
||||
VerifyOrExit(aOption.mNumber >= mOptionLast, error = kThreadError_InvalidArgs);
|
||||
|
||||
// Calculate the total option size and check the buffers.
|
||||
optionLength = 1 + aOption.mLength;
|
||||
optionLength += optionDelta < kOption1ByteExtensionOffset ? 0 :
|
||||
(optionDelta < kOption2ByteExtensionOffset ? 1 : 2);
|
||||
optionLength += aOption.mLength < kOption1ByteExtensionOffset ? 0 :
|
||||
(aOption.mLength < kOption2ByteExtensionOffset ? 1 : 2);
|
||||
VerifyOrExit(mHeaderLength + optionLength < kMaxHeaderLength, error = kThreadError_NoBufs);
|
||||
|
||||
// Insert option delta.
|
||||
if (optionDelta < kOption1ByteExtensionOffset)
|
||||
{
|
||||
*buf = (optionDelta << Option::kOptionDeltaOffset) & Option::kOptionDeltaMask;
|
||||
@@ -181,6 +196,7 @@ ThreadError Header::AppendOption(const Option &aOption)
|
||||
*cur++ = optionDelta & 0xff;
|
||||
}
|
||||
|
||||
// Insert option length.
|
||||
if (aOption.mLength < kOption1ByteExtensionOffset)
|
||||
{
|
||||
*buf |= aOption.mLength;
|
||||
@@ -198,17 +214,20 @@ ThreadError Header::AppendOption(const Option &aOption)
|
||||
*cur++ = optionLength & 0xff;
|
||||
}
|
||||
|
||||
// Insert option value.
|
||||
memcpy(cur, aOption.mValue, aOption.mLength);
|
||||
cur += aOption.mLength;
|
||||
|
||||
mHeaderLength += static_cast<uint8_t>(cur - buf);
|
||||
mOptionLast = aOption.mNumber;
|
||||
|
||||
return kThreadError_None;
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Header::AppendUriPathOptions(const char *aUriPath)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
const char *cur = aUriPath;
|
||||
const char *end;
|
||||
Header::Option coapOption;
|
||||
@@ -219,15 +238,16 @@ ThreadError Header::AppendUriPathOptions(const char *aUriPath)
|
||||
{
|
||||
coapOption.mLength = static_cast<uint16_t>(end - cur);
|
||||
coapOption.mValue = reinterpret_cast<const uint8_t *>(cur);
|
||||
AppendOption(coapOption);
|
||||
SuccessOrExit(error = AppendOption(coapOption));
|
||||
cur = end + 1;
|
||||
}
|
||||
|
||||
coapOption.mLength = static_cast<uint16_t>(strlen(cur));
|
||||
coapOption.mValue = reinterpret_cast<const uint8_t *>(cur);
|
||||
AppendOption(coapOption);
|
||||
SuccessOrExit(error = AppendOption(coapOption));
|
||||
|
||||
return kThreadError_None;
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Header::AppendContentFormatOption(MediaType aType)
|
||||
@@ -238,14 +258,13 @@ ThreadError Header::AppendContentFormatOption(MediaType aType)
|
||||
coapOption.mNumber = Option::kOptionContentFormat;
|
||||
coapOption.mLength = 1;
|
||||
coapOption.mValue = &type;
|
||||
AppendOption(coapOption);
|
||||
|
||||
return kThreadError_None;
|
||||
return AppendOption(coapOption);
|
||||
}
|
||||
|
||||
const Header::Option *Header::GetCurrentOption(void) const
|
||||
{
|
||||
return &mOption;
|
||||
return static_cast<const Header::Option *>(&mOption);
|
||||
}
|
||||
|
||||
const Header::Option *Header::GetNextOption(void)
|
||||
@@ -256,8 +275,8 @@ const Header::Option *Header::GetNextOption(void)
|
||||
|
||||
VerifyOrExit(mNextOptionOffset < mHeaderLength, ;);
|
||||
|
||||
optionDelta = mHeader[mNextOptionOffset] >> 4;
|
||||
optionLength = mHeader[mNextOptionOffset] & 0xf;
|
||||
optionDelta = mHeader.mBytes[mNextOptionOffset] >> 4;
|
||||
optionLength = mHeader.mBytes[mNextOptionOffset] & 0xf;
|
||||
mNextOptionOffset += sizeof(uint8_t);
|
||||
|
||||
if (optionDelta < kOption1ByteExtension)
|
||||
@@ -266,13 +285,13 @@ const Header::Option *Header::GetNextOption(void)
|
||||
}
|
||||
else if (optionDelta == kOption1ByteExtension)
|
||||
{
|
||||
optionDelta = kOption1ByteExtensionOffset + mHeader[mNextOptionOffset];
|
||||
optionDelta = kOption1ByteExtensionOffset + mHeader.mBytes[mNextOptionOffset];
|
||||
mNextOptionOffset += sizeof(uint8_t);
|
||||
}
|
||||
else if (optionDelta == kOption2ByteExtension)
|
||||
{
|
||||
optionDelta = kOption2ByteExtensionOffset +
|
||||
static_cast<uint16_t>((mHeader[mNextOptionOffset] << 8) | mHeader[mNextOptionOffset + 1]);
|
||||
static_cast<uint16_t>((mHeader.mBytes[mNextOptionOffset] << 8) | mHeader.mBytes[mNextOptionOffset + 1]);
|
||||
mNextOptionOffset += sizeof(uint16_t);
|
||||
}
|
||||
else
|
||||
@@ -286,13 +305,13 @@ const Header::Option *Header::GetNextOption(void)
|
||||
}
|
||||
else if (optionLength == kOption1ByteExtension)
|
||||
{
|
||||
optionLength = kOption1ByteExtensionOffset + mHeader[mNextOptionOffset];
|
||||
optionLength = kOption1ByteExtensionOffset + mHeader.mBytes[mNextOptionOffset];
|
||||
mNextOptionOffset += sizeof(uint8_t);
|
||||
}
|
||||
else if (optionLength == kOption2ByteExtension)
|
||||
{
|
||||
optionLength = kOption2ByteExtensionOffset +
|
||||
static_cast<uint16_t>((mHeader[mNextOptionOffset] << 8) | mHeader[mNextOptionOffset + 1]);
|
||||
static_cast<uint16_t>((mHeader.mBytes[mNextOptionOffset] << 8) | mHeader.mBytes[mNextOptionOffset + 1]);
|
||||
mNextOptionOffset += sizeof(uint16_t);
|
||||
}
|
||||
else
|
||||
@@ -302,13 +321,48 @@ const Header::Option *Header::GetNextOption(void)
|
||||
|
||||
mOption.mNumber += optionDelta;
|
||||
mOption.mLength = optionLength;
|
||||
mOption.mValue = mHeader + mNextOptionOffset;
|
||||
mOption.mValue = mHeader.mBytes + mNextOptionOffset;
|
||||
mNextOptionOffset += optionLength;
|
||||
rval = &mOption;
|
||||
rval = static_cast<Header::Option *>(&mOption);
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
}
|
||||
|
||||
ThreadError Header::Finalize(void)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
|
||||
VerifyOrExit(mHeaderLength < kMaxHeaderLength, error = kThreadError_NoBufs);
|
||||
mHeader.mBytes[mHeaderLength++] = 0xff;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Header::SetToken(uint8_t aTokenLength)
|
||||
{
|
||||
assert(aTokenLength <= kMaxTokenLength);
|
||||
|
||||
uint8_t token[kMaxTokenLength] = { 0 };
|
||||
|
||||
for (uint8_t i = 0; i < aTokenLength; i++)
|
||||
{
|
||||
token[i] = static_cast<uint8_t>(otPlatRandomGet());
|
||||
}
|
||||
|
||||
SetToken(token, aTokenLength);
|
||||
}
|
||||
|
||||
void Header::SetDefaultResponseHeader(const Header &aRequestHeader)
|
||||
{
|
||||
Init();
|
||||
SetType(kTypeAcknowledgment);
|
||||
SetCode(kCodeChanged);
|
||||
SetMessageId(aRequestHeader.GetMessageId());
|
||||
SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
|
||||
Finalize();
|
||||
}
|
||||
|
||||
} // namespace Coap
|
||||
} // namespace Thread
|
||||
|
||||
+133
-42
@@ -36,6 +36,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread-types.h>
|
||||
#include <openthread-coap.h>
|
||||
#include <common/encoding.hpp>
|
||||
#include <common/message.hpp>
|
||||
|
||||
@@ -65,12 +67,15 @@ namespace Coap {
|
||||
* This class implements CoAP header generation and parsing.
|
||||
*
|
||||
*/
|
||||
class Header
|
||||
class Header : public otCoapHeader
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kVersion1 = 1, ///< Version 1
|
||||
kVersion1 = 1, ///< Version 1
|
||||
kMinHeaderLength = 4, ///< Minimum header length
|
||||
kMaxHeaderLength = OT_COAP_HEADER_MAX_LENGTH, ///< Maximum header length
|
||||
kDefaultTokenLength = 2 ///< Default token length
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -96,7 +101,7 @@ public:
|
||||
* @returns The Version value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetVersion(void) const { return (mHeader[0] & kVersionMask) >> kVersionOffset; }
|
||||
uint8_t GetVersion(void) const { return (mHeader.mFields.mVersionTypeToken & kVersionMask) >> kVersionOffset; }
|
||||
|
||||
/**
|
||||
* This method sets the Version value.
|
||||
@@ -104,7 +109,10 @@ public:
|
||||
* @param[in] aVersion The Version value.
|
||||
*
|
||||
*/
|
||||
void SetVersion(uint8_t aVersion) { mHeader[0] &= ~kVersionMask; mHeader[0] |= aVersion << kVersionOffset; }
|
||||
void SetVersion(uint8_t aVersion) {
|
||||
mHeader.mFields.mVersionTypeToken &= ~kVersionMask;
|
||||
mHeader.mFields.mVersionTypeToken |= aVersion << kVersionOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* CoAP Type values.
|
||||
@@ -124,7 +132,7 @@ public:
|
||||
* @returns The Type value.
|
||||
*
|
||||
*/
|
||||
Type GetType(void) const { return static_cast<Header::Type>(mHeader[0] & kTypeMask); }
|
||||
Type GetType(void) const { return static_cast<Header::Type>(mHeader.mFields.mVersionTypeToken & kTypeMask); }
|
||||
|
||||
/**
|
||||
* This method sets the Type value.
|
||||
@@ -132,7 +140,11 @@ public:
|
||||
* @param[in] aType The Type value.
|
||||
*
|
||||
*/
|
||||
void SetType(Type aType) { mHeader[0] &= ~kTypeMask; mHeader[0] |= aType; }
|
||||
void SetType(Type aType) {
|
||||
mHeader.mFields.mVersionTypeToken &= ~kTypeMask;
|
||||
mHeader.mFields.mVersionTypeToken |= aType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CoAP Code values.
|
||||
@@ -154,7 +166,7 @@ public:
|
||||
* @returns The Code value.
|
||||
*
|
||||
*/
|
||||
Code GetCode(void) const { return static_cast<Code>(mCode); }
|
||||
Code GetCode(void) const { return static_cast<Code>(mHeader.mFields.mCode); }
|
||||
|
||||
/**
|
||||
* This method sets the Code value.
|
||||
@@ -162,7 +174,7 @@ public:
|
||||
* @param[in] aCode The Code value.
|
||||
*
|
||||
*/
|
||||
void SetCode(Code aCode) { mCode = static_cast<uint8_t>(aCode); }
|
||||
void SetCode(Code aCode) { mHeader.mFields.mCode = static_cast<uint8_t>(aCode); }
|
||||
|
||||
/**
|
||||
* This method returns the Message ID value.
|
||||
@@ -170,7 +182,7 @@ public:
|
||||
* @returns The Message ID value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetMessageId(void) const { return HostSwap16(mMessageId); }
|
||||
uint16_t GetMessageId(void) const { return HostSwap16(mHeader.mFields.mMessageId); }
|
||||
|
||||
/**
|
||||
* This method sets the Message ID value.
|
||||
@@ -178,7 +190,7 @@ public:
|
||||
* @param[in] aMessageId The Message ID value.
|
||||
*
|
||||
*/
|
||||
void SetMessageId(uint16_t aMessageId) { mMessageId = HostSwap16(aMessageId); }
|
||||
void SetMessageId(uint16_t aMessageId) { mHeader.mFields.mMessageId = HostSwap16(aMessageId); }
|
||||
|
||||
/**
|
||||
* This method returns the Token length.
|
||||
@@ -186,7 +198,7 @@ public:
|
||||
* @returns The Token length.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTokenLength(void) const { return (mHeader[0] & kTokenLengthMask) >> kTokenLengthOffset; }
|
||||
uint8_t GetTokenLength(void) const { return (mHeader.mFields.mVersionTypeToken & kTokenLengthMask) >> kTokenLengthOffset; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the Token value.
|
||||
@@ -194,7 +206,7 @@ public:
|
||||
* @returns A pointer to the Token value.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetToken(void) const { return mHeader + kTokenOffset; }
|
||||
const uint8_t *GetToken(void) const { return mHeader.mBytes + kTokenOffset; }
|
||||
|
||||
/**
|
||||
* This method sets the Token value and length.
|
||||
@@ -204,16 +216,39 @@ public:
|
||||
*
|
||||
*/
|
||||
void SetToken(const uint8_t *aToken, uint8_t aTokenLength) {
|
||||
mHeader[0] = (mHeader[0] & ~kTokenLengthMask) | ((aTokenLength << kTokenLengthOffset) & kTokenLengthMask);
|
||||
memcpy(mHeader + kTokenOffset, aToken, aTokenLength);
|
||||
mHeader.mFields.mVersionTypeToken = (mHeader.mFields.mVersionTypeToken & ~kTokenLengthMask) |
|
||||
((aTokenLength << kTokenLengthOffset) & kTokenLengthMask);
|
||||
memcpy(mHeader.mBytes + kTokenOffset, aToken, aTokenLength);
|
||||
mHeaderLength += aTokenLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the Token length and randomizes its value.
|
||||
*
|
||||
* @param[in] aTokenLength The Length of a Token to set.
|
||||
*
|
||||
*/
|
||||
void SetToken(uint8_t aTokenLength);
|
||||
|
||||
/**
|
||||
* This method checks if Tokens in two CoAP headers are equal.
|
||||
*
|
||||
* @param[in] aHeader A header to compare.
|
||||
*
|
||||
* @retval TRUE If two Tokens are equal.
|
||||
* @retval FALSE If Tokens differ in length or value.
|
||||
*
|
||||
*/
|
||||
bool IsTokenEqual(const Header &aHeader) const {
|
||||
return ((this->GetTokenLength() == aHeader.GetTokenLength()) &&
|
||||
(memcmp(this->GetToken(), aHeader.GetToken(), this->GetTokenLength()) == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* This structure represents a CoAP option.
|
||||
*
|
||||
*/
|
||||
struct Option
|
||||
struct Option : public otCoapOption
|
||||
{
|
||||
/**
|
||||
* Protocol Constants
|
||||
@@ -233,10 +268,6 @@ public:
|
||||
kOptionUriPath = 11, ///< Uri-Path
|
||||
kOptionContentFormat = 12, ///< Content-Format
|
||||
};
|
||||
|
||||
uint16_t mNumber; ///< Option Number
|
||||
uint16_t mLength; ///< Option Length
|
||||
const uint8_t *mValue; ///< A pointer to the Option Value
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -246,6 +277,7 @@ public:
|
||||
*
|
||||
* @retval kThreadError_None Successfully appended the option.
|
||||
* @retval kThreadError_InvalidArgs The option type is not equal or greater than the last option type.
|
||||
* @retval kThreadError_NoBufs The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
ThreadError AppendOption(const Option &aOption);
|
||||
@@ -257,6 +289,7 @@ public:
|
||||
*
|
||||
* @retval kThreadError_None Successfully appended the option.
|
||||
* @retval kThreadError_InvalidArgs The option type is not equal or greater than the last option type.
|
||||
* @retval kThreadError_NoBufs The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
ThreadError AppendUriPathOptions(const char *aUriPath);
|
||||
@@ -277,6 +310,7 @@ public:
|
||||
*
|
||||
* @retval kThreadError_None Successfully appended the option.
|
||||
* @retval kThreadError_InvalidArgs The option type is not equal or greater than the last option type.
|
||||
* @retval kThreadError_NoBufs The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
ThreadError AppendContentFormatOption(MediaType aType);
|
||||
@@ -300,8 +334,11 @@ public:
|
||||
/**
|
||||
* This method terminates the CoAP header.
|
||||
*
|
||||
* @retval kThreadError_None Header successfully terminated.
|
||||
* @retval kThreadError_NoBufs Header Payload Marker exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
void Finalize(void) { mHeader[mHeaderLength++] = 0xff; }
|
||||
ThreadError Finalize(void);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the first byte of the header.
|
||||
@@ -309,7 +346,7 @@ public:
|
||||
* @returns A pointer to the first byte of the header.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return mHeader; }
|
||||
const uint8_t *GetBytes(void) const { return mHeader.mBytes; }
|
||||
|
||||
/**
|
||||
* This method returns the header length in bytes.
|
||||
@@ -319,6 +356,77 @@ public:
|
||||
*/
|
||||
uint8_t GetLength(void) const { return mHeaderLength; }
|
||||
|
||||
/**
|
||||
* This method sets a default response header based on request header.
|
||||
*
|
||||
* @param[in] aRequestHeader Request header to base on.
|
||||
*
|
||||
*/
|
||||
void SetDefaultResponseHeader(const Header &aRequestHeader);
|
||||
|
||||
/**
|
||||
* This method checks if a header is an empty message header.
|
||||
*
|
||||
* @retval TRUE Header is an empty message header.
|
||||
* @retval FALSE Header is not an empty message header.
|
||||
*
|
||||
*/
|
||||
bool IsEmpty(void) const { return (GetCode() == 0); };
|
||||
|
||||
/**
|
||||
* This method checks if a header is a request header.
|
||||
*
|
||||
* @retval TRUE Header is a request header.
|
||||
* @retval FALSE Header is not a request header.
|
||||
*
|
||||
*/
|
||||
bool IsRequest(void) const { return (GetCode() >= kCodeGet && GetCode() <= kCodeDelete); };
|
||||
|
||||
/**
|
||||
* This method checks if a header is a response header.
|
||||
*
|
||||
* @retval TRUE Header is a response header.
|
||||
* @retval FALSE Header is not a response header.
|
||||
*
|
||||
*/
|
||||
bool IsResponse(void) const { return (GetCode() >= kCodeChanged); };
|
||||
|
||||
/**
|
||||
* This method checks if a header is a CON message header.
|
||||
*
|
||||
* @retval TRUE Header is a CON message header.
|
||||
* @retval FALSE Header is not is a CON message header.
|
||||
*
|
||||
*/
|
||||
bool IsConfirmable(void) const { return (GetType() == kTypeConfirmable); };
|
||||
|
||||
/**
|
||||
* This method checks if a header is a NON message header.
|
||||
*
|
||||
* @retval TRUE Header is a NON message header.
|
||||
* @retval FALSE Header is not is a NON message header.
|
||||
*
|
||||
*/
|
||||
bool IsNonConfirmable(void) const { return (GetType() == kTypeNonConfirmable); };
|
||||
|
||||
/**
|
||||
* This method checks if a header is a ACK message header.
|
||||
*
|
||||
* @retval TRUE Header is a ACK message header.
|
||||
* @retval FALSE Header is not is a ACK message header.
|
||||
*
|
||||
*/
|
||||
bool IsAck(void) const { return (GetType() == kTypeAcknowledgment); };
|
||||
|
||||
/**
|
||||
* This method checks if a header is a RST message header.
|
||||
*
|
||||
* @retval TRUE Header is a RST message header.
|
||||
* @retval FALSE Header is not is a RST message header.
|
||||
*
|
||||
*/
|
||||
bool IsReset(void) const { return (GetType() == kTypeReset); };
|
||||
|
||||
private:
|
||||
/**
|
||||
* Protocol Constants (RFC 7252).
|
||||
@@ -329,38 +437,21 @@ private:
|
||||
kVersionMask = 0xc0, ///< Version mask as specified (RFC 7252).
|
||||
kVersionOffset = 6, ///< Version offset as specified (RFC 7252).
|
||||
|
||||
kTypeMask = 0x30, ///< Type mask as specified (RFC 7252).
|
||||
|
||||
kTokenLengthMask = 0x0f, ///< Token Length mask as specified (RFC 7252).
|
||||
kTokenLengthOffset = 0, ///< Token Length offset as specified (RFC 7252).
|
||||
kTokenOffset = 4, ///< Token offset as specified (RFC 7252).
|
||||
kMaxTokenLength = 8, ///< Max token length as specified (RFC 7252).
|
||||
|
||||
kMaxOptionHeaderSize = 5, ///< Maximum size of an Option header
|
||||
|
||||
kOption1ByteExtension = 13, ///< Indicates a 1 byte extension (RFC 7252).
|
||||
kOption2ByteExtension = 14, ///< Indicates a 1 byte extension (RFC 7252).
|
||||
|
||||
kOption1ByteExtensionOffset = 13, ///< Delta/Length offset as specified (RFC 7252).
|
||||
kOption2ByteExtensionOffset = 269, ///< Delta/Length offset as specified (RFC 7252).
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kTypeMask = 0x30,
|
||||
kMinHeaderLength = 4,
|
||||
kMaxHeaderLength = 128,
|
||||
};
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t mVersionTypeToken;
|
||||
uint8_t mCode;
|
||||
uint16_t mMessageId;
|
||||
};
|
||||
uint8_t mHeader[kMaxHeaderLength];
|
||||
};
|
||||
uint8_t mHeaderLength;
|
||||
uint16_t mOptionLast;
|
||||
uint16_t mNextOptionOffset;
|
||||
Option mOption;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS
|
||||
#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 40
|
||||
#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 40
|
||||
#endif // OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE
|
||||
#define OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE 128
|
||||
#define OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE 128
|
||||
#endif // OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE
|
||||
|
||||
/**
|
||||
@@ -62,7 +62,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DEFAULT_CHANNEL
|
||||
#define OPENTHREAD_CONFIG_DEFAULT_CHANNEL 11
|
||||
#define OPENTHREAD_CONFIG_DEFAULT_CHANNEL 11
|
||||
#endif // OPENTHREAD_CONFIG_DEFAULT_CHANNEL
|
||||
|
||||
/**
|
||||
@@ -72,7 +72,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DEFAULT_MAX_TRANSMIT_POWER
|
||||
#define OPENTHREAD_CONFIG_DEFAULT_MAX_TRANSMIT_POWER 0
|
||||
#define OPENTHREAD_CONFIG_DEFAULT_MAX_TRANSMIT_POWER 0
|
||||
#endif // OPENTHREAD_CONFIG_DEFAULT_MAX_TRANSMIT_POWER
|
||||
|
||||
/**
|
||||
@@ -82,7 +82,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_ATTACH_DATA_POLL_PERIOD
|
||||
#define OPENTHREAD_CONFIG_ATTACH_DATA_POLL_PERIOD 100
|
||||
#define OPENTHREAD_CONFIG_ATTACH_DATA_POLL_PERIOD 100
|
||||
#endif // OPENTHREAD_CONFIG_ATTACH_DATA_POLL_PERIOD
|
||||
|
||||
/**
|
||||
@@ -92,7 +92,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_ADDRESS_CACHE_ENTRIES
|
||||
#define OPENTHREAD_CONFIG_ADDRESS_CACHE_ENTRIES 10
|
||||
#define OPENTHREAD_CONFIG_ADDRESS_CACHE_ENTRIES 10
|
||||
#endif // OPENTHREAD_CONFIG_ADDRESS_CACHE_ENTRIES
|
||||
|
||||
/**
|
||||
@@ -102,7 +102,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAX_CHILDREN
|
||||
#define OPENTHREAD_CONFIG_MAX_CHILDREN 10
|
||||
#define OPENTHREAD_CONFIG_MAX_CHILDREN 10
|
||||
#endif // OPENTHREAD_CONFIG_MAX_CHILDREN
|
||||
|
||||
/**
|
||||
@@ -112,7 +112,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_IP_ADDRS_PER_CHILD
|
||||
#define OPENTHREAD_CONFIG_IP_ADDRS_PER_CHILD 4
|
||||
#define OPENTHREAD_CONFIG_IP_ADDRS_PER_CHILD 4
|
||||
#endif // OPENTHREAD_CONFIG_IP_ADDRS_PER_CHILD
|
||||
|
||||
/**
|
||||
@@ -122,7 +122,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS
|
||||
#define OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS 4
|
||||
#define OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS 4
|
||||
#endif // OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS
|
||||
|
||||
/**
|
||||
@@ -132,7 +132,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT 5
|
||||
#define OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT 5
|
||||
#endif // OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT
|
||||
|
||||
/**
|
||||
@@ -142,7 +142,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES
|
||||
#define OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES 32
|
||||
#define OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES 32
|
||||
#endif // OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES
|
||||
|
||||
/**
|
||||
@@ -152,7 +152,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME
|
||||
#define OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME 5
|
||||
#define OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME 5
|
||||
#endif // OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME
|
||||
|
||||
/**
|
||||
@@ -162,7 +162,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_JOINER_UDP_PORT
|
||||
#define OPENTHREAD_CONFIG_JOINER_UDP_PORT 1000
|
||||
#define OPENTHREAD_CONFIG_JOINER_UDP_PORT 1000
|
||||
#endif // OPENTHREAD_CONFIG_JOINER_UDP_PORT
|
||||
|
||||
/**
|
||||
@@ -172,7 +172,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS
|
||||
#define OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS 64
|
||||
#define OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS 64
|
||||
#endif // OPENTHREAD_CONFIG_MAX_ENERGY_RESULTS
|
||||
|
||||
/**
|
||||
@@ -182,7 +182,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAX_JOINER_ENTRIES
|
||||
#define OPENTHREAD_CONFIG_MAX_JOINER_ENTRIES 2
|
||||
#define OPENTHREAD_CONFIG_MAX_JOINER_ENTRIES 2
|
||||
#endif // OPENTHREAD_CONFIG_MAX_JOINER_ENTRIES
|
||||
|
||||
/**
|
||||
@@ -192,9 +192,50 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS
|
||||
#define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 1
|
||||
#define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 1
|
||||
#endif // OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT
|
||||
*
|
||||
* Minimum spacing before first retransmission when ACK is not received (RFC7252 default value is 2).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT 2
|
||||
#endif // OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR
|
||||
*
|
||||
* Numerator of ACK_RANDOM_FACTOR used to calculate maximum spacing before first retransmission when
|
||||
* ACK is not received (RFC7252 default value of ACK_RANDOM_FACTOR is 1.5, must not be decreased below 1).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR
|
||||
#define OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR 3
|
||||
#endif // OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR
|
||||
*
|
||||
* Denominator of ACK_RANDOM_FACTOR used to calculate maximum spacing before first retransmission when
|
||||
* ACK is not received (RFC7252 default value of ACK_RANDOM_FACTOR is 1.5, must not be decreased below 1).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR
|
||||
#define OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR 2
|
||||
#endif // OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT
|
||||
*
|
||||
* Maximum number of retransmissions for CoAP Confirmable messages (RFC7252 default value is 4).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT
|
||||
#define OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT 4
|
||||
#endif // OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_LOG_LEVEL
|
||||
@@ -203,7 +244,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_LOG_LEVEL
|
||||
#define OPENTHREAD_CONFIG_LOG_LEVEL OPENTHREAD_LOG_LEVEL_CRIT
|
||||
#define OPENTHREAD_CONFIG_LOG_LEVEL OPENTHREAD_LOG_LEVEL_CRIT
|
||||
#endif // OPENTHREAD_CONFIG_LOG_LEVEL
|
||||
|
||||
/**
|
||||
@@ -270,7 +311,6 @@
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_LOG_MEM
|
||||
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_LOG_NETDIAG
|
||||
*
|
||||
@@ -286,7 +326,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SETTINGS_BASE_ADDRESS
|
||||
#define OPENTHREAD_CONFIG_SETTINGS_BASE_ADDRESS 0x39000
|
||||
#define OPENTHREAD_CONFIG_SETTINGS_BASE_ADDRESS 0x39000
|
||||
#endif // OPENTHREAD_CONFIG_SETTINGS_BASE_ADDRESS
|
||||
|
||||
/**
|
||||
@@ -296,7 +336,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SETTINGS_PAGE_SIZE
|
||||
#define OPENTHREAD_CONFIG_SETTINGS_PAGE_SIZE 0x800
|
||||
#define OPENTHREAD_CONFIG_SETTINGS_PAGE_SIZE 0x800
|
||||
#endif // OPENTHREAD_CONFIG_SETTINGS_PAGE_SIZE
|
||||
|
||||
/**
|
||||
@@ -306,7 +346,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SETTINGS_PAGE_NUM
|
||||
#define OPENTHREAD_CONFIG_SETTINGS_PAGE_NUM 2
|
||||
#define OPENTHREAD_CONFIG_SETTINGS_PAGE_NUM 2
|
||||
#endif // OPENTHREAD_CONFIG_SETTINGS_PAGE_NUM
|
||||
|
||||
#endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
#include <thread/thread_uris.hpp>
|
||||
#include <utils/global_address.hpp>
|
||||
#include <openthread-instance.h>
|
||||
#include <coap/coap_header.hpp>
|
||||
#include <coap/coap_client.hpp>
|
||||
|
||||
#ifndef OPENTHREAD_MULTIPLE_INSTANCE
|
||||
static otDEFINE_ALIGNED_VAR(sInstanceRaw, sizeof(otInstance), uint64_t);
|
||||
@@ -1518,6 +1520,53 @@ ThreadError otJoinerStop(otInstance *aInstance)
|
||||
}
|
||||
#endif // OPENTHREAD_ENABLE_JOINER
|
||||
|
||||
void otCoapHeaderInit(otCoapHeader *aHeader, otCoapType aType, otCoapCode aCode)
|
||||
{
|
||||
Coap::Header *header = static_cast<Coap::Header *>(aHeader);
|
||||
header->Init();
|
||||
header->SetType(static_cast<Coap::Header::Type>(aType));
|
||||
header->SetCode(static_cast<Coap::Header::Code>(aCode));
|
||||
}
|
||||
|
||||
void otCoapHeaderSetToken(otCoapHeader *aHeader, const uint8_t *aToken, uint8_t aTokenLength)
|
||||
{
|
||||
static_cast<Coap::Header *>(aHeader)->SetToken(aToken, aTokenLength);
|
||||
}
|
||||
|
||||
ThreadError otCoapHeaderAppendOption(otCoapHeader *aHeader, const otCoapOption *aOption)
|
||||
{
|
||||
return static_cast<Coap::Header *>(aHeader)->AppendOption(*static_cast<const Coap::Header::Option *>(aOption));
|
||||
}
|
||||
|
||||
void otCoapHeaderSetPayloadMarker(otCoapHeader *aHeader)
|
||||
{
|
||||
static_cast<Coap::Header *>(aHeader)->Finalize();
|
||||
}
|
||||
|
||||
const otCoapOption *otCoapGetCurrentOption(const otCoapHeader *aHeader)
|
||||
{
|
||||
return static_cast<const otCoapOption *>(static_cast<const Coap::Header *>(aHeader)->GetCurrentOption());
|
||||
}
|
||||
|
||||
const otCoapOption *otCoapGetNextOption(otCoapHeader *aHeader)
|
||||
{
|
||||
return static_cast<const otCoapOption *>(static_cast<Coap::Header *>(aHeader)->GetNextOption());
|
||||
}
|
||||
|
||||
otMessage otNewCoapMessage(otInstance *aInstance, const otCoapHeader *aHeader)
|
||||
{
|
||||
return aInstance->mThreadNetif.GetCoapClient().NewMessage(*(static_cast<const Coap::Header *>(aHeader)));
|
||||
}
|
||||
|
||||
ThreadError otSendCoapMessage(otInstance *aInstance, otMessage aMessage, const otMessageInfo *aMessageInfo,
|
||||
otCoapResponseHandler aHandler, void *aContext)
|
||||
{
|
||||
return aInstance->mThreadNetif.GetCoapClient().SendMessage(
|
||||
*static_cast<Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo),
|
||||
aHandler, aContext);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
@@ -56,10 +56,10 @@ AddressResolver::AddressResolver(ThreadNetif &aThreadNetif) :
|
||||
mAddressQuery(OPENTHREAD_URI_ADDRESS_QUERY, &AddressResolver::HandleAddressQuery, this),
|
||||
mAddressNotification(OPENTHREAD_URI_ADDRESS_NOTIFY, &AddressResolver::HandleAddressNotification, this),
|
||||
mIcmpHandler(&AddressResolver::HandleDstUnreach, this),
|
||||
mSocket(aThreadNetif.GetIp6().mUdp),
|
||||
mTimer(aThreadNetif.GetIp6().mTimerScheduler, &AddressResolver::HandleTimer, this),
|
||||
mMeshForwarder(aThreadNetif.GetMeshForwarder()),
|
||||
mCoapServer(aThreadNetif.GetCoapServer()),
|
||||
mCoapClient(aThreadNetif.GetCoapClient()),
|
||||
mMle(aThreadNetif.GetMle()),
|
||||
mNetif(aThreadNetif)
|
||||
{
|
||||
@@ -68,7 +68,6 @@ AddressResolver::AddressResolver(ThreadNetif &aThreadNetif) :
|
||||
mCoapServer.AddResource(mAddressError);
|
||||
mCoapServer.AddResource(mAddressQuery);
|
||||
mCoapServer.AddResource(mAddressNotification);
|
||||
mCoapMessageId = static_cast<uint8_t>(otPlatRandomGet());
|
||||
|
||||
mNetif.GetIp6().mIcmp.RegisterCallbacks(mIcmpHandler);
|
||||
}
|
||||
@@ -168,26 +167,18 @@ exit:
|
||||
ThreadError AddressResolver::SendAddressQuery(const Ip6::Address &aEid)
|
||||
{
|
||||
ThreadError error;
|
||||
Ip6::SockAddr sockaddr;
|
||||
Message *message;
|
||||
Coap::Header header;
|
||||
ThreadTargetTlv targetTlv;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
|
||||
sockaddr.mPort = kCoapUdpPort;
|
||||
mSocket.Open(&AddressResolver::HandleUdpReceive, this);
|
||||
mSocket.Bind(sockaddr);
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
header.Init();
|
||||
header.SetType(Coap::Header::kTypeNonConfirmable);
|
||||
header.SetCode(Coap::Header::kCodePost);
|
||||
header.SetMessageId(++mCoapMessageId);
|
||||
header.SetToken(NULL, 0);
|
||||
header.AppendUriPathOptions(OPENTHREAD_URI_ADDRESS_QUERY);
|
||||
header.Finalize();
|
||||
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
|
||||
|
||||
VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
targetTlv.Init();
|
||||
targetTlv.SetTarget(aEid);
|
||||
@@ -200,7 +191,7 @@ ThreadError AddressResolver::SendAddressQuery(const Ip6::Address &aEid)
|
||||
messageInfo.mPeerPort = kCoapUdpPort;
|
||||
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
|
||||
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo, NULL, NULL));
|
||||
|
||||
otLogInfoArp("Sent address query\n");
|
||||
|
||||
@@ -219,13 +210,6 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void AddressResolver::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
(void)aContext;
|
||||
(void)aMessage;
|
||||
(void)aMessageInfo;
|
||||
}
|
||||
|
||||
void AddressResolver::HandleAddressNotification(void *aContext, Coap::Header &aHeader, Message &aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
@@ -318,12 +302,7 @@ void AddressResolver::SendAddressNotificationResponse(const Coap::Header &aReque
|
||||
|
||||
VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
responseHeader.Init();
|
||||
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
|
||||
responseHeader.SetCode(Coap::Header::kCodeChanged);
|
||||
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
|
||||
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
|
||||
responseHeader.Finalize();
|
||||
responseHeader.SetDefaultResponseHeader(aRequestHeader);
|
||||
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
|
||||
|
||||
memcpy(&responseInfo, &aRequestInfo, sizeof(responseInfo));
|
||||
@@ -347,22 +326,15 @@ ThreadError AddressResolver::SendAddressError(const ThreadTargetTlv &aTarget, co
|
||||
Message *message;
|
||||
Coap::Header header;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
Ip6::SockAddr sockaddr;
|
||||
|
||||
sockaddr.mPort = kCoapUdpPort;
|
||||
mSocket.Open(&AddressResolver::HandleUdpReceive, this);
|
||||
mSocket.Bind(sockaddr);
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
header.Init();
|
||||
header.SetType(Coap::Header::kTypeConfirmable);
|
||||
header.SetType(aDestination == NULL ? Coap::Header::kTypeNonConfirmable : Coap::Header::kTypeConfirmable);
|
||||
header.SetCode(Coap::Header::kCodePost);
|
||||
header.SetMessageId(++mCoapMessageId);
|
||||
header.SetToken(NULL, 0);
|
||||
header.AppendUriPathOptions(OPENTHREAD_URI_ADDRESS_ERROR);
|
||||
header.Finalize();
|
||||
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
|
||||
|
||||
VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
SuccessOrExit(error = message->Append(&aTarget, sizeof(aTarget)));
|
||||
SuccessOrExit(error = message->Append(&aEid, sizeof(aEid)));
|
||||
|
||||
@@ -381,7 +353,7 @@ ThreadError AddressResolver::SendAddressError(const ThreadTargetTlv &aTarget, co
|
||||
messageInfo.mPeerPort = kCoapUdpPort;
|
||||
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
|
||||
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo, NULL, NULL));
|
||||
|
||||
otLogInfoArp("Sent address error\n");
|
||||
|
||||
@@ -405,12 +377,8 @@ void AddressResolver::SendAddressErrorResponse(const Coap::Header &aRequestHeade
|
||||
|
||||
VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
responseHeader.Init();
|
||||
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
|
||||
responseHeader.SetCode(Coap::Header::kCodeChanged);
|
||||
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
|
||||
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
|
||||
responseHeader.Finalize();
|
||||
responseHeader.SetDefaultResponseHeader(aRequestHeader);
|
||||
|
||||
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
|
||||
|
||||
memcpy(&responseInfo, &aRequestInfo, sizeof(responseInfo));
|
||||
@@ -581,16 +549,13 @@ void AddressResolver::SendAddressQueryResponse(const ThreadTargetTlv &aTargetTlv
|
||||
ThreadRloc16Tlv rloc16Tlv;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
header.Init();
|
||||
header.SetType(Coap::Header::kTypeConfirmable);
|
||||
header.SetCode(Coap::Header::kCodePost);
|
||||
header.SetMessageId(++mCoapMessageId);
|
||||
header.SetToken(NULL, 0);
|
||||
header.AppendUriPathOptions(OPENTHREAD_URI_ADDRESS_NOTIFY);
|
||||
header.Finalize();
|
||||
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
|
||||
|
||||
VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
SuccessOrExit(error = message->Append(&aTargetTlv, sizeof(aTargetTlv)));
|
||||
SuccessOrExit(error = message->Append(&aMlIidTlv, sizeof(aMlIidTlv)));
|
||||
@@ -609,7 +574,7 @@ void AddressResolver::SendAddressQueryResponse(const ThreadTargetTlv &aTargetTlv
|
||||
messageInfo.GetSockAddr() = *mMle.GetMeshLocal16();
|
||||
messageInfo.mPeerPort = kCoapUdpPort;
|
||||
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo, NULL, NULL));
|
||||
|
||||
otLogInfoArp("Sent address notification\n");
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <openthread-core-config.h>
|
||||
#include <openthread-types.h>
|
||||
#include <coap/coap_client.hpp>
|
||||
#include <coap/coap_server.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <mac/mac.hpp>
|
||||
@@ -181,13 +182,12 @@ private:
|
||||
Coap::Resource mAddressQuery;
|
||||
Coap::Resource mAddressNotification;
|
||||
Cache mCache[kCacheEntries];
|
||||
uint16_t mCoapMessageId;
|
||||
Ip6::IcmpHandler mIcmpHandler;
|
||||
Ip6::UdpSocket mSocket;
|
||||
Timer mTimer;
|
||||
|
||||
MeshForwarder &mMeshForwarder;
|
||||
Coap::Server &mCoapServer;
|
||||
Coap::Client &mCoapClient;
|
||||
Mle::MleRouter &mMle;
|
||||
Ip6::Netif &mNetif;
|
||||
};
|
||||
|
||||
@@ -1105,6 +1105,14 @@ protected:
|
||||
*/
|
||||
ThreadError SetStateChild(uint16_t aRloc16);
|
||||
|
||||
/**
|
||||
* This method returns a new MLE message.
|
||||
*
|
||||
* @returns A pointer to the message or NULL if no buffers are available.
|
||||
*
|
||||
*/
|
||||
Message *NewMessage(void) { return mSocket.NewMessage(0); };
|
||||
|
||||
/**
|
||||
* This method sets the Leader's Partition ID, Weighting, and Router ID values.
|
||||
*
|
||||
|
||||
@@ -55,10 +55,10 @@ MleRouter::MleRouter(ThreadNetif &aThreadNetif):
|
||||
mAdvertiseTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleAdvertiseTimer, NULL, this),
|
||||
mStateUpdateTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleStateUpdateTimer, this),
|
||||
mDelayedResponseTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleDelayedResponseTimer, this),
|
||||
mSocket(aThreadNetif.GetIp6().mUdp),
|
||||
mAddressSolicit(OPENTHREAD_URI_ADDRESS_SOLICIT, &MleRouter::HandleAddressSolicit, this),
|
||||
mAddressRelease(OPENTHREAD_URI_ADDRESS_RELEASE, &MleRouter::HandleAddressRelease, this),
|
||||
mCoapServer(aThreadNetif.GetCoapServer())
|
||||
mCoapServer(aThreadNetif.GetCoapServer()),
|
||||
mCoapClient(aThreadNetif.GetCoapClient())
|
||||
{
|
||||
mChallengeTimeout = 0;
|
||||
mNextChildId = kMaxChildId;
|
||||
@@ -76,8 +76,6 @@ MleRouter::MleRouter(ThreadNetif &aThreadNetif):
|
||||
mPreviousRouterId = kInvalidRouterId;
|
||||
mRouterIdSequenceLastUpdated = 0;
|
||||
mRouterRoleEnabled = true;
|
||||
|
||||
mCoapMessageId = static_cast<uint8_t>(otPlatRandomGet());
|
||||
}
|
||||
|
||||
bool MleRouter::IsRouterRoleEnabled(void) const
|
||||
@@ -210,7 +208,6 @@ ThreadError MleRouter::BecomeRouter(ThreadStatusTlv::Status aStatus)
|
||||
mRouters[i].mNextHop = kInvalidRouterId;
|
||||
}
|
||||
|
||||
mSocket.Open(&MleRouter::HandleUdpReceive, this);
|
||||
mAdvertiseTimer.Stop();
|
||||
mAddressResolver.Clear();
|
||||
|
||||
@@ -251,7 +248,6 @@ ThreadError MleRouter::BecomeLeader(void)
|
||||
mRouters[i].mNextHop = kInvalidRouterId;
|
||||
}
|
||||
|
||||
mSocket.Open(&MleRouter::HandleUdpReceive, this);
|
||||
mAdvertiseTimer.Stop();
|
||||
mStateUpdateTimer.Start(kStateUpdatePeriod);
|
||||
mAddressResolver.Clear();
|
||||
@@ -465,7 +461,7 @@ ThreadError MleRouter::SendAdvertisement(void)
|
||||
Ip6::Address destination;
|
||||
Message *message;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandAdvertisement));
|
||||
SuccessOrExit(error = AppendSourceAddress(*message));
|
||||
@@ -514,7 +510,7 @@ ThreadError MleRouter::SendLinkRequest(Neighbor *aNeighbor)
|
||||
|
||||
memset(&destination, 0, sizeof(destination));
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandLinkRequest));
|
||||
SuccessOrExit(error = AppendVersion(*message));
|
||||
@@ -690,7 +686,7 @@ ThreadError MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, Neig
|
||||
command = (aNeighbor == NULL || aNeighbor->mState == Neighbor::kStateValid) ?
|
||||
Header::kCommandLinkAccept : Header::kCommandLinkAcceptAndRequest;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, command));
|
||||
SuccessOrExit(error = AppendVersion(*message));
|
||||
@@ -982,7 +978,7 @@ ThreadError MleRouter::SendLinkReject(const Ip6::Address &aDestination)
|
||||
ThreadError error = kThreadError_None;
|
||||
Message *message;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandLinkReject));
|
||||
SuccessOrExit(error = AppendStatus(*message, StatusTlv::kError));
|
||||
@@ -1884,7 +1880,7 @@ ThreadError MleRouter::SendParentResponse(Child *aChild, const ChallengeTlv &cha
|
||||
Message *message;
|
||||
uint16_t delay;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandParentResponse));
|
||||
SuccessOrExit(error = AppendSourceAddress(*message));
|
||||
@@ -2306,7 +2302,7 @@ ThreadError MleRouter::SendChildIdResponse(Child *aChild)
|
||||
Ip6::Address destination;
|
||||
Message *message;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildIdResponse));
|
||||
SuccessOrExit(error = AppendSourceAddress(*message));
|
||||
@@ -2391,7 +2387,7 @@ ThreadError MleRouter::SendChildUpdateResponse(Child *aChild, const Ip6::Message
|
||||
ThreadError error = kThreadError_None;
|
||||
Message *message;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildUpdateResponse));
|
||||
|
||||
@@ -2454,7 +2450,7 @@ ThreadError MleRouter::SendDataResponse(const Ip6::Address &aDestination, const
|
||||
Neighbor *neighbor;
|
||||
bool stableOnly;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
|
||||
VerifyOrExit((message = NewMessage()) != NULL, ;);
|
||||
message->SetLinkSecurityEnabled(false);
|
||||
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDataResponse));
|
||||
SuccessOrExit(error = AppendSourceAddress(*message));
|
||||
@@ -3118,21 +3114,14 @@ ThreadError MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
|
||||
Ip6::MessageInfo messageInfo;
|
||||
Message *message;
|
||||
|
||||
for (size_t i = 0; i < sizeof(mCoapToken); i++)
|
||||
{
|
||||
mCoapToken[i] = static_cast<uint8_t>(otPlatRandomGet());
|
||||
}
|
||||
|
||||
header.Init();
|
||||
header.SetType(Coap::Header::kTypeConfirmable);
|
||||
header.SetCode(Coap::Header::kCodePost);
|
||||
header.SetMessageId(++mCoapMessageId);
|
||||
header.SetToken(mCoapToken, sizeof(mCoapToken));
|
||||
header.SetToken(Coap::Header::kDefaultTokenLength);
|
||||
header.AppendUriPathOptions(OPENTHREAD_URI_ADDRESS_SOLICIT);
|
||||
header.Finalize();
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
|
||||
VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
macAddr64Tlv.Init();
|
||||
macAddr64Tlv.SetMacAddr(*mMac.GetExtAddress());
|
||||
@@ -3152,11 +3141,19 @@ ThreadError MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
|
||||
memset(&messageInfo, 0, sizeof(messageInfo));
|
||||
SuccessOrExit(error = GetLeaderAddress(messageInfo.GetPeerAddr()));
|
||||
messageInfo.mPeerPort = kCoapUdpPort;
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
|
||||
SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo,
|
||||
&MleRouter::HandleAddressSolicitResponse, this));
|
||||
|
||||
otLogInfoMle("Sent address solicit to %04x\n", HostSwap16(messageInfo.GetPeerAddr().mFields.m16[7]));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -3169,21 +3166,14 @@ ThreadError MleRouter::SendAddressRelease(void)
|
||||
Ip6::MessageInfo messageInfo;
|
||||
Message *message;
|
||||
|
||||
for (size_t i = 0; i < sizeof(mCoapToken); i++)
|
||||
{
|
||||
mCoapToken[i] = static_cast<uint8_t>(otPlatRandomGet());
|
||||
}
|
||||
|
||||
header.Init();
|
||||
header.SetType(Coap::Header::kTypeConfirmable);
|
||||
header.SetCode(Coap::Header::kCodePost);
|
||||
header.SetMessageId(++mCoapMessageId);
|
||||
header.SetToken(mCoapToken, sizeof(mCoapToken));
|
||||
header.SetToken(Coap::Header::kDefaultTokenLength);
|
||||
header.AppendUriPathOptions(OPENTHREAD_URI_ADDRESS_RELEASE);
|
||||
header.Finalize();
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
|
||||
VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
rlocTlv.Init();
|
||||
rlocTlv.SetRloc16(GetRloc16(mRouterId));
|
||||
@@ -3196,54 +3186,51 @@ ThreadError MleRouter::SendAddressRelease(void)
|
||||
memset(&messageInfo, 0, sizeof(messageInfo));
|
||||
SuccessOrExit(error = GetLeaderAddress(messageInfo.GetPeerAddr()));
|
||||
messageInfo.mPeerPort = kCoapUdpPort;
|
||||
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
|
||||
SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo, NULL, NULL));
|
||||
|
||||
otLogInfoMle("Sent address release\n");
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && message != NULL)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void MleRouter::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
|
||||
void MleRouter::HandleAddressSolicitResponse(void *aContext, otCoapHeader *aHeader, otMessage aMessage,
|
||||
ThreadError result)
|
||||
{
|
||||
static_cast<MleRouter *>(aContext)->HandleUdpReceive(*static_cast<Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
|
||||
(void)aMessageInfo;
|
||||
static_cast<MleRouter *>(aContext)->HandleAddressSolicitResponse(static_cast<Coap::Header *>(aHeader),
|
||||
static_cast<Message *>(aMessage), result);
|
||||
}
|
||||
|
||||
void MleRouter::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
void MleRouter::HandleAddressSolicitResponse(Coap::Header *aHeader, Message *aMessage, ThreadError result)
|
||||
{
|
||||
(void)aMessageInfo;
|
||||
HandleAddressSolicitResponse(aMessage);
|
||||
}
|
||||
(void) result;
|
||||
|
||||
void MleRouter::HandleAddressSolicitResponse(Message &aMessage)
|
||||
{
|
||||
Coap::Header header;
|
||||
ThreadStatusTlv statusTlv;
|
||||
ThreadRloc16Tlv rlocTlv;
|
||||
ThreadRouterMaskTlv routerMaskTlv;
|
||||
uint8_t routerId;
|
||||
bool old;
|
||||
|
||||
SuccessOrExit(header.FromMessage(aMessage));
|
||||
VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment &&
|
||||
header.GetCode() == Coap::Header::kCodeChanged &&
|
||||
header.GetMessageId() == mCoapMessageId &&
|
||||
header.GetTokenLength() == sizeof(mCoapToken) &&
|
||||
memcmp(mCoapToken, header.GetToken(), sizeof(mCoapToken)) == 0, ;);
|
||||
aMessage.MoveOffset(header.GetLength());
|
||||
VerifyOrExit(result == kThreadError_None && aHeader != NULL && aMessage != NULL, ;);
|
||||
|
||||
VerifyOrExit(aHeader->GetCode() == Coap::Header::kCodeChanged, ;);
|
||||
|
||||
otLogInfoMle("Received address reply\n");
|
||||
|
||||
SuccessOrExit(ThreadTlv::GetTlv(aMessage, ThreadTlv::kStatus, sizeof(statusTlv), statusTlv));
|
||||
SuccessOrExit(ThreadTlv::GetTlv(*aMessage, ThreadTlv::kStatus, sizeof(statusTlv), statusTlv));
|
||||
VerifyOrExit(statusTlv.IsValid() && statusTlv.GetStatus() == statusTlv.kSuccess, ;);
|
||||
|
||||
SuccessOrExit(ThreadTlv::GetTlv(aMessage, ThreadTlv::kRloc16, sizeof(rlocTlv), rlocTlv));
|
||||
SuccessOrExit(ThreadTlv::GetTlv(*aMessage, ThreadTlv::kRloc16, sizeof(rlocTlv), rlocTlv));
|
||||
VerifyOrExit(rlocTlv.IsValid(), ;);
|
||||
VerifyOrExit(IsRouterIdValid(routerId = GetRouterId(rlocTlv.GetRloc16())), ;);
|
||||
|
||||
SuccessOrExit(ThreadTlv::GetTlv(aMessage, ThreadTlv::kRouterMask, sizeof(routerMaskTlv), routerMaskTlv));
|
||||
SuccessOrExit(ThreadTlv::GetTlv(*aMessage, ThreadTlv::kRouterMask, sizeof(routerMaskTlv), routerMaskTlv));
|
||||
VerifyOrExit(routerMaskTlv.IsValid(), ;);
|
||||
|
||||
// assign short address
|
||||
@@ -3419,12 +3406,7 @@ void MleRouter::SendAddressSolicitResponse(const Coap::Header &aRequestHeader, u
|
||||
Message *message;
|
||||
|
||||
VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
responseHeader.Init();
|
||||
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
|
||||
responseHeader.SetCode(Coap::Header::kCodeChanged);
|
||||
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
|
||||
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
|
||||
responseHeader.Finalize();
|
||||
responseHeader.SetDefaultResponseHeader(aRequestHeader);
|
||||
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
|
||||
|
||||
statusTlv.Init();
|
||||
@@ -3509,12 +3491,8 @@ void MleRouter::SendAddressReleaseResponse(const Coap::Header &aRequestHeader, c
|
||||
Message *message;
|
||||
|
||||
VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
|
||||
responseHeader.Init();
|
||||
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
|
||||
responseHeader.SetCode(Coap::Header::kCodeChanged);
|
||||
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
|
||||
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
|
||||
responseHeader.Finalize();
|
||||
responseHeader.SetDefaultResponseHeader(aRequestHeader);
|
||||
|
||||
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
|
||||
|
||||
SuccessOrExit(error = mCoapServer.SendMessage(*message, aMessageInfo));
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <coap/coap_header.hpp>
|
||||
#include <coap/coap_server.hpp>
|
||||
#include <coap/coap_client.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <common/trickle_timer.hpp>
|
||||
#include <mac/mac_frame.hpp>
|
||||
@@ -686,9 +687,9 @@ private:
|
||||
ThreadError UpdateChildAddresses(const AddressRegistrationTlv &aTlv, Child &aChild);
|
||||
void UpdateRoutes(const RouteTlv &aTlv, uint8_t aRouterId);
|
||||
|
||||
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
|
||||
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
void HandleAddressSolicitResponse(Message &aMessage);
|
||||
static void HandleAddressSolicitResponse(void *aContext, otCoapHeader *aHeader, otMessage aMessage,
|
||||
ThreadError result);
|
||||
void HandleAddressSolicitResponse(Coap::Header *aHeader, Message *aMessage, ThreadError result);
|
||||
static void HandleAddressRelease(void *aContext, Coap::Header &aHeader, Message &aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo);
|
||||
void HandleAddressRelease(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
@@ -726,7 +727,6 @@ private:
|
||||
Timer mStateUpdateTimer;
|
||||
Timer mDelayedResponseTimer;
|
||||
|
||||
Ip6::UdpSocket mSocket;
|
||||
Coap::Resource mAddressSolicit;
|
||||
Coap::Resource mAddressRelease;
|
||||
|
||||
@@ -750,8 +750,7 @@ private:
|
||||
uint8_t mPreviousRouterId;
|
||||
|
||||
Coap::Server &mCoapServer;
|
||||
uint8_t mCoapToken[2];
|
||||
uint16_t mCoapMessageId;
|
||||
Coap::Client &mCoapClient;
|
||||
};
|
||||
|
||||
} // namespace Mle
|
||||
|
||||
@@ -58,6 +58,7 @@ static const char name[] = "thread";
|
||||
ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6):
|
||||
Netif(aIp6),
|
||||
mCoapServer(aIp6.mUdp, kCoapUdpPort),
|
||||
mCoapClient(*this),
|
||||
mAddressResolver(*this),
|
||||
mActiveDataset(*this),
|
||||
mPendingDataset(*this),
|
||||
@@ -103,12 +104,14 @@ ThreadError ThreadNetif::Up(void)
|
||||
mIsUp = true;
|
||||
}
|
||||
|
||||
mCoapClient.Start();
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
ThreadError ThreadNetif::Down(void)
|
||||
{
|
||||
mCoapServer.Stop();
|
||||
mCoapClient.Stop();
|
||||
mMleRouter.Disable();
|
||||
mMeshForwarder.Stop();
|
||||
mIp6.RemoveNetif(*this);
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include <openthread-types.h>
|
||||
|
||||
#include <coap/coap_server.hpp>
|
||||
#include <coap/coap_client.hpp>
|
||||
#include <mac/mac.hpp>
|
||||
#include <meshcop/joiner_router.hpp>
|
||||
#include <meshcop/leader.hpp>
|
||||
@@ -170,13 +172,21 @@ public:
|
||||
NetworkDiagnostic::NetworkDiagnostic &GetNetworkDiagnostic(void) { return mNetworkDiagnostic; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the coap server object.
|
||||
* This method returns a reference to the CoAP server object.
|
||||
*
|
||||
* @returns A pointer to the coap server object.
|
||||
* @returns A reference to the CoAP server object.
|
||||
*
|
||||
*/
|
||||
Coap::Server &GetCoapServer(void) { return mCoapServer; }
|
||||
|
||||
/**
|
||||
* This method returns a reference to the CoAP client object.
|
||||
*
|
||||
* @returns A reference to the CoAP client object.
|
||||
*
|
||||
*/
|
||||
Coap::Client &GetCoapClient(void) { return mCoapClient; }
|
||||
|
||||
/**
|
||||
* This method returns a reference to the IPv6 filter object.
|
||||
*
|
||||
@@ -273,6 +283,7 @@ public:
|
||||
|
||||
private:
|
||||
Coap::Server mCoapServer;
|
||||
Coap::Client mCoapClient;
|
||||
AddressResolver mAddressResolver;
|
||||
MeshCoP::ActiveDataset mActiveDataset;
|
||||
MeshCoP::PendingDataset mPendingDataset;
|
||||
|
||||
Reference in New Issue
Block a user