diff --git a/include/Makefile.am b/include/Makefile.am index 6729d6817..e91c87c7d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -84,6 +84,7 @@ openthread_headers = \ openthread/srp_server.h \ openthread/tasklet.h \ openthread/tcp.h \ + openthread/tcp_ext.h \ openthread/thread.h \ openthread/thread_ftd.h \ openthread/trel.h \ diff --git a/include/openthread/BUILD.gn b/include/openthread/BUILD.gn index 1b89d9dba..75abeb094 100644 --- a/include/openthread/BUILD.gn +++ b/include/openthread/BUILD.gn @@ -109,6 +109,7 @@ source_set("openthread") { "srp_server.h", "tasklet.h", "tcp.h", + "tcp_ext.h", "thread.h", "thread_ftd.h", "trel.h", diff --git a/include/openthread/tcp_ext.h b/include/openthread/tcp_ext.h new file mode 100644 index 000000000..5c0ddc678 --- /dev/null +++ b/include/openthread/tcp_ext.h @@ -0,0 +1,216 @@ +/* + * 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 + * @brief + * This file defines extensions to the OpenThread TCP API. + * + */ + +#ifndef OPENTHREAD_TCP_EXT_H_ +#define OPENTHREAD_TCP_EXT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup api-tcp-ext + * + * @brief + * This module includes easy-to-use abstractions on top of the base TCP API. + * + * @{ + * + */ + +/** + * This structure represents a circular send buffer for use with a TCP endpoint. + * + * Using a circular send buffer is optional. Applications can use a TCP + * endpoint to send data by managing otLinkedBuffers directly. However, some + * applications may find it more convenient to have a circular send buffer; + * such applications can call otTcpCircularSendBufferWrite() to "attach" a + * circular send buffer to a TCP endpoint and send out data on that TCP + * endpoint, relying on the circular send buffer to manage the underlying + * otLinkedBuffers. + * + * otTcpCircularSendBuffer is implemented on top of the otLinkedBuffer-based + * API provided by an otTcpEndpoint. Once attached to an otTcpEndpoint, an + * otTcpCircularSendBuffer performs all the work of managing otLinkedBuffers + * for the connection. This means that, once an otTcpCircularSendBuffer is + * attached to an otTcpEndpoint, the application should not call + * otTcpSendByReference() or otTcpSendByExtension() on that otTcpEndpoint. + * Instead, the application should use otTcpCircularSendBufferWrite() to add + * data to the send buffer. + * + * The otTcpForwardProgress() callback is the intended way for users to learn + * when space becomes available in the circular send buffer. On an + * otTcpEndpoint to which an otTcpCircularSendBuffer is attached, the + * application MUST install an otTcpForwardProgress() callback and call + * otTcpCircularSendBufferHandleForwardProgress() on the attached + * otTcpCircularSendBuffer at the start of the callback function. It is + * recommended that the user NOT install an otTcpSendDone() callback, as all + * management of otLinkedBuffers is handled by the circular send buffer. + * + * The application should not inspect the fields of this structure directly; it + * should only interact with it via the TCP Circular Send Buffer API functions + * whose signature are provided in this file. + * + */ +typedef struct otTcpCircularSendBuffer +{ + const uint8_t *mDataBuffer; ///< Pointer to data in 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 mCapacityUsed; ///< Number of bytes stored in the send buffer + + otLinkedBuffer mSendLinks[2]; + uint8_t mFirstSendLinkIndex; +} otTcpCircularSendBuffer; + +/** + * Initializes a TCP circular send buffer. + * + * @param[in] aSendBuffer A pointer to the TCP circular send buffer to initialize. + * @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 otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, void *aDataBuffer, size_t aCapacity); + +/** + * Sends out data on a TCP endpoint, using the provided TCP circular send + * buffer to manage buffering. + * + * Once this function is called, @p aSendBuffer and @p aEndpoint are considered + * "attached" to each other. While they are attached, ALL send operations for + * @p aEndpoint must be made using @p aSendBuffer and ALL operations on + * @p aSendBuffer must be associated with @p aEndpoint . + * + * The only way to "detach" a TCP circular send buffer and a TCP endpoint is to + * wait for the send buffer to become completely empty. This can happen in two + * ways: (1) all data in the send buffer is sent and acknowledged in the normal + * course of TCP protocol operation, or (2) the connection is terminated. + * + * The recommended usage pattern is to use a single TCP circular send buffer + * with a TCP endpoint, and to send data on that TCP endpoint only via its + * associated TCP circular buffer. This recommended usage pattern sidesteps the + * issues described above by always using a TCP endpoint and TCP circular send + * buffer together. + * + * If the circular send buffer reaches capacity, only a prefix of the provided + * data is copied into the circular send buffer. + * + * @param[in] aEndpoint The TCP endpoint on which to send out data. + * @param[in] aSendBuffer The TCP circular send buffer into which to copy 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. + * + * @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. + */ +otError otTcpCircularSendBufferWrite(otTcpEndpoint * aEndpoint, + otTcpCircularSendBuffer *aSendBuffer, + void * aData, + size_t aLength, + size_t * aWritten); + +/** + * Performs circular-send-buffer-specific handling in the otTcpForwardProgress + * callback. + * + * The application is expected to install an otTcpForwardProgress() callback on + * the otTcpEndpoint, and call this function at the start of the callback + * function for circular-send-buffer-specific processing. + * + * In the callback function, the application can determine the amount of free + * space in the circular send buffer by calling + * otTcpCircularSendBufferFreeSpace(), or by comparing @p aInSendBuffer with + * the send buffer's capacity, chosen by the user when calling + * otTcpCircularSendBufferInitialize(). + * + * @param[in] aSendBuffer A pointer to the TCP circular send buffer for the endpoint for which + * otTcpForwardProgress() was invoked. + * @param[in] aInSendBuffer Value of @p aInSendBuffer passed to the otTcpForwardProgress() callback. + */ +void otTcpCircularSendBufferHandleForwardProgress(otTcpCircularSendBuffer *aSendBuffer, size_t aInSendBuffer); + +/** + * Returns the amount of free space in the TCP circular send buffer. + * + * This operation will always succeed. + * + * @param[in] aSendBuffer A pointer to the TCP circular send buffer whose amount of free space to return. + * + * @return The amount of free space in the send buffer. + */ +size_t otTcpCircularSendBufferFreeSpace(otTcpCircularSendBuffer *aSendBuffer); + +/** + * Forcibly discards all data in the circular send buffer. + * + * The application is expected to call this function when a TCP connection is + * terminated unceremoniously (e.g., if the application calls + * otTcpEndpointAbort() or is informed of a reset connection via the + * otTcpConnectionLost() callback). + * + * Calling this function on a nonempty TCP circular send buffer attached to a + * TCP endpoint results in undefined behavior. + * + * @param[in] aSendBuffer The TCP circular send buffer whose data to discard. + */ +void otTcpCircularSendBufferForceDiscardAll(otTcpCircularSendBuffer *aSendBuffer); + +/** + * Deinitializes a TCP circular send buffer, detaching it if attached. + * + * If the TCP circular send buffer is not empty, then this operation will fail. + * + * @param[in] aSendBuffer The TCP circular send buffer to deinitialize. + * + * @retval OT_ERROR_NONE Successfully deinitialize the TCP circular send buffer. + * @retval OT_ERROR_BUSY Circular buffer contains data and cannot be deinitialized. + */ +otError otTcpCircularSendBufferDeinitialize(otTcpCircularSendBuffer *aSendBuffer); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_TCP_EXT_H_