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

Generated by: LCOV version 2.0-1