Matter SDK Coverage Report
Current view: top level - transport/raw - TCP.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 84.0 % 282 237
Test Date: 2025-01-17 19:00:11 Functions: 81.5 % 27 22

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

Generated by: LCOV version 2.0-1