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

Generated by: LCOV version 2.0-1