1 /*
2  *  Copyright (c) 2021, 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  *   This file implements TCP/IPv6 sockets.
32  */
33 
34 #include "openthread-core-config.h"
35 
36 #if OPENTHREAD_CONFIG_TCP_ENABLE
37 
38 #include "tcp6.hpp"
39 
40 #include "common/code_utils.hpp"
41 #include "common/error.hpp"
42 #include "common/instance.hpp"
43 #include "common/logging.hpp"
44 #include "net/ip6.hpp"
45 
46 namespace ot {
47 namespace Ip6 {
48 
Tcp(Instance & aInstance)49 Tcp::Tcp(Instance &aInstance)
50     : InstanceLocator(aInstance)
51     , mTimer(aInstance, Tcp::HandleTimer)
52     , mEphemeralPort(kDynamicPortMin)
53 {
54     OT_UNUSED_VARIABLE(mEphemeralPort);
55 }
56 
Initialize(Instance & aInstance,otTcpEndpointInitializeArgs & aArgs)57 Error Tcp::Endpoint::Initialize(Instance &aInstance, otTcpEndpointInitializeArgs &aArgs)
58 {
59     Error error;
60 
61     SuccessOrExit(error = aInstance.Get<Tcp>().mEndpoints.Add(*this));
62 
63     mContext                  = aArgs.mContext;
64     mEstablishedCallback      = aArgs.mEstablishedCallback;
65     mSendDoneCallback         = aArgs.mSendDoneCallback;
66     mSendReadyCallback        = aArgs.mSendReadyCallback;
67     mReceiveAvailableCallback = aArgs.mReceiveAvailableCallback;
68     mDisconnectedCallback     = aArgs.mDisconnectedCallback;
69 
70     mInstance = &aInstance;
71 
72     memset(mTimers, 0x00, sizeof(mTimers));
73 
74 exit:
75     return error;
76 }
77 
GetInstance(void)78 Instance &Tcp::Endpoint::GetInstance(void)
79 {
80     return *static_cast<Instance *>(mInstance);
81 }
82 
GetLocalAddress(void) const83 const SockAddr &Tcp::Endpoint::GetLocalAddress(void) const
84 {
85     static otSockAddr temp;
86     return *static_cast<SockAddr *>(&temp);
87 }
88 
GetPeerAddress(void) const89 const SockAddr &Tcp::Endpoint::GetPeerAddress(void) const
90 {
91     static otSockAddr temp;
92     return *static_cast<SockAddr *>(&temp);
93 }
94 
Bind(const SockAddr & aSockName)95 Error Tcp::Endpoint::Bind(const SockAddr &aSockName)
96 {
97     OT_UNUSED_VARIABLE(aSockName);
98 
99     return kErrorNotImplemented;
100 }
101 
Connect(const SockAddr & aSockName,uint32_t aFlags)102 Error Tcp::Endpoint::Connect(const SockAddr &aSockName, uint32_t aFlags)
103 {
104     OT_UNUSED_VARIABLE(aSockName);
105     OT_UNUSED_VARIABLE(aFlags);
106 
107     return kErrorNotImplemented;
108 }
109 
SendByReference(otLinkedBuffer & aBuffer,uint32_t aFlags)110 Error Tcp::Endpoint::SendByReference(otLinkedBuffer &aBuffer, uint32_t aFlags)
111 {
112     OT_UNUSED_VARIABLE(aBuffer);
113     OT_UNUSED_VARIABLE(aFlags);
114 
115     return kErrorNotImplemented;
116 }
117 
SendByExtension(size_t aNumBytes,uint32_t aFlags)118 Error Tcp::Endpoint::SendByExtension(size_t aNumBytes, uint32_t aFlags)
119 {
120     OT_UNUSED_VARIABLE(aNumBytes);
121     OT_UNUSED_VARIABLE(aFlags);
122 
123     return kErrorNotImplemented;
124 }
125 
ReceiveByReference(const otLinkedBuffer * & aBuffer) const126 Error Tcp::Endpoint::ReceiveByReference(const otLinkedBuffer *&aBuffer) const
127 {
128     OT_UNUSED_VARIABLE(aBuffer);
129 
130     return kErrorNotImplemented;
131 }
132 
ReceiveContiguify(void)133 Error Tcp::Endpoint::ReceiveContiguify(void)
134 {
135     return kErrorNotImplemented;
136 }
137 
CommitReceive(size_t aNumBytes,uint32_t aFlags)138 Error Tcp::Endpoint::CommitReceive(size_t aNumBytes, uint32_t aFlags)
139 {
140     OT_UNUSED_VARIABLE(aNumBytes);
141     OT_UNUSED_VARIABLE(aFlags);
142 
143     return kErrorNotImplemented;
144 }
145 
SendEndOfStream(void)146 Error Tcp::Endpoint::SendEndOfStream(void)
147 {
148     return kErrorNotImplemented;
149 }
150 
Abort(void)151 Error Tcp::Endpoint::Abort(void)
152 {
153     return kErrorNotImplemented;
154 }
155 
Deinitialize(void)156 Error Tcp::Endpoint::Deinitialize(void)
157 {
158     Error error;
159 
160     Tcp &tcp = GetInstance().Get<Tcp>();
161 
162     SuccessOrExit(error = tcp.mEndpoints.Remove(*this));
163     SetNext(nullptr);
164 
165 exit:
166     return error;
167 }
168 
TimerFlagToIndex(uint8_t aTimerFlag)169 uint8_t Tcp::Endpoint::TimerFlagToIndex(uint8_t aTimerFlag)
170 {
171     OT_UNUSED_VARIABLE(aTimerFlag);
172     /*
173      * TODO: Convert from the timer flag provided by TCPlp to the index in
174      * our timers array.
175      */
176     return 0;
177 }
178 
IsTimerActive(uint8_t aTimerIndex)179 bool Tcp::Endpoint::IsTimerActive(uint8_t aTimerIndex)
180 {
181     OT_UNUSED_VARIABLE(aTimerIndex);
182     /* TODO: Check whether TCPlp has marked this timer as active. */
183     return false;
184 }
185 
SetTimer(uint8_t aTimerFlag,uint32_t aDelay)186 void Tcp::Endpoint::SetTimer(uint8_t aTimerFlag, uint32_t aDelay)
187 {
188     /*
189      * TCPlp has already set the flag for this timer to record that it's
190      * running. So, all that's left to do is record the expiry time and
191      * (re)set the main timer as appropriate.
192      */
193 
194     TimeMilli now         = TimerMilli::GetNow();
195     TimeMilli newFireTime = now + aDelay;
196     uint8_t   timerIndex  = TimerFlagToIndex(aTimerFlag);
197 
198     mTimers[timerIndex] = newFireTime.GetValue();
199     otLogDebgTcp("Endpoint %p set timer %u to %u ms", static_cast<void *>(this), static_cast<unsigned int>(timerIndex),
200                  static_cast<unsigned int>(aDelay));
201 
202     GetInstance().Get<Tcp>().mTimer.FireAtIfEarlier(newFireTime);
203 }
204 
CancelTimer(uint8_t aTimerFlag)205 void Tcp::Endpoint::CancelTimer(uint8_t aTimerFlag)
206 {
207     /*
208      * TCPlp has already cleared the timer flag before calling this. Since the
209      * main timer's callback properly handles the case where no timers are
210      * actually due, there's actually no work to be done here.
211      */
212 
213     OT_UNUSED_VARIABLE(aTimerFlag);
214 
215     otLogDebgTcp("Endpoint %p cancelled timer %u", static_cast<void *>(this),
216                  static_cast<unsigned int>(TimerFlagToIndex(aTimerFlag)));
217 }
218 
FirePendingTimers(TimeMilli aNow,bool & aHasFutureTimer,TimeMilli & aEarliestFutureExpiry)219 bool Tcp::Endpoint::FirePendingTimers(TimeMilli aNow, bool &aHasFutureTimer, TimeMilli &aEarliestFutureExpiry)
220 {
221     /*
222      * NOTE: Firing a timer might potentially activate/deactivate other timers.
223      * If timers x and y expire at the same time, but the callback for timer x
224      * (for x < y) cancels or postpones timer y, should timer y's callback be
225      * called? Our answer is no, since timer x's callback has updated the
226      * TCP stack's state in such a way that it no longer expects timer y's
227      * callback to to be called. Because the TCP stack thinks that timer y
228      * has been cancelled, calling timer y's callback could potentially cause
229      * problems.
230      *
231      * If the timer callbacks set other timers, then they may not be taken
232      * into account when setting aEarliestFutureExpiry. But mTimer's expiry
233      * time will be updated by those, so we can just compare against mTimer's
234      * expiry time when resetting mTimer.
235      */
236     for (uint8_t timerIndex = 0; timerIndex != kNumTimers; timerIndex++)
237     {
238         if (IsTimerActive(timerIndex))
239         {
240             TimeMilli expiry(mTimers[timerIndex]);
241 
242             if (expiry <= aNow)
243             {
244                 /* TODO: Call TCPlp's callback for this timer. */
245                 /* If a user callback is called, then return true. */
246             }
247             else
248             {
249                 aHasFutureTimer       = true;
250                 aEarliestFutureExpiry = OT_MIN(aEarliestFutureExpiry, expiry);
251             }
252         }
253     }
254 
255     return false;
256 }
257 
Initialize(Instance & aInstance,otTcpListenerInitializeArgs & aArgs)258 Error Tcp::Listener::Initialize(Instance &aInstance, otTcpListenerInitializeArgs &aArgs)
259 {
260     Error error;
261 
262     SuccessOrExit(error = aInstance.Get<Tcp>().mListeners.Add(*this));
263 
264     mContext             = aArgs.mContext;
265     mAcceptReadyCallback = aArgs.mAcceptReadyCallback;
266     mAcceptDoneCallback  = aArgs.mAcceptDoneCallback;
267 
268     mInstance = &aInstance;
269 
270 exit:
271     return error;
272 }
273 
GetInstance(void)274 Instance &Tcp::Listener::GetInstance(void)
275 {
276     return *static_cast<Instance *>(mInstance);
277 }
278 
Listen(const SockAddr & aSockName)279 Error Tcp::Listener::Listen(const SockAddr &aSockName)
280 {
281     OT_UNUSED_VARIABLE(aSockName);
282 
283     return kErrorNotImplemented;
284 }
285 
StopListening(void)286 Error Tcp::Listener::StopListening(void)
287 {
288     return kErrorNotImplemented;
289 }
290 
Deinitialize(void)291 Error Tcp::Listener::Deinitialize(void)
292 {
293     Error error;
294 
295     Tcp &tcp = GetInstance().Get<Tcp>();
296 
297     SuccessOrExit(error = tcp.mListeners.Remove(*this));
298     SetNext(nullptr);
299 
300 exit:
301     return error;
302 }
303 
HandleMessage(ot::Ip6::Header & aIp6Header,Message & aMessage,MessageInfo & aMessageInfo)304 Error Tcp::HandleMessage(ot::Ip6::Header &aIp6Header, Message &aMessage, MessageInfo &aMessageInfo)
305 {
306     OT_UNUSED_VARIABLE(aIp6Header);
307     OT_UNUSED_VARIABLE(aMessage);
308     OT_UNUSED_VARIABLE(aMessageInfo);
309 
310     Error error = kErrorNotImplemented;
311 
312     for (Endpoint &active : mEndpoints)
313     {
314         OT_UNUSED_VARIABLE(active);
315     }
316 
317     for (Listener &passive : mListeners)
318     {
319         OT_UNUSED_VARIABLE(passive);
320     }
321 
322     return error;
323 }
324 
HandleTimer(Timer & aTimer)325 void Tcp::HandleTimer(Timer &aTimer)
326 {
327     OT_ASSERT(&aTimer == &aTimer.GetInstance().Get<Tcp>().mTimer);
328     otLogDebgTcp("Main TCP timer expired");
329     aTimer.GetInstance().Get<Tcp>().ProcessTimers();
330 }
331 
ProcessTimers()332 void Tcp::ProcessTimers()
333 {
334     TimeMilli now = TimerMilli::GetNow();
335     bool      pendingTimer;
336     TimeMilli earliestPendingTimerExpiry;
337 
338     OT_ASSERT(!mTimer.IsRunning());
339 
340     /*
341      * The timer callbacks could potentially set/reset/cancel timers.
342      * Importantly, Endpoint::SetTimer and Endpoint::CancelTimer do not call
343      * this function to recompute the timer. If they did, we'd have a
344      * re-entrancy problem, where the callbacks called in this function could
345      * wind up re-entering this function in a nested call frame.
346      *
347      * In general, calling this function from Endpoint::SetTimer and
348      * Endpoint::CancelTimer could be inefficient, since those functions are
349      * called multiple times on each received TCP segment. If we want to
350      * prevent the main timer from firing except when an actual TCP timer
351      * expires, a better alternative is to reset the main timer in
352      * HandleMessage, right before processing signals. That would achieve that
353      * objective while avoiding re-entrancy issues altogether.
354      */
355 restart:
356     pendingTimer               = false;
357     earliestPendingTimerExpiry = now.GetDistantFuture();
358 
359     for (Endpoint &endpoint : mEndpoints)
360     {
361         if (endpoint.FirePendingTimers(now, pendingTimer, earliestPendingTimerExpiry))
362         {
363             /*
364              * If a non-OpenThread callback is called --- which, in practice,
365              * happens if the connection times out and the user-defined
366              * connection lost callback is called --- then we might have to
367              * start over. The reason is that the user might deinitialize
368              * endpoints, changing the structure of the linked list. For
369              * example, if the user deinitializes both this endpoint and the
370              * next one in the linked list, then we can't continue traversing
371              * the linked list.
372              */
373             goto restart;
374         }
375     }
376 
377     if (pendingTimer)
378     {
379         /*
380          * We need to use Timer::FireAtIfEarlier instead of timer::FireAt
381          * because one of the earlier callbacks might have set TCP timers,
382          * in which case `mTimer` would have been set to the earliest of those
383          * timers.
384          */
385         mTimer.FireAtIfEarlier(earliestPendingTimerExpiry);
386         otLogDebgTcp("Reset main TCP timer to %u ms", static_cast<unsigned int>(earliestPendingTimerExpiry - now));
387     }
388     else
389     {
390         otLogDebgTcp("Did not reset main TCP timer");
391     }
392 }
393 
394 } // namespace Ip6
395 } // namespace ot
396 
397 #endif // OPENTHREAD_CONFIG_TCP_ENABLE
398