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 10 : CHIP_ERROR TCPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, bool reuseAddr)
47 : {
48 10 : VerifyOrReturnError(mState == State::kReady, CHIP_ERROR_INCORRECT_STATE);
49 9 : CHIP_ERROR res = CHIP_NO_ERROR;
50 :
51 9 : if (addr != IPAddress::Any && addr.Type() != IPAddressType::kAny && addr.Type() != addrType)
52 : {
53 2 : return INET_ERROR_WRONG_ADDRESS_TYPE;
54 : }
55 :
56 7 : res = BindImpl(addrType, addr, port, reuseAddr);
57 :
58 7 : if (res == CHIP_NO_ERROR)
59 : {
60 6 : mState = State::kBound;
61 : }
62 :
63 7 : return res;
64 : }
65 :
66 7 : CHIP_ERROR TCPEndPoint::Listen(uint16_t backlog)
67 : {
68 7 : VerifyOrReturnError(mState == State::kBound, CHIP_ERROR_INCORRECT_STATE);
69 6 : CHIP_ERROR res = CHIP_NO_ERROR;
70 :
71 6 : res = ListenImpl(backlog);
72 :
73 6 : if (res == CHIP_NO_ERROR)
74 : {
75 : // Once Listening, bump the reference count. The corresponding call to Release() will happen in DoClose().
76 6 : Retain();
77 6 : mState = State::kListening;
78 : }
79 :
80 6 : return res;
81 : }
82 :
83 4 : CHIP_ERROR TCPEndPoint::Connect(const IPAddress & addr, uint16_t port, InterfaceId intfId)
84 : {
85 4 : VerifyOrReturnError(mState == State::kReady || mState == State::kBound, CHIP_ERROR_INCORRECT_STATE);
86 3 : CHIP_ERROR res = CHIP_NO_ERROR;
87 :
88 3 : ReturnErrorOnFailure(ConnectImpl(addr, port, intfId));
89 :
90 3 : StartConnectTimerIfSet();
91 :
92 3 : return res;
93 : }
94 :
95 4 : CHIP_ERROR TCPEndPoint::Send(System::PacketBufferHandle && data, bool push)
96 : {
97 4 : VerifyOrReturnError(mState == State::kConnected || mState == State::kReceiveShutdown, CHIP_ERROR_INCORRECT_STATE);
98 3 : CHIP_ERROR res = CHIP_NO_ERROR;
99 :
100 3 : bool queueWasEmpty = mSendQueue.IsNull();
101 3 : if (queueWasEmpty)
102 : {
103 3 : mSendQueue = std::move(data);
104 : }
105 : else
106 : {
107 0 : mSendQueue->AddToEnd(std::move(data));
108 : }
109 :
110 3 : ReturnErrorOnFailure(SendQueuedImpl(queueWasEmpty));
111 :
112 3 : if (push)
113 : {
114 3 : res = DriveSending();
115 : }
116 :
117 3 : 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 : uint32_t TCPEndPoint::PendingSendLength()
130 : {
131 0 : if (!mSendQueue.IsNull())
132 : {
133 0 : return mSendQueue->TotalLength();
134 : }
135 0 : return 0;
136 : }
137 :
138 1 : uint32_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 12 : void TCPEndPoint::Close()
166 : {
167 : // Clear the receive queue.
168 12 : mRcvQueue = nullptr;
169 :
170 : // Suppress closing callbacks, since the application explicitly called Close().
171 12 : OnConnectionClosed = nullptr;
172 12 : OnPeerClose = nullptr;
173 12 : OnConnectComplete = nullptr;
174 :
175 : // Perform a graceful close.
176 12 : DoClose(CHIP_NO_ERROR, true);
177 12 : }
178 :
179 0 : void TCPEndPoint::Abort()
180 : {
181 : // Suppress closing callbacks, since the application explicitly called Abort().
182 0 : OnConnectionClosed = nullptr;
183 0 : OnPeerClose = nullptr;
184 0 : OnConnectComplete = nullptr;
185 :
186 0 : DoClose(CHIP_ERROR_CONNECTION_ABORTED, true);
187 0 : }
188 :
189 12 : void TCPEndPoint::Free()
190 : {
191 : // Ensure no callbacks to the app after this point.
192 12 : OnAcceptError = nullptr;
193 12 : OnConnectComplete = nullptr;
194 12 : OnConnectionReceived = nullptr;
195 12 : OnConnectionClosed = nullptr;
196 12 : OnPeerClose = nullptr;
197 12 : OnDataReceived = nullptr;
198 12 : OnDataSent = nullptr;
199 :
200 : // Ensure the end point is Closed or Closing.
201 12 : Close();
202 :
203 : // Release the Retain() that happened when the end point was allocated.
204 12 : Release();
205 12 : }
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 3 : void TCPEndPoint::StartConnectTimerIfSet()
287 : {
288 3 : if (mConnectTimeoutMsecs > 0)
289 : {
290 0 : GetSystemLayer().StartTimer(System::Clock::Milliseconds32(mConnectTimeoutMsecs), TCPConnectTimeoutHandler, this);
291 : }
292 3 : }
293 :
294 15 : void TCPEndPoint::StopConnectTimer()
295 : {
296 15 : GetSystemLayer().CancelTimer(TCPConnectTimeoutHandler, this);
297 15 : }
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 64 : bool TCPEndPoint::IsConnected(State state)
309 : {
310 64 : return state == State::kConnected || state == State::kSendShutdown || state == State::kReceiveShutdown ||
311 64 : state == State::kClosing;
312 : }
313 :
314 3 : CHIP_ERROR TCPEndPoint::DriveSending()
315 : {
316 3 : CHIP_ERROR err = DriveSendingImpl();
317 :
318 3 : if (err != CHIP_NO_ERROR)
319 : {
320 0 : DoClose(err, false);
321 : }
322 :
323 3 : CHIP_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
324 :
325 3 : return err;
326 : }
327 :
328 6 : 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 6 : 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 3 : uint16_t ackLength = mRcvQueue->TotalLength();
337 3 : CHIP_ERROR err = OnDataReceived(this, std::move(mRcvQueue));
338 3 : if (err != CHIP_NO_ERROR)
339 : {
340 0 : DoClose(err, false);
341 0 : return;
342 : }
343 3 : 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 6 : if (mState == State::kClosing && mRcvQueue.IsNull())
349 : {
350 0 : DoClose(CHIP_NO_ERROR, false);
351 : }
352 : }
353 :
354 3 : void TCPEndPoint::HandleConnectComplete(CHIP_ERROR err)
355 : {
356 : // If the connect succeeded enter the Connected state and call the app's callback.
357 3 : if (err == CHIP_NO_ERROR)
358 : {
359 : // Stop the TCP Connect timer in case it is still running.
360 3 : StopConnectTimer();
361 :
362 : // Mark the connection as being active.
363 3 : MarkActive();
364 :
365 3 : mState = State::kConnected;
366 :
367 3 : HandleConnectCompleteImpl();
368 :
369 3 : if (OnConnectComplete != nullptr)
370 : {
371 3 : 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 3 : }
381 :
382 12 : void TCPEndPoint::DoClose(CHIP_ERROR err, bool suppressCallback)
383 : {
384 12 : 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 12 : if (IsConnected() && err == CHIP_NO_ERROR && (!mSendQueue.IsNull() || !mRcvQueue.IsNull()))
392 : {
393 0 : mState = State::kClosing;
394 : }
395 : else
396 : {
397 12 : mState = State::kClosed;
398 : }
399 :
400 12 : if (oldState != State::kClosed)
401 : {
402 : // Stop the Connect timer in case it is still running.
403 12 : StopConnectTimer();
404 : }
405 :
406 : // If not making a state transition, return immediately.
407 12 : if (mState == oldState)
408 : {
409 0 : return;
410 : }
411 :
412 12 : DoCloseImpl(err, oldState);
413 :
414 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
415 : // Stop the TCP UserTimeout timer if it is running.
416 12 : StopTCPUserTimeoutTimer();
417 : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
418 :
419 : // If entering the Closed state...
420 12 : if (mState == State::kClosed)
421 : {
422 : // Clear clear the send and receive queues.
423 12 : mSendQueue = nullptr;
424 12 : mRcvQueue = nullptr;
425 :
426 : // Call the appropriate app callback if allowed.
427 12 : if (!suppressCallback)
428 : {
429 0 : if (oldState == State::kConnecting)
430 : {
431 0 : if (OnConnectComplete != nullptr)
432 : {
433 0 : OnConnectComplete(this, err);
434 : }
435 : }
436 0 : else if ((oldState == State::kConnected || oldState == State::kSendShutdown || oldState == State::kReceiveShutdown ||
437 0 : oldState == State::kClosing) &&
438 0 : OnConnectionClosed != nullptr)
439 : {
440 0 : 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 12 : if (oldState != State::kReady && oldState != State::kBound)
446 : {
447 12 : Release();
448 : }
449 : }
450 : }
451 :
452 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
453 :
454 3 : void TCPEndPoint::ScheduleNextTCPUserTimeoutPoll(uint32_t aTimeOut)
455 : {
456 3 : GetSystemLayer().StartTimer(System::Clock::Milliseconds32(aTimeOut), TCPUserTimeoutHandler, this);
457 3 : }
458 :
459 3 : void TCPEndPoint::StartTCPUserTimeoutTimer()
460 : {
461 3 : ScheduleNextTCPUserTimeoutPoll(mUserTimeoutMillis);
462 3 : mUserTimeoutTimerRunning = true;
463 3 : }
464 :
465 18 : void TCPEndPoint::StopTCPUserTimeoutTimer()
466 : {
467 18 : GetSystemLayer().CancelTimer(TCPUserTimeoutHandler, this);
468 18 : mUserTimeoutTimerRunning = false;
469 18 : }
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
|