1 /*
2  *  Copyright (c) 2022, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  * @brief
32  *   This file defines extensions to the OpenThread TCP API.
33  *
34  */
35 
36 #ifndef OPENTHREAD_TCP_EXT_H_
37 #define OPENTHREAD_TCP_EXT_H_
38 
39 #include <openthread/tcp.h>
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /**
46  * @addtogroup api-tcp-ext
47  *
48  * @brief
49  *   This module includes easy-to-use abstractions on top of the base TCP API.
50  *
51  * @{
52  *
53  */
54 
55 /**
56  * Represents a circular send buffer for use with a TCP endpoint.
57  *
58  * Using a circular send buffer is optional. Applications can use a TCP
59  * endpoint to send data by managing otLinkedBuffers directly. However, some
60  * applications may find it more convenient to have a circular send buffer;
61  * such applications can call otTcpCircularSendBufferWrite() to "attach" a
62  * circular send buffer to a TCP endpoint and send out data on that TCP
63  * endpoint, relying on the circular send buffer to manage the underlying
64  * otLinkedBuffers.
65  *
66  * otTcpCircularSendBuffer is implemented on top of the otLinkedBuffer-based
67  * API provided by an otTcpEndpoint. Once attached to an otTcpEndpoint, an
68  * otTcpCircularSendBuffer performs all the work of managing otLinkedBuffers
69  * for the connection. This means that, once an otTcpCircularSendBuffer is
70  * attached to an otTcpEndpoint, the application should not call
71  * otTcpSendByReference() or otTcpSendByExtension() on that otTcpEndpoint.
72  * Instead, the application should use otTcpCircularSendBufferWrite() to add
73  * data to the send buffer.
74  *
75  * The otTcpForwardProgress() callback is the intended way for users to learn
76  * when space becomes available in the circular send buffer. On an
77  * otTcpEndpoint to which an otTcpCircularSendBuffer is attached, the
78  * application MUST install an otTcpForwardProgress() callback and call
79  * otTcpCircularSendBufferHandleForwardProgress() on the attached
80  * otTcpCircularSendBuffer at the start of the callback function. It is
81  * recommended that the user NOT install an otTcpSendDone() callback, as all
82  * management of otLinkedBuffers is handled by the circular send buffer.
83  *
84  * The application should not inspect the fields of this structure directly; it
85  * should only interact with it via the TCP Circular Send Buffer API functions
86  * whose signature are provided in this file.
87  *
88  */
89 typedef struct otTcpCircularSendBuffer
90 {
91     uint8_t *mDataBuffer;   ///< Pointer to data in the circular send buffer
92     size_t   mCapacity;     ///< Length of the circular send buffer
93     size_t   mStartIndex;   ///< Index of the first valid byte in the send buffer
94     size_t   mCapacityUsed; ///< Number of bytes stored in the send buffer
95 
96     otLinkedBuffer mSendLinks[2];
97     uint8_t        mFirstSendLinkIndex;
98 } otTcpCircularSendBuffer;
99 
100 /**
101  * Initializes a TCP circular send buffer.
102  *
103  * @param[in]  aSendBuffer      A pointer to the TCP circular send buffer to initialize.
104  * @param[in]  aDataBuffer      A pointer to memory to use to store data in the TCP circular send buffer.
105  * @param[in]  aCapacity        The capacity, in bytes, of the TCP circular send buffer, which must equal the size of
106  *                              the memory pointed to by @p aDataBuffer .
107  */
108 void otTcpCircularSendBufferInitialize(otTcpCircularSendBuffer *aSendBuffer, void *aDataBuffer, size_t aCapacity);
109 
110 /**
111  * Defines flags passed to @p otTcpCircularSendBufferWrite.
112  *
113  */
114 enum
115 {
116     OT_TCP_CIRCULAR_SEND_BUFFER_WRITE_MORE_TO_COME = 1 << 0,
117 };
118 
119 /**
120  * Sends out data on a TCP endpoint, using the provided TCP circular send
121  * buffer to manage buffering.
122  *
123  * Once this function is called, @p aSendBuffer and @p aEndpoint are considered
124  * "attached" to each other. While they are attached, ALL send operations for
125  * @p aEndpoint must be made using @p aSendBuffer and ALL operations on
126  * @p aSendBuffer must be associated with @p aEndpoint .
127  *
128  * The only way to "detach" a TCP circular send buffer and a TCP endpoint is to
129  * wait for the send buffer to become completely empty. This can happen in two
130  * ways: (1) all data in the send buffer is sent and acknowledged in the normal
131  * course of TCP protocol operation, or (2) the connection is terminated.
132  *
133  * The recommended usage pattern is to use a single TCP circular send buffer
134  * with a TCP endpoint, and to send data on that TCP endpoint only via its
135  * associated TCP circular buffer. This recommended usage pattern sidesteps the
136  * issues described above by always using a TCP endpoint and TCP circular send
137  * buffer together.
138  *
139  * If the circular send buffer reaches capacity, only a prefix of the provided
140  * data is copied into the circular send buffer.
141  *
142  * @param[in]   aEndpoint    The TCP endpoint on which to send out data.
143  * @param[in]   aSendBuffer  The TCP circular send buffer into which to copy data.
144  * @param[in]   aData        A pointer to data to copy into the TCP circular send buffer.
145  * @param[in]   aLength      The length of the data pointed to by @p aData to copy into the TCP circular send buffer.
146  * @param[out]  aWritten     Populated with the amount of data copied into the send buffer, which might be less than
147  *                           @p aLength if the send buffer reaches capacity.
148  * @param[in]   aFlags       Flags specifying options for this operation (see enumeration above).
149  *
150  * @retval OT_ERROR_NONE    Successfully copied data into the send buffer and sent it on the TCP endpoint.
151  * @retval OT_ERROR_FAILED  Failed to send out data on the TCP endpoint.
152  */
153 otError otTcpCircularSendBufferWrite(otTcpEndpoint           *aEndpoint,
154                                      otTcpCircularSendBuffer *aSendBuffer,
155                                      const void              *aData,
156                                      size_t                   aLength,
157                                      size_t                  *aWritten,
158                                      uint32_t                 aFlags);
159 
160 /**
161  * Performs circular-send-buffer-specific handling in the otTcpForwardProgress
162  * callback.
163  *
164  * The application is expected to install an otTcpForwardProgress() callback on
165  * the otTcpEndpoint, and call this function at the start of the callback
166  * function for circular-send-buffer-specific processing.
167  *
168  * In the callback function, the application can determine the amount of free
169  * space in the circular send buffer by calling
170  * otTcpCircularSendBufferFreeSpace(), or by comparing @p aInSendBuffer with
171  * the send buffer's capacity, chosen by the user when calling
172  * otTcpCircularSendBufferInitialize().
173  *
174  * @param[in]  aSendBuffer    A pointer to the TCP circular send buffer for the endpoint for which
175  *                            otTcpForwardProgress() was invoked.
176  * @param[in]  aInSendBuffer  Value of @p aInSendBuffer passed to the otTcpForwardProgress() callback.
177  */
178 void otTcpCircularSendBufferHandleForwardProgress(otTcpCircularSendBuffer *aSendBuffer, size_t aInSendBuffer);
179 
180 /**
181  * Returns the amount of free space in the TCP circular send buffer.
182  *
183  * This operation will always succeed.
184  *
185  * @param[in]  aSendBuffer  A pointer to the TCP circular send buffer whose amount of free space to return.
186  *
187  * @returns The amount of free space in the send buffer.
188  */
189 size_t otTcpCircularSendBufferGetFreeSpace(const otTcpCircularSendBuffer *aSendBuffer);
190 
191 /**
192  * Forcibly discards all data in the circular send buffer.
193  *
194  * The application is expected to call this function when a TCP connection is
195  * terminated unceremoniously (e.g., if the application calls
196  * otTcpEndpointAbort() or is informed of a reset connection via the
197  * otTcpConnectionLost() callback).
198  *
199  * Calling this function on a nonempty TCP circular send buffer attached to a
200  * TCP endpoint results in undefined behavior.
201  *
202  * @param[in]  aSendBuffer  The TCP circular send buffer whose data to discard.
203  */
204 void otTcpCircularSendBufferForceDiscardAll(otTcpCircularSendBuffer *aSendBuffer);
205 
206 /**
207  * Deinitializes a TCP circular send buffer, detaching it if attached.
208  *
209  * If the TCP circular send buffer is not empty, then this operation will fail.
210  *
211  * @param[in]  aSendBuffer  The TCP circular send buffer to deinitialize.
212  *
213  * @retval OT_ERROR_NONE    Successfully deinitialize the TCP circular send buffer.
214  * @retval OT_ERROR_BUSY    Circular buffer contains data and cannot be deinitialized.
215  */
216 otError otTcpCircularSendBufferDeinitialize(otTcpCircularSendBuffer *aSendBuffer);
217 
218 /**
219  * Context structure to use with mbedtls_ssl_set_bio.
220  */
221 typedef struct otTcpEndpointAndCircularSendBuffer
222 {
223     otTcpEndpoint           *mEndpoint;
224     otTcpCircularSendBuffer *mSendBuffer;
225 } otTcpEndpointAndCircularSendBuffer;
226 
227 /**
228  * Non-blocking send callback to pass to mbedtls_ssl_set_bio.
229  *
230  * @param[in]  aCtx  A pointer to an otTcpEndpointAndCircularSendBuffer.
231  * @param[in]  aBuf  The data to add to the send buffer.
232  * @param[in]  aLen  The amount of data to add to the send buffer.
233  *
234  * @returns The number of bytes sent, or an mbedtls error code.
235  */
236 int otTcpMbedTlsSslSendCallback(void *aCtx, const unsigned char *aBuf, size_t aLen);
237 
238 /**
239  * Non-blocking receive callback to pass to mbedtls_ssl_set_bio.
240  *
241  * @param[in]   aCtx  A pointer to an otTcpEndpointAndCircularSendBuffer.
242  * @param[out]  aBuf  The buffer into which to receive data.
243  * @param[in]   aLen  The maximum amount of data that can be received.
244  *
245  * @returns The number of bytes received, or an mbedtls error code.
246  */
247 int otTcpMbedTlsSslRecvCallback(void *aCtx, unsigned char *aBuf, size_t aLen);
248 
249 /**
250  * @}
251  *
252  */
253 
254 #ifdef __cplusplus
255 } // extern "C"
256 #endif
257 
258 #endif // OPENTHREAD_TCP_EXT_H_
259