Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2013-2018 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file implements the <tt>Inet::TCPEndPoint</tt> class,
22 : * where the CHIP Inet Layer encapsulates methods for interacting
23 : * with TCP transport endpoints (SOCK_DGRAM sockets on Linux and
24 : * BSD-derived systems) or LwIP TCP protocol control blocks, as
25 : * the system is configured accordingly.
26 : *
27 : */
28 :
29 : #include <inet/TCPEndPoint.h>
30 :
31 : #include <inet/InetFaultInjection.h>
32 : #include <inet/arpa-inet-compatibility.h>
33 :
34 : #include <lib/support/CodeUtils.h>
35 : #include <lib/support/SafeInt.h>
36 : #include <lib/support/logging/CHIPLogging.h>
37 : #include <system/SystemFaultInjection.h>
38 :
39 : #include <stdio.h>
40 : #include <string.h>
41 : #include <utility>
42 :
43 : namespace chip {
44 : namespace Inet {
45 :
46 18 : CHIP_ERROR TCPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, bool reuseAddr)
47 : {
48 18 : VerifyOrReturnError(mState == State::kReady, CHIP_ERROR_INCORRECT_STATE);
49 17 : CHIP_ERROR res = CHIP_NO_ERROR;
50 :
51 17 : if (addr != IPAddress::Any && addr.Type() != IPAddressType::kAny && addr.Type() != addrType)
52 : {
53 2 : return INET_ERROR_WRONG_ADDRESS_TYPE;
54 : }
55 :
56 15 : res = BindImpl(addrType, addr, port, reuseAddr);
57 :
58 15 : if (res == CHIP_NO_ERROR)
59 : {
60 14 : mState = State::kBound;
61 : }
62 :
63 15 : return res;
64 : }
65 :
66 15 : CHIP_ERROR TCPEndPoint::Listen(uint16_t backlog)
67 : {
68 15 : VerifyOrReturnError(mState == State::kBound, CHIP_ERROR_INCORRECT_STATE);
69 14 : CHIP_ERROR res = CHIP_NO_ERROR;
70 :
71 14 : res = ListenImpl(backlog);
72 :
73 14 : if (res == CHIP_NO_ERROR)
74 : {
75 : // Once Listening, bump the reference count. The corresponding call to Release() will happen in DoClose().
76 14 : Retain();
77 14 : mState = State::kListening;
78 : }
79 :
80 14 : return res;
81 : }
82 :
83 11 : CHIP_ERROR TCPEndPoint::Connect(const IPAddress & addr, uint16_t port, InterfaceId intfId)
84 : {
85 11 : VerifyOrReturnError(mState == State::kReady || mState == State::kBound, CHIP_ERROR_INCORRECT_STATE);
86 10 : CHIP_ERROR res = CHIP_NO_ERROR;
87 :
88 10 : ReturnErrorOnFailure(ConnectImpl(addr, port, intfId));
89 :
90 10 : StartConnectTimerIfSet();
91 :
92 10 : return res;
93 : }
94 :
95 6 : CHIP_ERROR TCPEndPoint::Send(System::PacketBufferHandle && data, bool push)
96 : {
97 6 : VerifyOrReturnError(mState == State::kConnected || mState == State::kReceiveShutdown, CHIP_ERROR_INCORRECT_STATE);
98 5 : CHIP_ERROR res = CHIP_NO_ERROR;
99 :
100 5 : bool queueWasEmpty = mSendQueue.IsNull();
101 5 : if (queueWasEmpty)
102 : {
103 5 : mSendQueue = std::move(data);
104 : }
105 : else
106 : {
107 0 : mSendQueue->AddToEnd(std::move(data));
108 : }
109 :
110 5 : ReturnErrorOnFailure(SendQueuedImpl(queueWasEmpty));
111 :
112 5 : if (push)
113 : {
114 5 : res = DriveSending();
115 : }
116 :
117 5 : return res;
118 : }
119 :
120 0 : CHIP_ERROR TCPEndPoint::SetReceivedDataForTesting(System::PacketBufferHandle && data)
121 : {
122 0 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
123 :
124 0 : mRcvQueue = std::move(data);
125 :
126 0 : return CHIP_NO_ERROR;
127 : }
128 :
129 0 : size_t TCPEndPoint::PendingSendLength()
130 : {
131 0 : if (!mSendQueue.IsNull())
132 : {
133 0 : return mSendQueue->TotalLength();
134 : }
135 0 : return 0;
136 : }
137 :
138 1 : size_t TCPEndPoint::PendingReceiveLength()
139 : {
140 1 : if (!mRcvQueue.IsNull())
141 : {
142 0 : return mRcvQueue->TotalLength();
143 : }
144 1 : return 0;
145 : }
146 :
147 0 : void TCPEndPoint::Shutdown()
148 : {
149 0 : VerifyOrReturn(IsConnected());
150 :
151 : // If fully connected, enter the SendShutdown state.
152 0 : if (mState == State::kConnected)
153 : {
154 0 : mState = State::kSendShutdown;
155 0 : DriveSending();
156 : }
157 :
158 : // Otherwise, if the peer has already closed their end of the connection,
159 0 : else if (mState == State::kReceiveShutdown)
160 : {
161 0 : DoClose(CHIP_NO_ERROR, false);
162 : }
163 : }
164 :
165 44 : void TCPEndPoint::Close()
166 : {
167 : // Clear the receive queue.
168 44 : mRcvQueue = nullptr;
169 :
170 : // Suppress closing callbacks, since the application explicitly called Close().
171 44 : OnConnectionClosed = nullptr;
172 44 : OnPeerClose = nullptr;
173 44 : OnConnectComplete = nullptr;
174 :
175 : // Perform a graceful close.
176 44 : DoClose(CHIP_NO_ERROR, true);
177 44 : }
178 :
179 10 : void TCPEndPoint::Abort()
180 : {
181 : // Suppress closing callbacks, since the application explicitly called Abort().
182 10 : OnConnectionClosed = nullptr;
183 10 : OnPeerClose = nullptr;
184 10 : OnConnectComplete = nullptr;
185 :
186 10 : DoClose(CHIP_ERROR_CONNECTION_ABORTED, true);
187 10 : }
188 :
189 34 : void TCPEndPoint::Free()
190 : {
191 : // Ensure no callbacks to the app after this point.
192 34 : OnAcceptError = nullptr;
193 34 : OnConnectComplete = nullptr;
194 34 : OnConnectionReceived = nullptr;
195 34 : OnConnectionClosed = nullptr;
196 34 : OnPeerClose = nullptr;
197 34 : OnDataReceived = nullptr;
198 34 : OnDataSent = nullptr;
199 :
200 : // Ensure the end point is Closed or Closing.
201 34 : Close();
202 :
203 : // Release the Retain() that happened when the end point was allocated.
204 34 : Release();
205 34 : }
206 :
207 : #if INET_TCP_IDLE_CHECK_INTERVAL > 0
208 0 : void TCPEndPoint::SetIdleTimeout(uint32_t timeoutMS)
209 : {
210 0 : uint32_t newIdleTimeout = (timeoutMS + (INET_TCP_IDLE_CHECK_INTERVAL - 1)) / INET_TCP_IDLE_CHECK_INTERVAL;
211 0 : bool isIdleTimerRunning = IsIdleTimerRunning(GetEndPointManager());
212 :
213 0 : if (newIdleTimeout > UINT16_MAX)
214 : {
215 0 : newIdleTimeout = UINT16_MAX;
216 : }
217 0 : mIdleTimeout = mRemainingIdleTime = static_cast<uint16_t>(newIdleTimeout);
218 :
219 0 : if (!isIdleTimerRunning && mIdleTimeout)
220 : {
221 0 : GetSystemLayer().StartTimer(System::Clock::Milliseconds32(INET_TCP_IDLE_CHECK_INTERVAL), HandleIdleTimer,
222 0 : &GetEndPointManager());
223 : }
224 0 : }
225 :
226 : // static
227 0 : void TCPEndPoint::HandleIdleTimer(chip::System::Layer * aSystemLayer, void * aAppState)
228 : {
229 0 : auto & endPointManager = *reinterpret_cast<EndPointManager<TCPEndPoint> *>(aAppState);
230 0 : bool lTimerRequired = IsIdleTimerRunning(endPointManager);
231 :
232 0 : endPointManager.ForEachEndPoint([](TCPEndPoint * lEndPoint) -> Loop {
233 0 : if (!lEndPoint->IsConnected())
234 0 : return Loop::Continue;
235 0 : if (lEndPoint->mIdleTimeout == 0)
236 0 : return Loop::Continue;
237 :
238 0 : if (lEndPoint->mRemainingIdleTime == 0)
239 : {
240 0 : lEndPoint->DoClose(INET_ERROR_IDLE_TIMEOUT, false);
241 : }
242 : else
243 : {
244 0 : --lEndPoint->mRemainingIdleTime;
245 : }
246 :
247 0 : return Loop::Continue;
248 : });
249 :
250 0 : if (lTimerRequired)
251 : {
252 0 : aSystemLayer->StartTimer(System::Clock::Milliseconds32(INET_TCP_IDLE_CHECK_INTERVAL), HandleIdleTimer, &endPointManager);
253 : }
254 0 : }
255 :
256 : // static
257 0 : bool TCPEndPoint::IsIdleTimerRunning(EndPointManager<TCPEndPoint> & endPointManager)
258 : {
259 : // See if there are any TCP connections with the idle timer check in use.
260 0 : return Loop::Break == endPointManager.ForEachEndPoint([](TCPEndPoint * lEndPoint) {
261 0 : return (lEndPoint->mIdleTimeout == 0) ? Loop::Continue : Loop::Break;
262 0 : });
263 : }
264 :
265 : #endif // INET_TCP_IDLE_CHECK_INTERVAL > 0
266 :
267 0 : CHIP_ERROR TCPEndPoint::SetUserTimeout(uint32_t userTimeoutMillis)
268 : {
269 0 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
270 0 : CHIP_ERROR res = CHIP_NO_ERROR;
271 :
272 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
273 :
274 : // Store the User timeout configuration if it is being overridden.
275 0 : mUserTimeoutMillis = userTimeoutMillis;
276 :
277 : #else // !INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
278 :
279 : res = SetUserTimeoutImpl(userTimeoutMillis);
280 :
281 : #endif // !INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
282 :
283 0 : return res;
284 : }
285 :
286 10 : void TCPEndPoint::StartConnectTimerIfSet()
287 : {
288 10 : if (mConnectTimeoutMsecs > 0)
289 : {
290 10 : GetSystemLayer().StartTimer(System::Clock::Milliseconds32(mConnectTimeoutMsecs), TCPConnectTimeoutHandler, this);
291 : }
292 10 : }
293 :
294 44 : void TCPEndPoint::StopConnectTimer()
295 : {
296 44 : GetSystemLayer().CancelTimer(TCPConnectTimeoutHandler, this);
297 44 : }
298 :
299 0 : void TCPEndPoint::TCPConnectTimeoutHandler(chip::System::Layer * aSystemLayer, void * aAppState)
300 : {
301 0 : TCPEndPoint * tcpEndPoint = reinterpret_cast<TCPEndPoint *>(aAppState);
302 0 : VerifyOrDie((aSystemLayer != nullptr) && (tcpEndPoint != nullptr));
303 :
304 : // Close Connection as we have timed out and Connect has not returned to stop this timer.
305 0 : tcpEndPoint->DoClose(INET_ERROR_TCP_CONNECT_TIMEOUT, false);
306 0 : }
307 :
308 214 : bool TCPEndPoint::IsConnected(State state)
309 : {
310 214 : return state == State::kConnected || state == State::kSendShutdown || state == State::kReceiveShutdown ||
311 214 : state == State::kClosing;
312 : }
313 :
314 5 : CHIP_ERROR TCPEndPoint::DriveSending()
315 : {
316 5 : CHIP_ERROR err = DriveSendingImpl();
317 :
318 5 : if (err != CHIP_NO_ERROR)
319 : {
320 0 : DoClose(err, false);
321 : }
322 :
323 5 : CHIP_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
324 :
325 5 : return err;
326 : }
327 :
328 14 : void TCPEndPoint::DriveReceiving()
329 : {
330 : // If there's data in the receive queue and the app is ready to receive it then call the app's callback
331 : // with the entire receive queue.
332 14 : if (!mRcvQueue.IsNull() && mReceiveEnabled && OnDataReceived != nullptr)
333 : {
334 : // Acknowledgement is done after handling the buffers to allow the
335 : // application processing to throttle flow.
336 5 : size_t ackLength = mRcvQueue->TotalLength();
337 5 : CHIP_ERROR err = OnDataReceived(this, std::move(mRcvQueue));
338 5 : if (err != CHIP_NO_ERROR)
339 : {
340 0 : DoClose(err, false);
341 0 : return;
342 : }
343 5 : AckReceive(ackLength);
344 : }
345 :
346 : // If the connection is closing, and the receive queue is now empty, call DoClose() to complete
347 : // the process of closing the connection.
348 14 : if (mState == State::kClosing && mRcvQueue.IsNull())
349 : {
350 9 : DoClose(CHIP_NO_ERROR, false);
351 : }
352 : }
353 :
354 10 : void TCPEndPoint::HandleConnectComplete(CHIP_ERROR err)
355 : {
356 : // If the connect succeeded enter the Connected state and call the app's callback.
357 10 : if (err == CHIP_NO_ERROR)
358 : {
359 : // Stop the TCP Connect timer in case it is still running.
360 10 : StopConnectTimer();
361 :
362 : // Mark the connection as being active.
363 10 : MarkActive();
364 :
365 10 : mState = State::kConnected;
366 :
367 10 : HandleConnectCompleteImpl();
368 :
369 10 : if (OnConnectComplete != nullptr)
370 : {
371 10 : OnConnectComplete(this, CHIP_NO_ERROR);
372 : }
373 : }
374 :
375 : // Otherwise, close the connection with an error.
376 : else
377 : {
378 0 : DoClose(err, false);
379 : }
380 10 : }
381 :
382 63 : void TCPEndPoint::DoClose(CHIP_ERROR err, bool suppressCallback)
383 : {
384 63 : State oldState = mState;
385 :
386 : // If in one of the connected states (Connected, LocalShutdown, PeerShutdown or Closing)
387 : // AND this is a graceful close (i.e. not prompted by an error)
388 : // AND there is data waiting to be processed on either the send or receive queues
389 : // ... THEN enter the Closing state, allowing the queued data to drain,
390 : // ... OTHERWISE go straight to the Closed state.
391 63 : if (IsConnected() && err == CHIP_NO_ERROR && (!mSendQueue.IsNull() || !mRcvQueue.IsNull()))
392 : {
393 0 : mState = State::kClosing;
394 : }
395 : else
396 : {
397 63 : mState = State::kClosed;
398 : }
399 :
400 63 : if (oldState != State::kClosed)
401 : {
402 : // Stop the Connect timer in case it is still running.
403 34 : StopConnectTimer();
404 : }
405 :
406 : // If not making a state transition, return immediately.
407 63 : if (mState == oldState)
408 : {
409 29 : return;
410 : }
411 :
412 34 : DoCloseImpl(err, oldState);
413 :
414 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
415 : // Stop the TCP UserTimeout timer if it is running.
416 34 : StopTCPUserTimeoutTimer();
417 : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
418 :
419 : // If entering the Closed state...
420 34 : if (mState == State::kClosed)
421 : {
422 : // Clear clear the send and receive queues.
423 34 : mSendQueue = nullptr;
424 34 : mRcvQueue = nullptr;
425 :
426 : // Call the appropriate app callback if allowed.
427 34 : if (!suppressCallback)
428 : {
429 9 : if (oldState == State::kConnecting)
430 : {
431 0 : if (OnConnectComplete != nullptr)
432 : {
433 0 : OnConnectComplete(this, err);
434 : }
435 : }
436 9 : else if ((oldState == State::kConnected || oldState == State::kSendShutdown || oldState == State::kReceiveShutdown ||
437 9 : oldState == State::kClosing) &&
438 9 : OnConnectionClosed != nullptr)
439 : {
440 9 : OnConnectionClosed(this, err);
441 : }
442 : }
443 :
444 : // Decrement the ref count that was added when the connection started (in Connect()) or listening started (in Listen()).
445 34 : if (oldState != State::kReady && oldState != State::kBound)
446 : {
447 34 : Release();
448 : }
449 : }
450 : }
451 :
452 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
453 :
454 5 : void TCPEndPoint::ScheduleNextTCPUserTimeoutPoll(uint32_t aTimeOut)
455 : {
456 5 : GetSystemLayer().StartTimer(System::Clock::Milliseconds32(aTimeOut), TCPUserTimeoutHandler, this);
457 5 : }
458 :
459 5 : void TCPEndPoint::StartTCPUserTimeoutTimer()
460 : {
461 5 : ScheduleNextTCPUserTimeoutPoll(mUserTimeoutMillis);
462 5 : mUserTimeoutTimerRunning = true;
463 5 : }
464 :
465 48 : void TCPEndPoint::StopTCPUserTimeoutTimer()
466 : {
467 48 : GetSystemLayer().CancelTimer(TCPUserTimeoutHandler, this);
468 48 : mUserTimeoutTimerRunning = false;
469 48 : }
470 :
471 0 : void TCPEndPoint::RestartTCPUserTimeoutTimer()
472 : {
473 0 : StopTCPUserTimeoutTimer();
474 0 : StartTCPUserTimeoutTimer();
475 0 : }
476 :
477 : // static
478 0 : void TCPEndPoint::TCPUserTimeoutHandler(chip::System::Layer * aSystemLayer, void * aAppState)
479 : {
480 0 : TCPEndPoint * tcpEndPoint = reinterpret_cast<TCPEndPoint *>(aAppState);
481 0 : VerifyOrDie((aSystemLayer != nullptr) && (tcpEndPoint != nullptr));
482 0 : tcpEndPoint->TCPUserTimeoutHandler();
483 0 : }
484 :
485 : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
486 :
487 : } // namespace Inet
488 : } // namespace chip
|