Matter SDK Coverage Report
Current view: top level - transport/raw - TCP.cpp (source / functions) Coverage Total Hit
Test: SHA:3f9cd168e84cd831b7699126f5296f5c5498690f Lines: 87.2 % 312 272
Test Date: 2026-04-27 19:52:19 Functions: 93.8 % 32 30

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2025 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           25 : CHIP_ERROR GetPeerAddress(Inet::TCPEndPoint & endPoint, PeerAddress & outAddr)
      55              : {
      56              :     Inet::IPAddress ipAddress;
      57              :     uint16_t port;
      58           25 :     Inet::InterfaceId interfaceId;
      59           25 :     ReturnErrorOnFailure(endPoint.GetPeerInfo(&ipAddress, &port));
      60           25 :     ReturnErrorOnFailure(endPoint.GetInterfaceId(&interfaceId));
      61           25 :     outAddr = PeerAddress::TCP(ipAddress, port, interfaceId);
      62              : 
      63           25 :     return CHIP_NO_ERROR;
      64              : }
      65              : 
      66              : } // namespace
      67              : 
      68          290 : TCPBase::~TCPBase() = default;
      69              : 
      70          295 : void TCPBase::CloseActiveConnections()
      71              : {
      72              :     // Nothing to do; we can't release as long as references are being held
      73         1467 :     for (size_t i = 0; i < mActiveConnectionsSize; i++)
      74              :     {
      75         1172 :         if (mActiveConnections[i].InUse())
      76              :         {
      77            3 :             CloseConnectionInternal(mActiveConnections[i], CHIP_NO_ERROR, SuppressCallback::Yes);
      78              :         }
      79              :     }
      80          295 : }
      81              : 
      82           26 : CHIP_ERROR TCPBase::Init(TcpListenParameters & params)
      83              : {
      84           26 :     CHIP_ERROR err = CHIP_NO_ERROR;
      85              : 
      86           26 :     VerifyOrExit(mState == TCPState::kNotReady, err = CHIP_ERROR_INCORRECT_STATE);
      87              : 
      88           26 :     mEndpointType = params.GetAddressType();
      89              : 
      90              :     // Primary socket endpoint created to help get EndPointManager handle for creating multiple
      91              :     // connection endpoints at runtime.
      92           26 :     err = params.GetEndPointManager()->NewEndPoint(mListenSocket);
      93           26 :     SuccessOrExit(err);
      94              : 
      95           26 :     if (params.IsServerListenEnabled())
      96              :     {
      97           48 :         err = mListenSocket->Bind(params.GetAddressType(), Inet::IPAddress::Any, params.GetListenPort(),
      98           24 :                                   params.GetInterfaceId().IsPresent());
      99           24 :         SuccessOrExit(err);
     100              : 
     101           24 :         mListenSocket->mAppState            = reinterpret_cast<void *>(this);
     102           24 :         mListenSocket->OnConnectionReceived = HandleIncomingConnection;
     103           24 :         mListenSocket->OnAcceptError        = HandleAcceptError;
     104              : 
     105           24 :         err = mListenSocket->Listen(kListenBacklogSize);
     106           24 :         SuccessOrExit(err);
     107           24 :         ChipLogProgress(Inet, "TCP server listening on port %d for incoming connections", params.GetListenPort());
     108              :     }
     109              : 
     110           26 :     mState = TCPState::kInitialized;
     111              : 
     112           26 : exit:
     113           52 :     if (err != CHIP_NO_ERROR)
     114              :     {
     115            0 :         ChipLogError(Inet, "Failed to initialize TCP transport: %" CHIP_ERROR_FORMAT, err.Format());
     116            0 :         mListenSocket.Release();
     117              :     }
     118              : 
     119           26 :     return err;
     120              : }
     121              : 
     122          295 : void TCPBase::Close()
     123              : {
     124          295 :     mListenSocket.Release();
     125              : 
     126          295 :     CloseActiveConnections();
     127              : 
     128          295 :     mState = TCPState::kNotReady;
     129          295 : }
     130              : 
     131           49 : ActiveTCPConnectionState * TCPBase::AllocateConnection(const Inet::TCPEndPointHandle & endpoint, const PeerAddress & address)
     132              : {
     133              :     // If a peer initiates a connection through HandleIncomingConnection but the connection is never claimed
     134              :     // in ProcessSingleMessage, we'll be left with a dangling ActiveTCPConnectionState which can be
     135              :     // reclaimed.  Don't try to reclaim these connections unless we're out of space
     136           49 :     for (int reclaim = 0; reclaim < 2; reclaim++)
     137              :     {
     138           65 :         for (size_t i = 0; i < mActiveConnectionsSize; i++)
     139              :         {
     140           65 :             ActiveTCPConnectionState * activeConnection = &mActiveConnections[i];
     141           65 :             if (!activeConnection->InUse() && (activeConnection->GetReferenceCount() == 0))
     142              :             {
     143              :                 // Update state for the active connection
     144           85 :                 activeConnection->Init(endpoint, address, [this](auto & conn) { TCPDisconnect(conn, true); });
     145           49 :                 return activeConnection;
     146              :             }
     147              :         }
     148              : 
     149              :         // Out of space; reclaim connections that were never claimed by ProcessSingleMessage
     150              :         // (i.e. that have a ref count of 0)
     151            0 :         for (size_t i = 0; i < mActiveConnectionsSize; i++)
     152              :         {
     153            0 :             ActiveTCPConnectionState * activeConnection = &mActiveConnections[i];
     154            0 :             if (!activeConnection->InUse() && (activeConnection->GetReferenceCount() != 0))
     155              :             {
     156              :                 char addrStr[Transport::PeerAddress::kMaxToStringSize];
     157            0 :                 activeConnection->mPeerAddr.ToString(addrStr);
     158            0 :                 ChipLogError(Inet, "Leaked TCP connection %p to %s.", activeConnection, addrStr);
     159              :                 // Try to notify callbacks in the hope that they release; the connection is no good
     160            0 :                 CloseConnectionInternal(*activeConnection, CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY, SuppressCallback::No);
     161              :             }
     162            0 :             ActiveTCPConnectionHandle releaseUnclaimed(activeConnection);
     163            0 :         }
     164              :     }
     165            0 :     return nullptr;
     166              : }
     167              : 
     168              : // Find an ActiveTCPConnectionState corresponding to a peer address
     169           48 : ActiveTCPConnectionHandle TCPBase::FindInUseConnection(const PeerAddress & address)
     170              : {
     171           48 :     if (address.GetTransportType() != Type::kTcp)
     172              :     {
     173            0 :         return nullptr;
     174              :     }
     175              : 
     176          172 :     for (size_t i = 0; i < mActiveConnectionsSize; i++)
     177              :     {
     178          139 :         auto & conn = mActiveConnections[i];
     179          139 :         if (!conn.InUse())
     180              :         {
     181          124 :             continue;
     182              :         }
     183              : 
     184           15 :         if (conn.mPeerAddr == address)
     185              :         {
     186              :             Inet::IPAddress addr;
     187              :             uint16_t port;
     188           15 :             if (conn.IsConnected())
     189              :             {
     190              :                 // Failure to get peer information means the connection is bad; close it
     191            6 :                 CHIP_ERROR err = conn.mEndPoint->GetPeerInfo(&addr, &port);
     192           12 :                 if (err != CHIP_NO_ERROR)
     193              :                 {
     194            0 :                     CloseConnectionInternal(conn, err, SuppressCallback::No);
     195            0 :                     return nullptr;
     196              :                 }
     197              :             }
     198              : 
     199           15 :             return ActiveTCPConnectionHandle(&conn);
     200              :         }
     201              :     }
     202              : 
     203           33 :     return nullptr;
     204              : }
     205              : 
     206              : // Find the ActiveTCPConnectionState for a given TCPEndPoint
     207           16 : ActiveTCPConnectionState * TCPBase::FindActiveConnection(const Inet::TCPEndPointHandle & endPoint)
     208              : {
     209           23 :     for (size_t i = 0; i < mActiveConnectionsSize; i++)
     210              :     {
     211           23 :         if (mActiveConnections[i].mEndPoint == endPoint && mActiveConnections[i].IsConnected())
     212              :         {
     213           16 :             return &mActiveConnections[i];
     214              :         }
     215              :     }
     216            0 :     return nullptr;
     217              : }
     218              : 
     219           29 : ActiveTCPConnectionHandle TCPBase::FindInUseConnection(const Inet::TCPEndPoint & endPoint)
     220              : {
     221           36 :     for (size_t i = 0; i < mActiveConnectionsSize; i++)
     222              :     {
     223           36 :         if (mActiveConnections[i].mEndPoint == endPoint)
     224              :         {
     225           29 :             return ActiveTCPConnectionHandle(&mActiveConnections[i]);
     226              :         }
     227              :     }
     228            0 :     return nullptr;
     229              : }
     230              : 
     231           13 : CHIP_ERROR TCPBase::PrepareBuffer(System::PacketBufferHandle & msgBuf)
     232              : {
     233              :     // Sent buffer data format is:
     234              :     //    - packet size as a uint32_t
     235              :     //    - actual data
     236              : 
     237           13 :     VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE);
     238           13 :     VerifyOrReturnError(kPacketSizeBytes + msgBuf->DataLength() <= System::PacketBuffer::kLargeBufMaxSizeWithoutReserve,
     239              :                         CHIP_ERROR_INVALID_ARGUMENT);
     240              : 
     241              :     static_assert(kPacketSizeBytes <= UINT16_MAX);
     242           13 :     VerifyOrReturnError(msgBuf->EnsureReservedSize(static_cast<uint16_t>(kPacketSizeBytes)), CHIP_ERROR_NO_MEMORY);
     243              : 
     244           13 :     msgBuf->SetStart(msgBuf->Start() - kPacketSizeBytes);
     245              : 
     246           13 :     uint8_t * output = msgBuf->Start();
     247           13 :     LittleEndian::Write32(output, static_cast<uint32_t>(msgBuf->DataLength() - kPacketSizeBytes));
     248              : 
     249           13 :     return CHIP_NO_ERROR;
     250              : }
     251              : 
     252            9 : CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System::PacketBufferHandle && msgBuf)
     253              : {
     254            9 :     VerifyOrReturnError(address.GetTransportType() == Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT);
     255            9 :     ReturnErrorOnFailure(PrepareBuffer(msgBuf));
     256              : 
     257              :     // Must find a previously-established connection with an owning reference
     258            9 :     auto connection = FindInUseConnection(address);
     259            9 :     VerifyOrReturnError(!connection.IsNull(), CHIP_ERROR_INCORRECT_STATE);
     260            9 :     if (connection->IsConnected())
     261              :     {
     262            2 :         return connection->mEndPoint->Send(std::move(msgBuf));
     263              :     }
     264              : 
     265            7 :     return SendAfterConnect(connection, std::move(msgBuf));
     266            9 : }
     267              : 
     268            4 : CHIP_ERROR TCPBase::SendMessage(const ActiveTCPConnectionHandle & connection, System::PacketBufferHandle && msgBuf)
     269              : {
     270            4 :     VerifyOrReturnError(!connection.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     271            4 :     ReturnErrorOnFailure(PrepareBuffer(msgBuf));
     272              : 
     273            4 :     if (connection->IsConnected())
     274              :     {
     275            4 :         return connection->mEndPoint->Send(std::move(msgBuf));
     276              :     }
     277              : 
     278            0 :     return SendAfterConnect(connection, std::move(msgBuf));
     279              : }
     280              : 
     281           37 : CHIP_ERROR TCPBase::StartConnect(const PeerAddress & addr, Transport::AppTCPConnectionCallbackCtxt * appState,
     282              :                                  ActiveTCPConnectionHandle & outPeerConnState)
     283              : {
     284              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     285           37 :     Inet::TCPEndPointHandle endPoint;
     286           37 :     outPeerConnState.Release();
     287           37 :     ReturnErrorOnFailure(mListenSocket->GetEndPointManager().NewEndPoint(endPoint));
     288              : 
     289           37 :     InitEndpoint(endPoint);
     290              : 
     291           37 :     ActiveTCPConnectionHandle activeConnection = FindInUseConnection(addr);
     292              :     // Re-use existing connection to peer if already connected
     293           37 :     if (!activeConnection.IsNull())
     294              :     {
     295            4 :         if (appState != nullptr)
     296              :         {
     297              :             // We do not support parallel attempts to connect to peer when setting appState
     298            0 :             VerifyOrReturnError(activeConnection->mConnectionState == TCPState::kConnected &&
     299              :                                     activeConnection->mAppState == nullptr,
     300              :                                 CHIP_ERROR_INCORRECT_STATE);
     301            0 :             activeConnection->mAppState = appState;
     302              :         }
     303            4 :         outPeerConnState = activeConnection;
     304              : 
     305            4 :         if (activeConnection->mConnectionState == TCPState::kConnected)
     306              :         {
     307            2 :             HandleConnectionAttemptComplete(activeConnection, CHIP_NO_ERROR);
     308              :         }
     309              : 
     310            4 :         return CHIP_NO_ERROR;
     311              :     }
     312              : 
     313           33 :     activeConnection = AllocateConnection(endPoint, addr);
     314           33 :     VerifyOrReturnError(!activeConnection.IsNull(), CHIP_ERROR_NO_MEMORY);
     315           33 :     activeConnection->mAppState        = appState;
     316           33 :     activeConnection->mConnectionState = TCPState::kConnecting;
     317              : 
     318           33 :     mUsedEndPointCount++;
     319              : 
     320           33 :     ReturnErrorOnFailure(endPoint->Connect(addr.GetIPAddress(), addr.GetPort(), addr.GetInterface()));
     321              : 
     322              :     // Set the return value of the peer connection state to the allocated
     323              :     // connection.
     324           21 :     outPeerConnState = activeConnection;
     325              : 
     326           21 :     return CHIP_NO_ERROR;
     327              : #else
     328              :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     329              : #endif
     330           37 : }
     331              : 
     332            7 : CHIP_ERROR TCPBase::SendAfterConnect(const ActiveTCPConnectionHandle & existing, System::PacketBufferHandle && msg)
     333              : {
     334              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     335            7 :     VerifyOrReturnError(!existing.IsNull(), CHIP_ERROR_INCORRECT_STATE);
     336            7 :     const PeerAddress & addr = existing->mPeerAddr;
     337              : 
     338              :     // This will initiate a connection to the specified peer
     339            7 :     bool alreadyConnecting = false;
     340              : 
     341              :     // Iterate through the ENTIRE array. If a pending packet for
     342              :     // the address already exists, this means a connection is pending and
     343              :     // does NOT need to be re-established.
     344            7 :     mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) {
     345            2 :         if (pending->mPeerAddress == addr)
     346              :         {
     347              :             // same destination exists.
     348            2 :             alreadyConnecting = true;
     349            2 :             pending->mPacketBuffer->AddToEnd(std::move(msg));
     350            2 :             return Loop::Break;
     351              :         }
     352            0 :         return Loop::Continue;
     353              :     });
     354              : 
     355              :     // If already connecting, buffer was just enqueued for more sending
     356            7 :     if (alreadyConnecting)
     357              :     {
     358            2 :         return CHIP_NO_ERROR;
     359              :     }
     360              : 
     361              :     // enqueue the packet once the connection succeeds
     362            5 :     VerifyOrReturnError(mPendingPackets.CreateObject(addr, std::move(msg)) != nullptr, CHIP_ERROR_NO_MEMORY);
     363              : 
     364            5 :     return CHIP_NO_ERROR;
     365              : #else
     366              :     return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
     367              : #endif
     368              : }
     369              : 
     370           16 : CHIP_ERROR TCPBase::ProcessReceivedBuffer(const Inet::TCPEndPointHandle & endPoint, const PeerAddress & peerAddress,
     371              :                                           System::PacketBufferHandle && buffer)
     372              : {
     373           16 :     ActiveTCPConnectionState * state = FindActiveConnection(endPoint);
     374              :     // There must be a preceding TCPConnect to hold a reference to connection
     375           16 :     VerifyOrReturnError(state != nullptr, CHIP_ERROR_INTERNAL);
     376           16 :     state->mReceived.AddToEnd(std::move(buffer));
     377              : 
     378           36 :     while (!state->mReceived.IsNull())
     379              :     {
     380              :         uint8_t messageSizeBuf[kPacketSizeBytes];
     381           22 :         CHIP_ERROR err = state->mReceived->Read(messageSizeBuf);
     382           44 :         if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
     383              :         {
     384              :             // We don't have enough data to read the message size. Wait until there's more.
     385            0 :             return CHIP_NO_ERROR;
     386              :         }
     387           44 :         if (err != CHIP_NO_ERROR)
     388              :         {
     389            0 :             return err;
     390              :         }
     391           22 :         uint32_t messageSize = LittleEndian::Get32(messageSizeBuf);
     392           22 :         if (messageSize >= kMaxTCPMessageSize)
     393              :         {
     394              :             // Message is too big for this node to process. Disconnect from peer.
     395            1 :             ChipLogError(Inet, "Received TCP message of length %" PRIu32 " exceeds limit.", messageSize);
     396            1 :             CloseConnectionInternal(*state, CHIP_ERROR_MESSAGE_TOO_LONG, SuppressCallback::No);
     397              : 
     398            1 :             return CHIP_ERROR_MESSAGE_TOO_LONG;
     399              :         }
     400              :         // The subtraction will not underflow because we successfully read kPacketSizeBytes.
     401           21 :         if (messageSize > (state->mReceived->TotalLength() - kPacketSizeBytes))
     402              :         {
     403              :             // We have not yet received the complete message.
     404            0 :             return CHIP_NO_ERROR;
     405              :         }
     406              : 
     407           21 :         state->mReceived.Consume(kPacketSizeBytes);
     408              : 
     409           21 :         if (messageSize == 0)
     410              :         {
     411              :             // No payload but considered a valid message. Return success to keep the connection alive.
     412            1 :             return CHIP_NO_ERROR;
     413              :         }
     414              : 
     415           20 :         ReturnErrorOnFailure(ProcessSingleMessage(peerAddress, *state, messageSize));
     416              :     }
     417              : 
     418           14 :     return CHIP_NO_ERROR;
     419              : }
     420              : 
     421           20 : CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState & state, size_t messageSize)
     422              : {
     423              :     // We enter with `state->mReceived` containing at least one full message, perhaps in a chain.
     424              :     // `state->mReceived->Start()` currently points to the message data.
     425              :     // On exit, `state->mReceived` will have had `messageSize` bytes consumed, no matter what.
     426           20 :     System::PacketBufferHandle message;
     427              : 
     428           20 :     if (state.mReceived->DataLength() == messageSize)
     429              :     {
     430              :         // In this case, the head packet buffer contains exactly the message.
     431              :         // This is common because typical messages fit in a network packet, and are delivered as such.
     432              :         // Peel off the head to pass upstream, which effectively consumes it from `state->mReceived`.
     433           13 :         message = state.mReceived.PopHead();
     434              :     }
     435              :     else
     436              :     {
     437              :         // The message is either longer or shorter than the head buffer.
     438              :         // In either case, copy the message to a fresh linear buffer to pass upstream. We always copy, rather than provide
     439              :         // a shared reference to the current buffer, in case upper layers manipulate the buffer in ways that would affect
     440              :         // our use, e.g. chaining it elsewhere or reusing space beyond the current message.
     441            7 :         message = System::PacketBufferHandle::New(messageSize, 0);
     442            7 :         if (message.IsNull())
     443              :         {
     444            0 :             return CHIP_ERROR_NO_MEMORY;
     445              :         }
     446            7 :         CHIP_ERROR err = state.mReceived->Read(message->Start(), messageSize);
     447            7 :         state.mReceived.Consume(messageSize);
     448            7 :         ReturnErrorOnFailure(err);
     449            7 :         message->SetDataLength(messageSize);
     450              :     }
     451              : 
     452           20 :     MessageTransportContext msgContext;
     453           20 :     msgContext.conn = &state; // Take ownership
     454           20 :     HandleMessageReceived(peerAddress, std::move(message), &msgContext);
     455           20 :     return CHIP_NO_ERROR;
     456           20 : }
     457              : 
     458           49 : void TCPBase::CloseConnectionInternal(ActiveTCPConnectionState & connection, CHIP_ERROR err, SuppressCallback suppressCallback)
     459              : {
     460           49 :     if (connection.mConnectionState == TCPState::kClosed || !connection.mEndPoint)
     461              :     {
     462            0 :         return;
     463              :     }
     464              :     TCPState prevState;
     465              :     char addrStr[Transport::PeerAddress::kMaxToStringSize];
     466           49 :     connection.mPeerAddr.ToString(addrStr);
     467           49 :     ChipLogProgress(Inet, "Closing connection with peer %s.", addrStr);
     468              : 
     469           49 :     Inet::TCPEndPointHandle endpoint = connection.mEndPoint;
     470           49 :     connection.mEndPoint.Release();
     471           98 :     if (err == CHIP_NO_ERROR)
     472              :     {
     473            3 :         endpoint->Close();
     474              :     }
     475              :     else
     476              :     {
     477           46 :         endpoint->Abort();
     478              :     }
     479              : 
     480           49 :     prevState                   = connection.mConnectionState;
     481           49 :     connection.mConnectionState = TCPState::kClosed;
     482              : 
     483           49 :     if (suppressCallback == SuppressCallback::No)
     484              :     {
     485           12 :         if (prevState == TCPState::kConnecting)
     486              :         {
     487            0 :             ActiveTCPConnectionHandle holder(&connection);
     488              :             // Call upper layer connection attempt complete handler
     489            0 :             HandleConnectionAttemptComplete(holder, err);
     490            0 :         }
     491              :         else
     492              :         {
     493              :             // Call upper layer connection closed handler
     494           12 :             HandleConnectionClosed(connection, err);
     495              :         }
     496              :     }
     497              : 
     498           49 :     connection.Free();
     499           49 :     mUsedEndPointCount--;
     500           49 : }
     501              : 
     502            9 : CHIP_ERROR TCPBase::HandleTCPEndPointDataReceived(const Inet::TCPEndPointHandle & endPoint, System::PacketBufferHandle && buffer)
     503              : {
     504            9 :     PeerAddress peerAddress;
     505            9 :     ReturnErrorOnFailure(GetPeerAddress(*endPoint, peerAddress));
     506              : 
     507            9 :     TCPBase * tcp  = reinterpret_cast<TCPBase *>(endPoint->mAppState);
     508            9 :     CHIP_ERROR err = tcp->ProcessReceivedBuffer(endPoint, peerAddress, std::move(buffer));
     509              : 
     510           18 :     if (err != CHIP_NO_ERROR)
     511              :     {
     512              :         // Connection could need to be closed at this point
     513            0 :         ChipLogError(Inet, "Failed to accept received TCP message: %" CHIP_ERROR_FORMAT, err.Format());
     514            0 :         return CHIP_ERROR_UNEXPECTED_EVENT;
     515              :     }
     516            9 :     return CHIP_NO_ERROR;
     517              : }
     518              : 
     519           20 : void TCPBase::HandleTCPEndPointConnectComplete(const Inet::TCPEndPointHandle & endPoint, CHIP_ERROR conErr)
     520              : {
     521           20 :     CHIP_ERROR err          = CHIP_NO_ERROR;
     522           20 :     bool foundPendingPacket = false;
     523           20 :     TCPBase * tcp           = reinterpret_cast<TCPBase *>(endPoint->mAppState);
     524           20 :     ActiveTCPConnectionHandle activeConnection;
     525              : 
     526           20 :     PeerAddress addr;
     527              :     char addrStr[Transport::PeerAddress::kMaxToStringSize];
     528           20 :     activeConnection = tcp->FindInUseConnection(*endPoint);
     529           20 :     if (activeConnection.IsNull())
     530              :     {
     531            0 :         err = GetPeerAddress(*endPoint, addr);
     532              :     }
     533              :     else
     534              :     {
     535           20 :         addr = activeConnection->mPeerAddr;
     536              :     }
     537           40 :     if (err == CHIP_NO_ERROR)
     538              :     {
     539           20 :         addr.ToString(addrStr);
     540              :     }
     541              : 
     542           60 :     if (conErr != CHIP_NO_ERROR || err != CHIP_NO_ERROR)
     543              :     {
     544            0 :         auto failure = (conErr != CHIP_NO_ERROR) ? conErr : err;
     545            0 :         if (!activeConnection.IsNull())
     546              :         {
     547            0 :             tcp->CloseConnectionInternal(*activeConnection, failure, SuppressCallback::No);
     548              :         }
     549            0 :         ChipLogError(Inet, "Connection establishment with %s encountered an error: %" CHIP_ERROR_FORMAT, addrStr, failure.Format());
     550            0 :         return;
     551              :     }
     552              :     // Set the Data received handler when connection completes
     553           20 :     endPoint->OnDataReceived     = HandleTCPEndPointDataReceived;
     554           20 :     endPoint->OnDataSent         = nullptr;
     555           20 :     endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed;
     556              : 
     557           20 :     VerifyOrDie(!activeConnection.IsNull());
     558              : 
     559              :     // Set to Connected state
     560           20 :     activeConnection->mConnectionState = TCPState::kConnected;
     561              : 
     562              :     // Disable TCP Nagle buffering by setting TCP_NODELAY socket option to true.
     563              :     // This is to expedite transmission of payload data and not rely on the
     564              :     // network stack's configuration of collating enough data in the TCP
     565              :     // window to begin transmission.
     566           20 :     err = endPoint->EnableNoDelay();
     567           40 :     if (err != CHIP_NO_ERROR)
     568              :     {
     569            0 :         tcp->CloseConnectionInternal(*activeConnection, err, SuppressCallback::No);
     570            0 :         return;
     571              :     }
     572              : 
     573              :     // Send any pending packets that are queued for this connection
     574           20 :     tcp->mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) {
     575            5 :         if (pending->mPeerAddress == addr)
     576              :         {
     577            5 :             foundPendingPacket                = true;
     578            5 :             System::PacketBufferHandle buffer = std::move(pending->mPacketBuffer);
     579            5 :             tcp->mPendingPackets.ReleaseObject(pending);
     580              : 
     581           15 :             if ((conErr == CHIP_NO_ERROR) && (err == CHIP_NO_ERROR))
     582              :             {
     583              :                 // TODO(gmarcosb): These errors are just swallowed; caller unaware their message is just dropped?
     584              :                 // Likely just falls through to a timeout instead of fail-fast
     585            5 :                 err = endPoint->Send(std::move(buffer));
     586              :             }
     587            5 :         }
     588            5 :         return Loop::Continue;
     589              :     });
     590              : 
     591              :     // Set the TCPKeepalive configurations on the established connection
     592           40 :     TEMPORARY_RETURN_IGNORED endPoint->EnableKeepAlive(activeConnection->mTCPKeepAliveIntervalSecs,
     593           20 :                                                        activeConnection->mTCPMaxNumKeepAliveProbes);
     594              : 
     595           20 :     ChipLogProgress(Inet, "Connection established successfully with %s.", addrStr);
     596              : 
     597              :     // Let higher layer/delegate know that connection is successfully
     598              :     // established
     599           20 :     tcp->HandleConnectionAttemptComplete(activeConnection, CHIP_NO_ERROR);
     600           20 : }
     601              : 
     602            9 : void TCPBase::HandleTCPEndPointConnectionClosed(const Inet::TCPEndPointHandle & endPoint, CHIP_ERROR err)
     603              : {
     604            9 :     TCPBase * tcp                              = reinterpret_cast<TCPBase *>(endPoint->mAppState);
     605            9 :     ActiveTCPConnectionHandle activeConnection = tcp->FindInUseConnection(*endPoint);
     606              : 
     607            9 :     if (activeConnection.IsNull())
     608              :     {
     609            0 :         return;
     610              :     }
     611              : 
     612           18 :     if (err == CHIP_NO_ERROR && activeConnection->IsConnected())
     613              :     {
     614            2 :         err = CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY;
     615              :     }
     616              : 
     617            9 :     tcp->CloseConnectionInternal(*activeConnection, err, SuppressCallback::No);
     618            9 : }
     619              : 
     620              : // Handler for incoming connection requests from peer nodes
     621           18 : void TCPBase::HandleIncomingConnection(const Inet::TCPEndPointHandle & listenEndPoint, const Inet::TCPEndPointHandle & endPoint,
     622              :                                        const Inet::IPAddress & peerAddress, uint16_t peerPort)
     623              : {
     624           18 :     TCPBase * tcp = reinterpret_cast<TCPBase *>(listenEndPoint->mAppState);
     625           18 :     ReturnAndLogOnFailure(tcp->DoHandleIncomingConnection(listenEndPoint, endPoint, peerAddress, peerPort), Inet,
     626              :                           "Failure accepting incoming connection");
     627              : }
     628              : 
     629           18 : CHIP_ERROR TCPBase::DoHandleIncomingConnection(const Inet::TCPEndPointHandle & listenEndPoint,
     630              :                                                const Inet::TCPEndPointHandle & endPoint, const Inet::IPAddress & peerAddress,
     631              :                                                uint16_t peerPort)
     632              : {
     633              : #if INET_CONFIG_TEST
     634           18 :     if (sForceFailureInDoHandleIncomingConnection)
     635              :     {
     636            2 :         return CHIP_ERROR_INTERNAL;
     637              :     }
     638              : #endif
     639              : 
     640              :     // GetPeerAddress may fail if the client has already closed the connection, just drop it.
     641           16 :     PeerAddress addr;
     642           16 :     ReturnErrorOnFailure(GetPeerAddress(*endPoint, addr));
     643              : 
     644           16 :     ActiveTCPConnectionState * activeConnection = AllocateConnection(endPoint, addr);
     645           16 :     VerifyOrReturnError(activeConnection != nullptr, CHIP_ERROR_TOO_MANY_CONNECTIONS);
     646              : 
     647           16 :     auto connectionCleanup = ScopeExit([&]() { activeConnection->Free(); });
     648              : 
     649           16 :     endPoint->mAppState          = this;
     650           16 :     endPoint->OnDataReceived     = HandleTCPEndPointDataReceived;
     651           16 :     endPoint->OnDataSent         = nullptr;
     652           16 :     endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed;
     653              : 
     654              :     // By default, disable TCP Nagle buffering by setting TCP_NODELAY socket option to true
     655              :     // If it fails, we can still use the connection
     656           16 :     RETURN_SAFELY_IGNORED endPoint->EnableNoDelay();
     657              : 
     658           16 :     mUsedEndPointCount++;
     659           16 :     activeConnection->mConnectionState = TCPState::kConnected;
     660              : 
     661              :     // Set the TCPKeepalive configurations on the received connection
     662              :     // If it fails, we can still use the connection until it dies
     663           16 :     RETURN_SAFELY_IGNORED endPoint->EnableKeepAlive(activeConnection->mTCPKeepAliveIntervalSecs,
     664           16 :                                                     activeConnection->mTCPMaxNumKeepAliveProbes);
     665              : 
     666              :     char addrStr[Transport::PeerAddress::kMaxToStringSize];
     667           16 :     peerAddress.ToString(addrStr);
     668           16 :     ChipLogProgress(Inet, "Incoming connection established with peer at %s.", addrStr);
     669              : 
     670              :     // Call the upper layer handler for incoming connection received.
     671           16 :     HandleConnectionReceived(*activeConnection);
     672              : 
     673           16 :     connectionCleanup.release();
     674              : 
     675           16 :     return CHIP_NO_ERROR;
     676           16 : }
     677              : 
     678            2 : void TCPBase::HandleAcceptError(const Inet::TCPEndPointHandle & listeningEndpoint, CHIP_ERROR err)
     679              : {
     680            2 :     ChipLogError(Inet, "Accept error: %" CHIP_ERROR_FORMAT, err.Format());
     681            2 : }
     682              : 
     683           37 : CHIP_ERROR TCPBase::TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState,
     684              :                                ActiveTCPConnectionHandle & outPeerConnState)
     685              : {
     686           37 :     VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE);
     687              : 
     688              :     // Verify that PeerAddress AddressType is TCP
     689           37 :     VerifyOrReturnError(address.GetTransportType() == Transport::Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT);
     690              : 
     691           37 :     VerifyOrReturnError(mUsedEndPointCount < mActiveConnectionsSize, CHIP_ERROR_NO_MEMORY);
     692              : 
     693              :     char addrStr[Transport::PeerAddress::kMaxToStringSize];
     694           37 :     address.ToString(addrStr);
     695           37 :     ChipLogProgress(Inet, "Connecting to peer %s.", addrStr);
     696              : 
     697           37 :     ReturnErrorOnFailure(StartConnect(address, appState, outPeerConnState));
     698              : 
     699           25 :     return CHIP_NO_ERROR;
     700              : }
     701              : 
     702           36 : void TCPBase::TCPDisconnect(ActiveTCPConnectionState & conn, bool shouldAbort)
     703              : {
     704              :     // If there are still active references, we need to notify them of connection closure
     705           36 :     SuppressCallback suppressCallback = (conn.GetReferenceCount() > 0) ? SuppressCallback::No : SuppressCallback::Yes;
     706              : 
     707              :     // This call should be able to disconnect the connection either when it is
     708              :     // already established, or when it is being set up.
     709           36 :     if ((conn.IsConnected() && shouldAbort) || conn.IsConnecting())
     710              :     {
     711           36 :         CloseConnectionInternal(conn, CHIP_ERROR_CONNECTION_ABORTED, suppressCallback);
     712              :     }
     713              : 
     714           36 :     if (conn.IsConnected() && !shouldAbort)
     715              :     {
     716            0 :         CloseConnectionInternal(conn, CHIP_NO_ERROR, suppressCallback);
     717              :     }
     718           36 : }
     719              : 
     720           42 : bool TCPBase::HasActiveConnections() const
     721              : {
     722          178 :     for (size_t i = 0; i < mActiveConnectionsSize; i++)
     723              :     {
     724          144 :         if (mActiveConnections[i].IsConnected())
     725              :         {
     726            8 :             return true;
     727              :         }
     728              :     }
     729              : 
     730           34 :     return false;
     731              : }
     732              : 
     733           37 : void TCPBase::InitEndpoint(const Inet::TCPEndPointHandle & endpoint)
     734              : {
     735           37 :     endpoint->mAppState         = reinterpret_cast<void *>(this);
     736           37 :     endpoint->OnConnectComplete = HandleTCPEndPointConnectComplete;
     737           37 :     endpoint->SetConnectTimeout(mConnectTimeout);
     738           37 : }
     739              : 
     740              : #if INET_CONFIG_TEST
     741              : bool TCPBase::sForceFailureInDoHandleIncomingConnection = false;
     742              : #endif
     743              : 
     744              : } // namespace Transport
     745              : } // namespace chip
        

Generated by: LCOV version 2.0-1