mirror of
https://github.com/espressif/openthread.git
synced 2026-09-14 05:00:11 +00:00
[tcp] implement TCP Circular Send Buffer (#7867)
This commit is contained in:
@@ -212,6 +212,7 @@ LOCAL_SRC_FILES := \
|
|||||||
src/core/api/srp_server_api.cpp \
|
src/core/api/srp_server_api.cpp \
|
||||||
src/core/api/tasklet_api.cpp \
|
src/core/api/tasklet_api.cpp \
|
||||||
src/core/api/tcp_api.cpp \
|
src/core/api/tcp_api.cpp \
|
||||||
|
src/core/api/tcp_ext_api.cpp \
|
||||||
src/core/api/thread_api.cpp \
|
src/core/api/thread_api.cpp \
|
||||||
src/core/api/thread_ftd_api.cpp \
|
src/core/api/thread_ftd_api.cpp \
|
||||||
src/core/api/trel_api.cpp \
|
src/core/api/trel_api.cpp \
|
||||||
@@ -315,6 +316,7 @@ LOCAL_SRC_FILES := \
|
|||||||
src/core/net/srp_client.cpp \
|
src/core/net/srp_client.cpp \
|
||||||
src/core/net/srp_server.cpp \
|
src/core/net/srp_server.cpp \
|
||||||
src/core/net/tcp6.cpp \
|
src/core/net/tcp6.cpp \
|
||||||
|
src/core/net/tcp6_ext.cpp \
|
||||||
src/core/net/udp6.cpp \
|
src/core/net/udp6.cpp \
|
||||||
src/core/radio/radio.cpp \
|
src/core/radio/radio.cpp \
|
||||||
src/core/radio/radio_callbacks.cpp \
|
src/core/radio/radio_callbacks.cpp \
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ extern "C" {
|
|||||||
* @note This number versions both OpenThread platform and user APIs.
|
* @note This number versions both OpenThread platform and user APIs.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define OPENTHREAD_API_VERSION (244)
|
#define OPENTHREAD_API_VERSION (245)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup api-instance
|
* @addtogroup api-instance
|
||||||
|
|||||||
@@ -88,10 +88,10 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
typedef struct otTcpCircularSendBuffer
|
typedef struct otTcpCircularSendBuffer
|
||||||
{
|
{
|
||||||
const uint8_t *mDataBuffer; ///< Pointer to data in the circular send buffer
|
uint8_t *mDataBuffer; ///< Pointer to data in the circular send buffer
|
||||||
size_t mCapacity; ///< Length of the circular send buffer
|
size_t mCapacity; ///< Length of the circular send buffer
|
||||||
size_t mStartIndex; ///< Index of the first valid byte in the send buffer
|
size_t mStartIndex; ///< Index of the first valid byte in the send buffer
|
||||||
size_t mCapacityUsed; ///< Number of bytes stored in the send buffer
|
size_t mCapacityUsed; ///< Number of bytes stored in the send buffer
|
||||||
|
|
||||||
otLinkedBuffer mSendLinks[2];
|
otLinkedBuffer mSendLinks[2];
|
||||||
uint8_t mFirstSendLinkIndex;
|
uint8_t mFirstSendLinkIndex;
|
||||||
@@ -107,6 +107,15 @@ typedef struct otTcpCircularSendBuffer
|
|||||||
*/
|
*/
|
||||||
void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, void *aDataBuffer, size_t aCapacity);
|
void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, void *aDataBuffer, size_t aCapacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enumeration defines flags passed to @p otTcpCircularSendBufferWrite.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
OT_TCP_CIRCULAR_SEND_BUFFER_WRITE_MORE_TO_COME = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends out data on a TCP endpoint, using the provided TCP circular send
|
* Sends out data on a TCP endpoint, using the provided TCP circular send
|
||||||
* buffer to manage buffering.
|
* buffer to manage buffering.
|
||||||
@@ -136,15 +145,17 @@ void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, voi
|
|||||||
* @param[in] aLength The length of the data pointed to by @p aData to copy into the TCP circular send buffer.
|
* @param[in] aLength The length of the data pointed to by @p aData to copy into the TCP circular send buffer.
|
||||||
* @param[out] aWritten Populated with the amount of data copied into the send buffer, which might be less than
|
* @param[out] aWritten Populated with the amount of data copied into the send buffer, which might be less than
|
||||||
* @p aLength if the send buffer reaches capacity.
|
* @p aLength if the send buffer reaches capacity.
|
||||||
|
* @param[in] aFlags Flags specifying options for this operation (see enumeration above).
|
||||||
*
|
*
|
||||||
* @returns OT_ERROR_NONE Successfully copied data into the send buffer and sent it on the TCP endpoint.
|
* @returns OT_ERROR_NONE Successfully copied data into the send buffer and sent it on the TCP endpoint.
|
||||||
* @returns OT_ERROR_FAILED Failed to send out data on the TCP endpoint.
|
* @returns OT_ERROR_FAILED Failed to send out data on the TCP endpoint.
|
||||||
*/
|
*/
|
||||||
otError otTcpCircularSendBufferWrite(otTcpEndpoint * aEndpoint,
|
otError otTcpCircularSendBufferWrite(otTcpEndpoint * aEndpoint,
|
||||||
otTcpCircularSendBuffer *aSendBuffer,
|
otTcpCircularSendBuffer *aSendBuffer,
|
||||||
void * aData,
|
const void * aData,
|
||||||
size_t aLength,
|
size_t aLength,
|
||||||
size_t * aWritten);
|
size_t * aWritten,
|
||||||
|
uint32_t aFlags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs circular-send-buffer-specific handling in the otTcpForwardProgress
|
* Performs circular-send-buffer-specific handling in the otTcpForwardProgress
|
||||||
@@ -175,7 +186,7 @@ void otTcpCircularSendBufferHandleForwardProgress(otTcpCircularSendBuffer *aSend
|
|||||||
*
|
*
|
||||||
* @return The amount of free space in the send buffer.
|
* @return The amount of free space in the send buffer.
|
||||||
*/
|
*/
|
||||||
size_t otTcpCircularSendBufferFreeSpace(otTcpCircularSendBuffer *aSendBuffer);
|
size_t otTcpCircularSendBufferGetFreeSpace(const otTcpCircularSendBuffer *aSendBuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forcibly discards all data in the circular send buffer.
|
* Forcibly discards all data in the circular send buffer.
|
||||||
|
|||||||
@@ -351,6 +351,7 @@ openthread_core_files = [
|
|||||||
"api/srp_server_api.cpp",
|
"api/srp_server_api.cpp",
|
||||||
"api/tasklet_api.cpp",
|
"api/tasklet_api.cpp",
|
||||||
"api/tcp_api.cpp",
|
"api/tcp_api.cpp",
|
||||||
|
"api/tcp_ext_api.cpp",
|
||||||
"api/thread_api.cpp",
|
"api/thread_api.cpp",
|
||||||
"api/thread_ftd_api.cpp",
|
"api/thread_ftd_api.cpp",
|
||||||
"api/trel_api.cpp",
|
"api/trel_api.cpp",
|
||||||
@@ -583,6 +584,8 @@ openthread_core_files = [
|
|||||||
"net/srp_server.hpp",
|
"net/srp_server.hpp",
|
||||||
"net/tcp6.cpp",
|
"net/tcp6.cpp",
|
||||||
"net/tcp6.hpp",
|
"net/tcp6.hpp",
|
||||||
|
"net/tcp6_ext.cpp",
|
||||||
|
"net/tcp6_ext.hpp",
|
||||||
"net/udp6.cpp",
|
"net/udp6.cpp",
|
||||||
"net/udp6.hpp",
|
"net/udp6.hpp",
|
||||||
"radio/max_power_table.hpp",
|
"radio/max_power_table.hpp",
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ set(COMMON_SOURCES
|
|||||||
api/srp_server_api.cpp
|
api/srp_server_api.cpp
|
||||||
api/tasklet_api.cpp
|
api/tasklet_api.cpp
|
||||||
api/tcp_api.cpp
|
api/tcp_api.cpp
|
||||||
|
api/tcp_ext_api.cpp
|
||||||
api/thread_api.cpp
|
api/thread_api.cpp
|
||||||
api/thread_ftd_api.cpp
|
api/thread_ftd_api.cpp
|
||||||
api/trel_api.cpp
|
api/trel_api.cpp
|
||||||
@@ -181,6 +182,7 @@ set(COMMON_SOURCES
|
|||||||
net/srp_client.cpp
|
net/srp_client.cpp
|
||||||
net/srp_server.cpp
|
net/srp_server.cpp
|
||||||
net/tcp6.cpp
|
net/tcp6.cpp
|
||||||
|
net/tcp6_ext.cpp
|
||||||
net/udp6.cpp
|
net/udp6.cpp
|
||||||
radio/radio.cpp
|
radio/radio.cpp
|
||||||
radio/radio_callbacks.cpp
|
radio/radio_callbacks.cpp
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ SOURCES_COMMON = \
|
|||||||
api/srp_server_api.cpp \
|
api/srp_server_api.cpp \
|
||||||
api/tasklet_api.cpp \
|
api/tasklet_api.cpp \
|
||||||
api/tcp_api.cpp \
|
api/tcp_api.cpp \
|
||||||
|
api/tcp_ext_api.cpp \
|
||||||
api/thread_api.cpp \
|
api/thread_api.cpp \
|
||||||
api/thread_ftd_api.cpp \
|
api/thread_ftd_api.cpp \
|
||||||
api/trel_api.cpp \
|
api/trel_api.cpp \
|
||||||
@@ -271,6 +272,7 @@ SOURCES_COMMON = \
|
|||||||
net/srp_client.cpp \
|
net/srp_client.cpp \
|
||||||
net/srp_server.cpp \
|
net/srp_server.cpp \
|
||||||
net/tcp6.cpp \
|
net/tcp6.cpp \
|
||||||
|
net/tcp6_ext.cpp \
|
||||||
net/udp6.cpp \
|
net/udp6.cpp \
|
||||||
radio/radio.cpp \
|
radio/radio.cpp \
|
||||||
radio/radio_callbacks.cpp \
|
radio/radio_callbacks.cpp \
|
||||||
@@ -584,6 +586,7 @@ HEADERS_COMMON = \
|
|||||||
net/srp_client.hpp \
|
net/srp_client.hpp \
|
||||||
net/srp_server.hpp \
|
net/srp_server.hpp \
|
||||||
net/tcp6.hpp \
|
net/tcp6.hpp \
|
||||||
|
net/tcp6_ext.hpp \
|
||||||
net/udp6.hpp \
|
net/udp6.hpp \
|
||||||
openthread-core-config.h \
|
openthread-core-config.h \
|
||||||
radio/max_power_table.hpp \
|
radio/max_power_table.hpp \
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, The OpenThread Authors.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* This file implements extensions to the OpenThread TCP API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openthread-core-config.h"
|
||||||
|
|
||||||
|
#if OPENTHREAD_CONFIG_TCP_ENABLE
|
||||||
|
|
||||||
|
#include <openthread/tcp_ext.h>
|
||||||
|
|
||||||
|
#include "common/as_core_type.hpp"
|
||||||
|
#include "common/locator_getters.hpp"
|
||||||
|
#include "net/tcp6_ext.hpp"
|
||||||
|
|
||||||
|
using namespace ot;
|
||||||
|
|
||||||
|
void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, void *aDataBuffer, size_t aCapacity)
|
||||||
|
{
|
||||||
|
AsCoreType(aSendBuffer).Initialize(aDataBuffer, aCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
otError otTcpCircularSendBufferWrite(otTcpEndpoint * aEndpoint,
|
||||||
|
otTcpCircularSendBuffer *aSendBuffer,
|
||||||
|
const void * aData,
|
||||||
|
size_t aLength,
|
||||||
|
size_t * aWritten,
|
||||||
|
uint32_t aFlags)
|
||||||
|
{
|
||||||
|
AssertPointerIsNotNull(aWritten);
|
||||||
|
return AsCoreType(aSendBuffer).Write(AsCoreType(aEndpoint), aData, aLength, *aWritten, aFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void otTcpCircularSendBufferHandleForwardProgress(otTcpCircularSendBuffer *aSendBuffer, size_t aInSendBuffer)
|
||||||
|
{
|
||||||
|
AsCoreType(aSendBuffer).HandleForwardProgress(aInSendBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t otTcpCircularSendBufferGetFreeSpace(const otTcpCircularSendBuffer *aSendBuffer)
|
||||||
|
{
|
||||||
|
return AsCoreType(aSendBuffer).GetFreeSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
void otTcpCircularSendBufferForceDiscardAll(otTcpCircularSendBuffer *aSendBuffer)
|
||||||
|
{
|
||||||
|
AsCoreType(aSendBuffer).ForceDiscardAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
otError otTcpCircularSendBufferDeinitialize(otTcpCircularSendBuffer *aSendBuffer)
|
||||||
|
{
|
||||||
|
return AsCoreType(aSendBuffer).Deinitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENTHREAD_CONFIG_TCP_ENABLE
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, The OpenThread Authors.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* This file implements TCP/IPv6 socket extensions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openthread-core-config.h"
|
||||||
|
|
||||||
|
#if OPENTHREAD_CONFIG_TCP_ENABLE
|
||||||
|
|
||||||
|
#include "tcp6_ext.hpp"
|
||||||
|
|
||||||
|
#include "common/code_utils.hpp"
|
||||||
|
#include "common/error.hpp"
|
||||||
|
#include "common/locator_getters.hpp"
|
||||||
|
#include "common/log.hpp"
|
||||||
|
|
||||||
|
namespace ot {
|
||||||
|
namespace Ip6 {
|
||||||
|
|
||||||
|
RegisterLogModule("TcpExt");
|
||||||
|
|
||||||
|
void TcpCircularSendBuffer::Initialize(void *aDataBuffer, size_t aCapacity)
|
||||||
|
{
|
||||||
|
mDataBuffer = static_cast<uint8_t *>(aDataBuffer);
|
||||||
|
mCapacity = aCapacity;
|
||||||
|
ForceDiscardAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error TcpCircularSendBuffer::Write(Tcp::Endpoint &aEndpoint,
|
||||||
|
const void * aData,
|
||||||
|
size_t aLength,
|
||||||
|
size_t & aWritten,
|
||||||
|
uint32_t aFlags)
|
||||||
|
{
|
||||||
|
Error error = kErrorNone;
|
||||||
|
size_t bytesFree = GetFreeSpace();
|
||||||
|
size_t writeIndex;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
size_t bytesUntilWrap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle the case where we don't have enough space to accommodate all of the
|
||||||
|
* provided data.
|
||||||
|
*/
|
||||||
|
aLength = Min(aLength, bytesFree);
|
||||||
|
VerifyOrExit(aLength != 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a "simplifying" if statement the removes an edge case from the logic
|
||||||
|
* below. It guarantees that a write to an empty buffer will never wrap.
|
||||||
|
*/
|
||||||
|
if (mCapacityUsed == 0)
|
||||||
|
{
|
||||||
|
mStartIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeIndex = GetIndex(mStartIndex, mCapacityUsed);
|
||||||
|
|
||||||
|
if ((aFlags & OT_TCP_CIRCULAR_SEND_BUFFER_WRITE_MORE_TO_COME) != 0 && aLength < bytesFree)
|
||||||
|
{
|
||||||
|
flags |= OT_TCP_SEND_MORE_TO_COME;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesUntilWrap = mCapacity - writeIndex;
|
||||||
|
if (aLength <= bytesUntilWrap)
|
||||||
|
{
|
||||||
|
memcpy(&mDataBuffer[writeIndex], aData, aLength);
|
||||||
|
if (writeIndex == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* mCapacityUsed == 0 corresponds to the case where we're writing
|
||||||
|
* to an empty buffer. mCapacityUsed != 0 && writeIndex == 0
|
||||||
|
* corresponds to the case where the buffer is not empty and this is
|
||||||
|
* writing the first bytes that wrap.
|
||||||
|
*/
|
||||||
|
uint8_t linkIndex;
|
||||||
|
if (mCapacityUsed == 0)
|
||||||
|
{
|
||||||
|
linkIndex = mFirstSendLinkIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
linkIndex = 1 - mFirstSendLinkIndex;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
otLinkedBuffer &dataSendLink = mSendLinks[linkIndex];
|
||||||
|
|
||||||
|
dataSendLink.mNext = nullptr;
|
||||||
|
dataSendLink.mData = &mDataBuffer[writeIndex];
|
||||||
|
dataSendLink.mLength = aLength;
|
||||||
|
|
||||||
|
LogDebg("Appending link %u (points to index %u, length %u)", static_cast<unsigned>(linkIndex),
|
||||||
|
static_cast<unsigned>(writeIndex), static_cast<unsigned>(aLength));
|
||||||
|
error = aEndpoint.SendByReference(dataSendLink, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogDebg("Extending tail link by length %u", static_cast<unsigned>(aLength));
|
||||||
|
error = aEndpoint.SendByExtension(aLength, flags);
|
||||||
|
}
|
||||||
|
VerifyOrExit(error == kErrorNone, aLength = 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const uint8_t *dataIndexable = static_cast<const uint8_t *>(aData);
|
||||||
|
size_t bytesWrapped = aLength - bytesUntilWrap;
|
||||||
|
|
||||||
|
memcpy(&mDataBuffer[writeIndex], &dataIndexable[0], bytesUntilWrap);
|
||||||
|
memcpy(&mDataBuffer[0], &dataIndexable[bytesUntilWrap], bytesWrapped);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because of the "simplifying" if statement at the top, we don't
|
||||||
|
* have to worry about starting from an empty buffer in this case.
|
||||||
|
*/
|
||||||
|
LogDebg("Extending tail link by length %u (wrapping)", static_cast<unsigned>(bytesUntilWrap));
|
||||||
|
error = aEndpoint.SendByExtension(bytesUntilWrap, flags | OT_TCP_SEND_MORE_TO_COME);
|
||||||
|
VerifyOrExit(error == kErrorNone, aLength = 0);
|
||||||
|
|
||||||
|
{
|
||||||
|
otLinkedBuffer &wrappedDataSendLink = mSendLinks[1 - mFirstSendLinkIndex];
|
||||||
|
|
||||||
|
wrappedDataSendLink.mNext = nullptr;
|
||||||
|
wrappedDataSendLink.mData = &mDataBuffer[0];
|
||||||
|
wrappedDataSendLink.mLength = bytesWrapped;
|
||||||
|
|
||||||
|
LogDebg("Appending link %u (wrapping)", static_cast<unsigned>(1 - mFirstSendLinkIndex));
|
||||||
|
error = aEndpoint.SendByReference(wrappedDataSendLink, flags);
|
||||||
|
VerifyOrExit(error == kErrorNone, aLength = bytesUntilWrap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mCapacityUsed += aLength;
|
||||||
|
aWritten = aLength;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpCircularSendBuffer::HandleForwardProgress(size_t aInSendBuffer)
|
||||||
|
{
|
||||||
|
size_t bytesRemoved;
|
||||||
|
size_t bytesUntilWrap;
|
||||||
|
|
||||||
|
OT_ASSERT(aInSendBuffer <= mCapacityUsed);
|
||||||
|
LogDebg("Forward progress: %u bytes in send buffer\n", aInSendBuffer);
|
||||||
|
bytesRemoved = mCapacityUsed - aInSendBuffer;
|
||||||
|
bytesUntilWrap = mCapacity - mStartIndex;
|
||||||
|
|
||||||
|
if (bytesRemoved < bytesUntilWrap)
|
||||||
|
{
|
||||||
|
mStartIndex += bytesRemoved;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mStartIndex = bytesRemoved - bytesUntilWrap;
|
||||||
|
/* The otLinkedBuffer for the pre-wrap data is now empty. */
|
||||||
|
LogDebg("Pre-wrap linked buffer now empty: switching first link index from %u to %u\n",
|
||||||
|
static_cast<unsigned>(mFirstSendLinkIndex), static_cast<unsigned>(1 - mFirstSendLinkIndex));
|
||||||
|
mFirstSendLinkIndex = 1 - mFirstSendLinkIndex;
|
||||||
|
}
|
||||||
|
mCapacityUsed = aInSendBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TcpCircularSendBuffer::GetFreeSpace(void) const
|
||||||
|
{
|
||||||
|
return mCapacity - mCapacityUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpCircularSendBuffer::ForceDiscardAll(void)
|
||||||
|
{
|
||||||
|
mStartIndex = 0;
|
||||||
|
mCapacityUsed = 0;
|
||||||
|
mFirstSendLinkIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error TcpCircularSendBuffer::Deinitialize(void)
|
||||||
|
{
|
||||||
|
return (mCapacityUsed != 0) ? kErrorBusy : kErrorNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TcpCircularSendBuffer::GetIndex(size_t aStart, size_t aOffsetFromStart) const
|
||||||
|
{
|
||||||
|
size_t bytesUntilWrap;
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
OT_ASSERT(aStart < mCapacity);
|
||||||
|
bytesUntilWrap = mCapacity - aStart;
|
||||||
|
if (aOffsetFromStart < bytesUntilWrap)
|
||||||
|
{
|
||||||
|
index = aStart + aOffsetFromStart;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = aOffsetFromStart - bytesUntilWrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ip6
|
||||||
|
} // namespace ot
|
||||||
|
|
||||||
|
#endif // OPENTHREAD_CONFIG_TCP_ENABLE
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, The OpenThread Authors.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the copyright holder nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* This file includes definitions for TCP/IPv6 socket extensions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCP6_EXT_HPP_
|
||||||
|
#define TCP6_EXT_HPP_
|
||||||
|
|
||||||
|
#include "openthread-core-config.h"
|
||||||
|
|
||||||
|
#include <openthread/tcp_ext.h>
|
||||||
|
|
||||||
|
#include "net/tcp6.hpp"
|
||||||
|
|
||||||
|
namespace ot {
|
||||||
|
namespace Ip6 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup core-tcp-ext
|
||||||
|
*
|
||||||
|
* @brief
|
||||||
|
* This module includes definitions for TCP/IPv6 socket extensions.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a TCP circular send buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class TcpCircularSendBuffer : public otTcpCircularSendBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Initializes a TCP circular send buffer.
|
||||||
|
*
|
||||||
|
* @sa otTcpCircularSendBufferInitialize
|
||||||
|
*
|
||||||
|
* @param[in] aDataBuffer A pointer to memory to use to store data in the TCP circular send buffer.
|
||||||
|
* @param[in] aCapacity The capacity, in bytes, of the TCP circular send buffer, which must equal the size
|
||||||
|
* of the memory pointed to by @p aDataBuffer .
|
||||||
|
*/
|
||||||
|
void Initialize(void *aDataBuffer, size_t aCapacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends out data on a TCP endpoint, using this TCP circular send buffer to manage buffering.
|
||||||
|
*
|
||||||
|
* @sa otTcpCircularSendBufferWrite, particularly for guidance on how @p aEndpoint must be chosen.
|
||||||
|
*
|
||||||
|
* @param[in] aEndpoint The TCP endpoint on which to send out data.
|
||||||
|
* @param[in] aData A pointer to data to copy into the TCP circular send buffer.
|
||||||
|
* @param[in] aLength The length of the data pointed to by @p aData to copy into the TCP circular send buffer.
|
||||||
|
* @param[out] aWritten Populated with the amount of data copied into the send buffer, which might be less than
|
||||||
|
* @p aLength if the send buffer reaches capacity.
|
||||||
|
* @param[in] aFlags Flags specifying options for this operation.
|
||||||
|
*
|
||||||
|
* @retval kErrorNone on success, or the error returned by the TCP endpoint on failure.
|
||||||
|
*/
|
||||||
|
Error Write(Tcp::Endpoint &aEndpoint, const void *aData, size_t aLength, size_t &aWritten, uint32_t aFlags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs circular-send-buffer-specific handling in the otTcpForwardProgress callback.
|
||||||
|
*
|
||||||
|
* @sa otTcpCircularSendBufferHandleForwardProgress
|
||||||
|
*
|
||||||
|
* @param[in] aInSendBuffer Value of @p aInSendBuffer passed to the otTcpForwardProgress() callback.
|
||||||
|
*/
|
||||||
|
void HandleForwardProgress(size_t aInSendBuffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount of free space in this TCP circular send buffer.
|
||||||
|
*
|
||||||
|
* @sa otTcpCircularSendBufferFreeSpace
|
||||||
|
*
|
||||||
|
* @return The amount of free space in the send buffer.
|
||||||
|
*/
|
||||||
|
size_t GetFreeSpace(void) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcibly discards all data in this TCP circular send buffer.
|
||||||
|
*
|
||||||
|
* @sa otTcpCircularSendBufferForceDiscardAll
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ForceDiscardAll(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deinitializes this TCP circular send buffer.
|
||||||
|
*
|
||||||
|
* @sa otTcpCircularSendBufferDeinitialize
|
||||||
|
*
|
||||||
|
* @retval kErrorNone Successfully deinitialized this TCP circular send buffer.
|
||||||
|
* @retval kErrorFailed Failed to deinitialize the TCP circular send buffer.
|
||||||
|
*/
|
||||||
|
Error Deinitialize(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t GetIndex(size_t aStart, size_t aOffsetFromStart) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ip6
|
||||||
|
|
||||||
|
DefineCoreType(otTcpCircularSendBuffer, Ip6::TcpCircularSendBuffer);
|
||||||
|
|
||||||
|
} // namespace ot
|
||||||
|
|
||||||
|
#endif // TCP6_HPP_
|
||||||
Vendored
+1
@@ -55,6 +55,7 @@ void lbuf_append(struct lbufhead* buffer, otLinkedBuffer* newentry) {
|
|||||||
|
|
||||||
void lbuf_extend(struct lbufhead* buffer, size_t numbytes) {
|
void lbuf_extend(struct lbufhead* buffer, size_t numbytes) {
|
||||||
buffer->tail->mLength += numbytes;
|
buffer->tail->mLength += numbytes;
|
||||||
|
buffer->length += numbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, uint32_t* ntraversed) {
|
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, uint32_t* ntraversed) {
|
||||||
|
|||||||
Reference in New Issue
Block a user