Matter SDK Coverage Report
Current view: top level - transport/raw - TCP.cpp (source / functions) Coverage Total Hit
Test: SHA:3108862db59e5fa02f4a254cea1d5089c60155eb Lines: 82.2 % 331 272
Test Date: 2025-10-12 07:08:15 Functions: 88.2 % 34 30

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

Generated by: LCOV version 2.0-1