Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : * All rights reserved.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * @file
22 : * This file implements the CHIP Transport object that maintains TCP connections
23 : * to peers. Handles both establishing new connections and accepting peer connection
24 : * requests.
25 : */
26 : #include <transport/raw/TCP.h>
27 :
28 : #include <lib/core/CHIPEncoding.h>
29 : #include <lib/support/CodeUtils.h>
30 : #include <lib/support/logging/CHIPLogging.h>
31 : #include <transport/raw/MessageHeader.h>
32 :
33 : #include <inttypes.h>
34 : #include <limits>
35 :
36 : namespace chip {
37 : namespace Transport {
38 : namespace {
39 :
40 : using namespace chip::Encoding;
41 :
42 : // Packets start with a 32-bit size field.
43 : constexpr size_t kPacketSizeBytes = 4;
44 :
45 : static_assert(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve <= UINT32_MAX, "Cast below could truncate the value");
46 : static_assert(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve >= kPacketSizeBytes,
47 : "Large buffer allocation should be large enough to hold the length field");
48 :
49 : constexpr uint32_t kMaxTCPMessageSize =
50 : static_cast<uint32_t>(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve - kPacketSizeBytes);
51 :
52 : constexpr int kListenBacklogSize = 2;
53 :
54 : } // namespace
55 :
56 13 : TCPBase::~TCPBase()
57 : {
58 13 : if (mListenSocket != nullptr)
59 : {
60 : // endpoint is only non null if it is initialized and listening
61 12 : mListenSocket->Free();
62 12 : mListenSocket = nullptr;
63 : }
64 :
65 13 : CloseActiveConnections();
66 13 : }
67 :
68 13 : void TCPBase::CloseActiveConnections()
69 : {
70 65 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
71 : {
72 52 : if (mActiveConnections[i].InUse())
73 : {
74 1 : CloseConnectionInternal(&mActiveConnections[i], CHIP_NO_ERROR, SuppressCallback::Yes);
75 : }
76 : }
77 13 : }
78 :
79 13 : CHIP_ERROR TCPBase::Init(TcpListenParameters & params)
80 : {
81 13 : CHIP_ERROR err = CHIP_NO_ERROR;
82 :
83 13 : VerifyOrExit(mState == TCPState::kNotReady, err = CHIP_ERROR_INCORRECT_STATE);
84 :
85 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
86 13 : err = params.GetEndPointManager()->NewEndPoint(&mListenSocket);
87 : #else
88 : err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
89 : #endif
90 13 : SuccessOrExit(err);
91 :
92 13 : err = mListenSocket->Bind(params.GetAddressType(), Inet::IPAddress::Any, params.GetListenPort(),
93 13 : params.GetInterfaceId().IsPresent());
94 13 : SuccessOrExit(err);
95 :
96 13 : mListenSocket->mAppState = reinterpret_cast<void *>(this);
97 13 : mListenSocket->OnConnectionReceived = HandleIncomingConnection;
98 13 : mListenSocket->OnAcceptError = HandleAcceptError;
99 :
100 13 : mEndpointType = params.GetAddressType();
101 :
102 13 : err = mListenSocket->Listen(kListenBacklogSize);
103 13 : SuccessOrExit(err);
104 :
105 13 : mState = TCPState::kInitialized;
106 :
107 13 : exit:
108 13 : if (err != CHIP_NO_ERROR)
109 : {
110 0 : ChipLogError(Inet, "Failed to initialize TCP transport: %" CHIP_ERROR_FORMAT, err.Format());
111 0 : if (mListenSocket)
112 : {
113 0 : mListenSocket->Free();
114 0 : mListenSocket = nullptr;
115 : }
116 : }
117 :
118 13 : return err;
119 : }
120 :
121 1 : void TCPBase::Close()
122 : {
123 1 : if (mListenSocket)
124 : {
125 1 : mListenSocket->Free();
126 1 : mListenSocket = nullptr;
127 : }
128 1 : mState = TCPState::kNotReady;
129 1 : }
130 :
131 20 : ActiveTCPConnectionState * TCPBase::AllocateConnection()
132 : {
133 30 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
134 : {
135 30 : if (!mActiveConnections[i].InUse())
136 : {
137 20 : return &mActiveConnections[i];
138 : }
139 : }
140 :
141 0 : return nullptr;
142 : }
143 :
144 : // Find an ActiveTCPConnectionState corresponding to a peer address
145 6 : ActiveTCPConnectionState * TCPBase::FindActiveConnection(const PeerAddress & address)
146 : {
147 6 : if (address.GetTransportType() != Type::kTcp)
148 : {
149 0 : return nullptr;
150 : }
151 :
152 18 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
153 : {
154 15 : if (!mActiveConnections[i].IsConnected())
155 : {
156 12 : continue;
157 : }
158 : Inet::IPAddress addr;
159 : uint16_t port;
160 3 : mActiveConnections[i].mEndPoint->GetPeerInfo(&addr, &port);
161 :
162 3 : if ((addr == address.GetIPAddress()) && (port == address.GetPort()))
163 : {
164 3 : return &mActiveConnections[i];
165 : }
166 : }
167 :
168 3 : return nullptr;
169 : }
170 :
171 : // Find the ActiveTCPConnectionState for a given TCPEndPoint
172 11 : ActiveTCPConnectionState * TCPBase::FindActiveConnection(const Inet::TCPEndPoint * endPoint)
173 : {
174 16 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
175 : {
176 16 : if (mActiveConnections[i].mEndPoint == endPoint && mActiveConnections[i].IsConnected())
177 : {
178 11 : return &mActiveConnections[i];
179 : }
180 : }
181 0 : return nullptr;
182 : }
183 :
184 19 : ActiveTCPConnectionState * TCPBase::FindInUseConnection(const Inet::TCPEndPoint * endPoint)
185 : {
186 19 : if (endPoint == nullptr)
187 : {
188 0 : return nullptr;
189 : }
190 :
191 28 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
192 : {
193 28 : if (mActiveConnections[i].mEndPoint == endPoint)
194 : {
195 19 : return &mActiveConnections[i];
196 : }
197 : }
198 0 : return nullptr;
199 : }
200 :
201 5 : CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System::PacketBufferHandle && msgBuf)
202 : {
203 : // Sent buffer data format is:
204 : // - packet size as a uint32_t
205 : // - actual data
206 :
207 5 : VerifyOrReturnError(address.GetTransportType() == Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT);
208 5 : VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE);
209 5 : VerifyOrReturnError(kPacketSizeBytes + msgBuf->DataLength() <= System::PacketBuffer::kLargeBufMaxSizeWithoutReserve,
210 : CHIP_ERROR_INVALID_ARGUMENT);
211 :
212 : static_assert(kPacketSizeBytes <= UINT16_MAX);
213 5 : VerifyOrReturnError(msgBuf->EnsureReservedSize(static_cast<uint16_t>(kPacketSizeBytes)), CHIP_ERROR_NO_MEMORY);
214 :
215 5 : msgBuf->SetStart(msgBuf->Start() - kPacketSizeBytes);
216 :
217 5 : uint8_t * output = msgBuf->Start();
218 5 : LittleEndian::Write32(output, static_cast<uint32_t>(msgBuf->DataLength() - kPacketSizeBytes));
219 :
220 : // Reuse existing connection if one exists, otherwise a new one
221 : // will be established
222 5 : ActiveTCPConnectionState * connection = FindActiveConnection(address);
223 :
224 5 : if (connection != nullptr)
225 : {
226 2 : return connection->mEndPoint->Send(std::move(msgBuf));
227 : }
228 :
229 3 : return SendAfterConnect(address, std::move(msgBuf));
230 : }
231 :
232 10 : CHIP_ERROR TCPBase::StartConnect(const PeerAddress & addr, Transport::AppTCPConnectionCallbackCtxt * appState,
233 : Transport::ActiveTCPConnectionState ** outPeerConnState)
234 : {
235 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
236 10 : ActiveTCPConnectionState * activeConnection = nullptr;
237 10 : Inet::TCPEndPoint * endPoint = nullptr;
238 10 : *outPeerConnState = nullptr;
239 10 : ReturnErrorOnFailure(mListenSocket->GetEndPointManager().NewEndPoint(&endPoint));
240 :
241 0 : auto EndPointDeletor = [](Inet::TCPEndPoint * e) { e->Free(); };
242 10 : std::unique_ptr<Inet::TCPEndPoint, decltype(EndPointDeletor)> endPointHolder(endPoint, EndPointDeletor);
243 :
244 10 : endPoint->mAppState = reinterpret_cast<void *>(this);
245 10 : endPoint->OnConnectComplete = HandleTCPEndPointConnectComplete;
246 10 : endPoint->SetConnectTimeout(mConnectTimeout);
247 :
248 10 : activeConnection = AllocateConnection();
249 10 : VerifyOrReturnError(activeConnection != nullptr, CHIP_ERROR_NO_MEMORY);
250 10 : activeConnection->Init(endPoint, addr);
251 10 : activeConnection->mAppState = appState;
252 10 : activeConnection->mConnectionState = TCPState::kConnecting;
253 : // Set the return value of the peer connection state to the allocated
254 : // connection.
255 10 : *outPeerConnState = activeConnection;
256 :
257 10 : ReturnErrorOnFailure(endPoint->Connect(addr.GetIPAddress(), addr.GetPort(), addr.GetInterface()));
258 :
259 10 : mUsedEndPointCount++;
260 :
261 10 : endPointHolder.release();
262 :
263 10 : return CHIP_NO_ERROR;
264 : #else
265 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
266 : #endif
267 10 : }
268 :
269 3 : CHIP_ERROR TCPBase::SendAfterConnect(const PeerAddress & addr, System::PacketBufferHandle && msg)
270 : {
271 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
272 : // This will initiate a connection to the specified peer
273 3 : bool alreadyConnecting = false;
274 :
275 : // Iterate through the ENTIRE array. If a pending packet for
276 : // the address already exists, this means a connection is pending and
277 : // does NOT need to be re-established.
278 3 : mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) {
279 0 : if (pending->mPeerAddress == addr)
280 : {
281 : // same destination exists.
282 0 : alreadyConnecting = true;
283 0 : pending->mPacketBuffer->AddToEnd(std::move(msg));
284 0 : return Loop::Break;
285 : }
286 0 : return Loop::Continue;
287 : });
288 :
289 : // If already connecting, buffer was just enqueued for more sending
290 3 : if (alreadyConnecting)
291 : {
292 0 : return CHIP_NO_ERROR;
293 : }
294 :
295 : // Ensures sufficient active connections size exist
296 3 : VerifyOrReturnError(mUsedEndPointCount < mActiveConnectionsSize, CHIP_ERROR_NO_MEMORY);
297 :
298 3 : Transport::ActiveTCPConnectionState * peerConnState = nullptr;
299 3 : ReturnErrorOnFailure(StartConnect(addr, nullptr, &peerConnState));
300 :
301 : // enqueue the packet once the connection succeeds
302 3 : VerifyOrReturnError(mPendingPackets.CreateObject(addr, std::move(msg)) != nullptr, CHIP_ERROR_NO_MEMORY);
303 3 : mUsedEndPointCount++;
304 :
305 3 : return CHIP_NO_ERROR;
306 : #else
307 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
308 : #endif
309 : }
310 :
311 11 : CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
312 : System::PacketBufferHandle && buffer)
313 : {
314 11 : ActiveTCPConnectionState * state = FindActiveConnection(endPoint);
315 11 : VerifyOrReturnError(state != nullptr, CHIP_ERROR_INTERNAL);
316 11 : state->mReceived.AddToEnd(std::move(buffer));
317 :
318 23 : while (!state->mReceived.IsNull())
319 : {
320 : uint8_t messageSizeBuf[kPacketSizeBytes];
321 13 : CHIP_ERROR err = state->mReceived->Read(messageSizeBuf);
322 13 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
323 : {
324 : // We don't have enough data to read the message size. Wait until there's more.
325 1 : return CHIP_NO_ERROR;
326 : }
327 13 : if (err != CHIP_NO_ERROR)
328 : {
329 0 : return err;
330 : }
331 13 : uint32_t messageSize = LittleEndian::Get32(messageSizeBuf);
332 13 : if (messageSize >= kMaxTCPMessageSize)
333 : {
334 : // Message is too big for this node to process. Disconnect from peer.
335 1 : ChipLogError(Inet, "Received TCP message of length %" PRIu32 " exceeds limit.", messageSize);
336 1 : CloseConnectionInternal(state, CHIP_ERROR_MESSAGE_TOO_LONG, SuppressCallback::No);
337 :
338 1 : return CHIP_ERROR_MESSAGE_TOO_LONG;
339 : }
340 : // The subtraction will not underflow because we successfully read kPacketSizeBytes.
341 12 : if (messageSize > (state->mReceived->TotalLength() - kPacketSizeBytes))
342 : {
343 : // We have not yet received the complete message.
344 0 : return CHIP_NO_ERROR;
345 : }
346 12 : state->mReceived.Consume(kPacketSizeBytes);
347 12 : ReturnErrorOnFailure(ProcessSingleMessage(peerAddress, state, messageSize));
348 : }
349 :
350 10 : return CHIP_NO_ERROR;
351 : }
352 :
353 12 : CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, size_t messageSize)
354 : {
355 : // We enter with `state->mReceived` containing at least one full message, perhaps in a chain.
356 : // `state->mReceived->Start()` currently points to the message data.
357 : // On exit, `state->mReceived` will have had `messageSize` bytes consumed, no matter what.
358 12 : System::PacketBufferHandle message;
359 12 : MessageTransportContext msgContext;
360 12 : msgContext.conn = state;
361 :
362 12 : if (state->mReceived->DataLength() == messageSize)
363 : {
364 : // In this case, the head packet buffer contains exactly the message.
365 : // This is common because typical messages fit in a network packet, and are delivered as such.
366 : // Peel off the head to pass upstream, which effectively consumes it from `state->mReceived`.
367 9 : message = state->mReceived.PopHead();
368 : }
369 : else
370 : {
371 : // The message is either longer or shorter than the head buffer.
372 : // In either case, copy the message to a fresh linear buffer to pass upstream. We always copy, rather than provide
373 : // a shared reference to the current buffer, in case upper layers manipulate the buffer in ways that would affect
374 : // our use, e.g. chaining it elsewhere or reusing space beyond the current message.
375 3 : message = System::PacketBufferHandle::New(messageSize, 0);
376 3 : if (message.IsNull())
377 : {
378 0 : return CHIP_ERROR_NO_MEMORY;
379 : }
380 3 : CHIP_ERROR err = state->mReceived->Read(message->Start(), messageSize);
381 3 : state->mReceived.Consume(messageSize);
382 3 : ReturnErrorOnFailure(err);
383 3 : message->SetDataLength(messageSize);
384 : }
385 :
386 12 : HandleMessageReceived(peerAddress, std::move(message), &msgContext);
387 12 : return CHIP_NO_ERROR;
388 12 : }
389 :
390 20 : void TCPBase::CloseConnectionInternal(ActiveTCPConnectionState * connection, CHIP_ERROR err, SuppressCallback suppressCallback)
391 : {
392 : TCPState prevState;
393 :
394 20 : if (connection == nullptr)
395 : {
396 0 : return;
397 : }
398 :
399 20 : if (connection->mConnectionState != TCPState::kClosed && connection->mEndPoint)
400 : {
401 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
402 20 : connection->mPeerAddr.ToString(addrStr);
403 20 : ChipLogProgress(Inet, "Closing connection with peer %s.", addrStr);
404 :
405 20 : if (err == CHIP_NO_ERROR)
406 : {
407 10 : connection->mEndPoint->Close();
408 : }
409 : else
410 : {
411 10 : connection->mEndPoint->Abort();
412 : }
413 :
414 20 : prevState = connection->mConnectionState;
415 20 : connection->mConnectionState = TCPState::kClosed;
416 :
417 20 : if (suppressCallback == SuppressCallback::No)
418 : {
419 10 : if (prevState == TCPState::kConnecting)
420 : {
421 : // Call upper layer connection attempt complete handler
422 0 : HandleConnectionAttemptComplete(connection, err);
423 : }
424 : else
425 : {
426 : // Call upper layer connection closed handler
427 10 : HandleConnectionClosed(connection, err);
428 : }
429 : }
430 :
431 20 : connection->Free();
432 20 : mUsedEndPointCount--;
433 : }
434 : }
435 :
436 5 : CHIP_ERROR TCPBase::HandleTCPEndPointDataReceived(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer)
437 : {
438 : Inet::IPAddress ipAddress;
439 : uint16_t port;
440 5 : Inet::InterfaceId interfaceId;
441 :
442 5 : endPoint->GetPeerInfo(&ipAddress, &port);
443 5 : endPoint->GetInterfaceId(&interfaceId);
444 5 : PeerAddress peerAddress = PeerAddress::TCP(ipAddress, port, interfaceId);
445 :
446 5 : TCPBase * tcp = reinterpret_cast<TCPBase *>(endPoint->mAppState);
447 5 : CHIP_ERROR err = tcp->ProcessReceivedBuffer(endPoint, peerAddress, std::move(buffer));
448 :
449 5 : if (err != CHIP_NO_ERROR)
450 : {
451 : // Connection could need to be closed at this point
452 0 : ChipLogError(Inet, "Failed to accept received TCP message: %" CHIP_ERROR_FORMAT, err.Format());
453 0 : return CHIP_ERROR_UNEXPECTED_EVENT;
454 : }
455 5 : return CHIP_NO_ERROR;
456 : }
457 :
458 10 : void TCPBase::HandleTCPEndPointConnectComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR conErr)
459 : {
460 10 : CHIP_ERROR err = CHIP_NO_ERROR;
461 10 : bool foundPendingPacket = false;
462 10 : TCPBase * tcp = reinterpret_cast<TCPBase *>(endPoint->mAppState);
463 : Inet::IPAddress ipAddress;
464 : uint16_t port;
465 10 : Inet::InterfaceId interfaceId;
466 10 : ActiveTCPConnectionState * activeConnection = nullptr;
467 :
468 10 : endPoint->GetPeerInfo(&ipAddress, &port);
469 10 : endPoint->GetInterfaceId(&interfaceId);
470 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
471 10 : PeerAddress addr = PeerAddress::TCP(ipAddress, port, interfaceId);
472 10 : addr.ToString(addrStr);
473 :
474 10 : if (conErr == CHIP_NO_ERROR)
475 : {
476 : // Set the Data received handler when connection completes
477 10 : endPoint->OnDataReceived = HandleTCPEndPointDataReceived;
478 10 : endPoint->OnDataSent = nullptr;
479 10 : endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed;
480 :
481 10 : activeConnection = tcp->FindInUseConnection(endPoint);
482 10 : VerifyOrDie(activeConnection != nullptr);
483 :
484 : // Set to Connected state
485 10 : activeConnection->mConnectionState = TCPState::kConnected;
486 :
487 : // Disable TCP Nagle buffering by setting TCP_NODELAY socket option to true.
488 : // This is to expedite transmission of payload data and not rely on the
489 : // network stack's configuration of collating enough data in the TCP
490 : // window to begin transmission.
491 10 : err = endPoint->EnableNoDelay();
492 10 : if (err != CHIP_NO_ERROR)
493 : {
494 0 : tcp->CloseConnectionInternal(activeConnection, err, SuppressCallback::No);
495 0 : return;
496 : }
497 :
498 : // Send any pending packets that are queued for this connection
499 10 : tcp->mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) {
500 3 : if (pending->mPeerAddress == addr)
501 : {
502 3 : foundPendingPacket = true;
503 3 : System::PacketBufferHandle buffer = std::move(pending->mPacketBuffer);
504 3 : tcp->mPendingPackets.ReleaseObject(pending);
505 :
506 3 : if ((conErr == CHIP_NO_ERROR) && (err == CHIP_NO_ERROR))
507 : {
508 3 : err = endPoint->Send(std::move(buffer));
509 : }
510 3 : }
511 3 : return Loop::Continue;
512 : });
513 :
514 : // Set the TCPKeepalive configurations on the established connection
515 10 : endPoint->EnableKeepAlive(activeConnection->mTCPKeepAliveIntervalSecs, activeConnection->mTCPMaxNumKeepAliveProbes);
516 :
517 10 : ChipLogProgress(Inet, "Connection established successfully with %s.", addrStr);
518 :
519 : // Let higher layer/delegate know that connection is successfully
520 : // established
521 10 : tcp->HandleConnectionAttemptComplete(activeConnection, CHIP_NO_ERROR);
522 : }
523 : else
524 : {
525 0 : ChipLogError(Inet, "Connection establishment with %s encountered an error: %" CHIP_ERROR_FORMAT, addrStr, err.Format());
526 0 : endPoint->Free();
527 0 : tcp->mUsedEndPointCount--;
528 : }
529 : }
530 :
531 9 : void TCPBase::HandleTCPEndPointConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err)
532 : {
533 9 : TCPBase * tcp = reinterpret_cast<TCPBase *>(endPoint->mAppState);
534 9 : ActiveTCPConnectionState * activeConnection = tcp->FindInUseConnection(endPoint);
535 :
536 9 : if (activeConnection == nullptr)
537 : {
538 0 : endPoint->Free();
539 0 : return;
540 : }
541 :
542 9 : if (err == CHIP_NO_ERROR && activeConnection->IsConnected())
543 : {
544 9 : err = CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY;
545 : }
546 :
547 9 : tcp->CloseConnectionInternal(activeConnection, err, SuppressCallback::No);
548 : }
549 :
550 : // Handler for incoming connection requests from peer nodes
551 10 : void TCPBase::HandleIncomingConnection(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint,
552 : const Inet::IPAddress & peerAddress, uint16_t peerPort)
553 : {
554 10 : TCPBase * tcp = reinterpret_cast<TCPBase *>(listenEndPoint->mAppState);
555 10 : ActiveTCPConnectionState * activeConnection = nullptr;
556 10 : Inet::InterfaceId interfaceId;
557 : Inet::IPAddress ipAddress;
558 : uint16_t port;
559 :
560 10 : endPoint->GetPeerInfo(&ipAddress, &port);
561 10 : endPoint->GetInterfaceId(&interfaceId);
562 10 : PeerAddress addr = PeerAddress::TCP(ipAddress, port, interfaceId);
563 :
564 10 : if (tcp->mUsedEndPointCount < tcp->mActiveConnectionsSize)
565 : {
566 10 : activeConnection = tcp->AllocateConnection();
567 :
568 10 : endPoint->mAppState = listenEndPoint->mAppState;
569 10 : endPoint->OnDataReceived = HandleTCPEndPointDataReceived;
570 10 : endPoint->OnDataSent = nullptr;
571 10 : endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed;
572 :
573 : // By default, disable TCP Nagle buffering by setting TCP_NODELAY socket option to true
574 10 : endPoint->EnableNoDelay();
575 :
576 : // Update state for the active connection
577 10 : activeConnection->Init(endPoint, addr);
578 10 : tcp->mUsedEndPointCount++;
579 10 : activeConnection->mConnectionState = TCPState::kConnected;
580 :
581 : // Set the TCPKeepalive configurations on the received connection
582 10 : endPoint->EnableKeepAlive(activeConnection->mTCPKeepAliveIntervalSecs, activeConnection->mTCPMaxNumKeepAliveProbes);
583 :
584 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
585 10 : peerAddress.ToString(addrStr);
586 10 : ChipLogProgress(Inet, "Incoming connection established with peer at %s.", addrStr);
587 :
588 : // Call the upper layer handler for incoming connection received.
589 10 : tcp->HandleConnectionReceived(activeConnection);
590 : }
591 : else
592 : {
593 0 : ChipLogError(Inet, "Insufficient connection space to accept new connections.");
594 0 : endPoint->Free();
595 0 : listenEndPoint->OnAcceptError(endPoint, CHIP_ERROR_TOO_MANY_CONNECTIONS);
596 : }
597 10 : }
598 :
599 0 : void TCPBase::HandleAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err)
600 : {
601 0 : endPoint->Free();
602 0 : ChipLogError(Inet, "Accept error: %" CHIP_ERROR_FORMAT, err.Format());
603 0 : }
604 :
605 7 : CHIP_ERROR TCPBase::TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState,
606 : Transport::ActiveTCPConnectionState ** outPeerConnState)
607 : {
608 7 : VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE);
609 :
610 : // Verify that PeerAddress AddressType is TCP
611 7 : VerifyOrReturnError(address.GetTransportType() == Transport::Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT);
612 :
613 7 : VerifyOrReturnError(mUsedEndPointCount < mActiveConnectionsSize, CHIP_ERROR_NO_MEMORY);
614 :
615 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
616 7 : address.ToString(addrStr);
617 7 : ChipLogProgress(Inet, "Connecting to peer %s.", addrStr);
618 :
619 7 : ReturnErrorOnFailure(StartConnect(address, appState, outPeerConnState));
620 :
621 7 : return CHIP_NO_ERROR;
622 : }
623 :
624 10 : void TCPBase::TCPDisconnect(const PeerAddress & address)
625 : {
626 : // Closes an existing connection
627 50 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
628 : {
629 40 : if (mActiveConnections[i].IsConnected())
630 : {
631 18 : const Inet::IPAddress & ipAddress = mActiveConnections[i].mPeerAddr.GetIPAddress();
632 18 : uint16_t port = mActiveConnections[i].mPeerAddr.GetPort();
633 :
634 : // Ignoring the InterfaceID in the check as it may not have been provided in
635 : // the PeerAddress during connection establishment. The IPAddress and Port
636 : // are the necessary and sufficient set of parameters for searching
637 : // through the connections.
638 18 : if (ipAddress == address.GetIPAddress() && port == address.GetPort() && address.GetTransportType() == Type::kTcp)
639 : {
640 : // NOTE: this leaves the socket in TIME_WAIT.
641 : // Calling Abort() would clean it since SO_LINGER would be set to 0,
642 : // however this seems not to be useful.
643 9 : CloseConnectionInternal(&mActiveConnections[i], CHIP_NO_ERROR, SuppressCallback::Yes);
644 : }
645 : }
646 : }
647 10 : }
648 :
649 0 : void TCPBase::TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort)
650 : {
651 :
652 0 : if (conn == nullptr)
653 : {
654 0 : ChipLogError(Inet, "Failed to Disconnect. Passed in Connection is null.");
655 0 : return;
656 : }
657 :
658 : // This call should be able to disconnect the connection either when it is
659 : // already established, or when it is being set up.
660 0 : if ((conn->IsConnected() && shouldAbort) || conn->IsConnecting())
661 : {
662 0 : CloseConnectionInternal(conn, CHIP_ERROR_CONNECTION_ABORTED, SuppressCallback::Yes);
663 : }
664 :
665 0 : if (conn->IsConnected() && !shouldAbort)
666 : {
667 0 : CloseConnectionInternal(conn, CHIP_NO_ERROR, SuppressCallback::Yes);
668 : }
669 : }
670 :
671 27 : bool TCPBase::HasActiveConnections() const
672 : {
673 103 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
674 : {
675 84 : if (mActiveConnections[i].IsConnected())
676 : {
677 8 : return true;
678 : }
679 : }
680 :
681 19 : return false;
682 : }
683 :
684 : } // namespace Transport
685 : } // namespace chip
|