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