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