Matter SDK Coverage Report
Current view: top level - inet - TCPEndPointImplSockets.cpp (source / functions) Coverage Total Hit
Test: SHA:3108862db59e5fa02f4a254cea1d5089c60155eb Lines: 69.3 % 391 271
Test Date: 2025-10-12 07:08:15 Functions: 87.5 % 24 21

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *    Copyright (c) 2013-2018 Nest Labs, Inc.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  * This file implements Inet::TCPEndPoint using sockets.
      21              :  */
      22              : 
      23              : #include <inet/TCPEndPointImplSockets.h>
      24              : 
      25              : #include <inet/InetFaultInjection.h>
      26              : #include <inet/arpa-inet-compatibility.h>
      27              : 
      28              : #include <lib/support/CodeUtils.h>
      29              : #include <lib/support/SafeInt.h>
      30              : #include <lib/support/logging/CHIPLogging.h>
      31              : #include <system/SystemFaultInjection.h>
      32              : 
      33              : #include <stdio.h>
      34              : #include <string.h>
      35              : #include <utility>
      36              : 
      37              : #include <errno.h>
      38              : #include <fcntl.h>
      39              : #include <net/if.h>
      40              : #include <netinet/tcp.h>
      41              : #include <sys/ioctl.h>
      42              : #include <sys/select.h>
      43              : #include <sys/socket.h>
      44              : #include <unistd.h>
      45              : 
      46              : // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
      47              : #ifndef SOCK_CLOEXEC
      48              : #define SOCK_CLOEXEC 0
      49              : #endif
      50              : 
      51              : #if defined(SOL_TCP)
      52              : // socket option level for Linux and BSD systems.
      53              : #define TCP_SOCKOPT_LEVEL SOL_TCP
      54              : #else
      55              : // socket option level for macOS & iOS systems.
      56              : #define TCP_SOCKOPT_LEVEL IPPROTO_TCP
      57              : #endif
      58              : 
      59              : #if defined(TCP_KEEPIDLE)
      60              : // socket option for Linux and BSD systems.
      61              : #define TCP_IDLE_INTERVAL_OPT_NAME TCP_KEEPIDLE
      62              : #else
      63              : // socket option for macOS & iOS systems.
      64              : #define TCP_IDLE_INTERVAL_OPT_NAME TCP_KEEPALIVE
      65              : #endif
      66              : 
      67              : namespace chip {
      68              : namespace Inet {
      69              : 
      70           22 : CHIP_ERROR TCPEndPointImplSockets::BindImpl(IPAddressType addrType, const IPAddress & addr, uint16_t port, bool reuseAddr)
      71              : {
      72           22 :     CHIP_ERROR res = GetSocket(addrType);
      73              : 
      74           22 :     if (res == CHIP_NO_ERROR && reuseAddr)
      75              :     {
      76            1 :         int n = 1;
      77            1 :         setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
      78              : 
      79              : #ifdef SO_REUSEPORT
      80              :         // Enable SO_REUSEPORT.  This permits coexistence between an
      81              :         // untargetted CHIP client and other services that listen on
      82              :         // a CHIP port on a specific address (such as a CHIP client
      83              :         // with TARGETED_LISTEN or TCP proxying services).  Note that
      84              :         // one of the costs of this implementation is the
      85              :         // non-deterministic connection dispatch when multple clients
      86              :         // listen on the address with the same degreee of selectivity,
      87              :         // e.g. two untargetted-listen CHIP clients, or two
      88              :         // targeted-listen CHIP clients with the same node id.
      89              : 
      90            1 :         if (setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n)) != 0)
      91              :         {
      92            0 :             ChipLogError(Inet, "SO_REUSEPORT: %d", errno);
      93              :         }
      94              : #endif // defined(SO_REUSEPORT)
      95              :     }
      96              : 
      97           22 :     if (res == CHIP_NO_ERROR)
      98              :     {
      99              :         SockAddr sa;
     100           21 :         memset(&sa, 0, sizeof(sa));
     101           21 :         socklen_t sockaddrsize = 0;
     102              : 
     103           21 :         if (addrType == IPAddressType::kIPv6)
     104              :         {
     105           12 :             sa.in6.sin6_family   = AF_INET6;
     106           12 :             sa.in6.sin6_port     = htons(port);
     107           12 :             sa.in6.sin6_flowinfo = 0;
     108           12 :             sa.in6.sin6_addr     = addr.ToIPv6();
     109           12 :             sa.in6.sin6_scope_id = 0;
     110              : 
     111           12 :             sockaddrsize = sizeof(sa.in6);
     112              :         }
     113              : #if INET_CONFIG_ENABLE_IPV4
     114            9 :         else if (addrType == IPAddressType::kIPv4)
     115              :         {
     116            9 :             sa.in.sin_family = AF_INET;
     117            9 :             sa.in.sin_port   = htons(port);
     118            9 :             sa.in.sin_addr   = addr.ToIPv4();
     119              : 
     120            9 :             sockaddrsize = sizeof(sa.in);
     121              :         }
     122              : #endif // INET_CONFIG_ENABLE_IPV4
     123              :         else
     124              :         {
     125            0 :             res = INET_ERROR_WRONG_ADDRESS_TYPE;
     126              :         }
     127              : 
     128           21 :         if (res == CHIP_NO_ERROR)
     129              :         {
     130              :             // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
     131           21 :             if (bind(mSocket, &sa.any, sockaddrsize) != 0)
     132              :             {
     133            0 :                 res = CHIP_ERROR_POSIX(errno);
     134              :             }
     135              :         }
     136              :     }
     137              : 
     138           22 :     return res;
     139              : }
     140              : 
     141           21 : CHIP_ERROR TCPEndPointImplSockets::ListenImpl(uint16_t backlog)
     142              : {
     143           21 :     if (listen(mSocket, backlog) != 0)
     144              :     {
     145            0 :         return CHIP_ERROR_POSIX(errno);
     146              :     }
     147              : 
     148              :     // Enable non-blocking mode for the socket.
     149           21 :     int flags = fcntl(mSocket, F_GETFL, 0);
     150           21 :     fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
     151              : 
     152              :     // Wait for ability to read on this endpoint.
     153           21 :     CHIP_ERROR res = static_cast<System::LayerSockets &>(GetSystemLayer())
     154           21 :                          .SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this));
     155           21 :     if (res == CHIP_NO_ERROR)
     156              :     {
     157           21 :         res = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch);
     158              :     }
     159              : 
     160           21 :     return res;
     161              : }
     162              : 
     163           15 : CHIP_ERROR TCPEndPointImplSockets::ConnectImpl(const IPAddress & addr, uint16_t port, InterfaceId intfId)
     164              : {
     165           15 :     IPAddressType addrType = addr.Type();
     166              : 
     167           15 :     ReturnErrorOnFailure(GetSocket(addrType));
     168              : 
     169           15 :     if (!intfId.IsPresent())
     170              :     {
     171              :         // The behavior when connecting to an IPv6 link-local address without specifying an outbound
     172              :         // interface is ambiguous. So prevent it in all cases.
     173           15 :         if (addr.IsIPv6LinkLocal())
     174              :         {
     175            0 :             return INET_ERROR_WRONG_ADDRESS_TYPE;
     176              :         }
     177              :     }
     178              :     else
     179              :     {
     180              :         // Try binding to the interface
     181              : 
     182              :         // If destination is link-local then there is no need to bind to
     183              :         // interface or address on the interface.
     184              : 
     185            0 :         if (!addr.IsIPv6LinkLocal())
     186              :         {
     187              : #ifdef SO_BINDTODEVICE
     188              :             struct ::ifreq ifr;
     189            0 :             memset(&ifr, 0, sizeof(ifr));
     190              : 
     191            0 :             ReturnErrorOnFailure(intfId.GetInterfaceName(ifr.ifr_name, sizeof(ifr.ifr_name)));
     192              : 
     193              :             // Attempt to bind to the interface using SO_BINDTODEVICE which requires privileged access.
     194              :             // If the permission is denied(EACCES) because CHIP is running in a context
     195              :             // that does not have privileged access, choose a source address on the
     196              :             // interface to bind the connetion to.
     197            0 :             int r = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
     198            0 :             if (r < 0 && errno != EACCES)
     199              :             {
     200            0 :                 return CHIP_ERROR_POSIX(errno);
     201              :             }
     202              : 
     203            0 :             if (r < 0)
     204              : #endif // SO_BINDTODEVICE
     205              :             {
     206              :                 // Attempting to initiate a connection via a specific interface is not allowed.
     207              :                 // The only way to do this is to bind the local to an address on the desired
     208              :                 // interface.
     209            0 :                 ReturnErrorOnFailure(BindSrcAddrFromIntf(addrType, intfId));
     210              :             }
     211              :         }
     212              :     }
     213              : 
     214              :     // Disable generation of SIGPIPE.
     215              : #ifdef SO_NOSIGPIPE
     216              :     int n = 1;
     217              :     setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &n, sizeof(n));
     218              : #endif // defined(SO_NOSIGPIPE)
     219              : 
     220              :     // Enable non-blocking mode for the socket.
     221           15 :     int flags = fcntl(mSocket, F_GETFL, 0);
     222           15 :     fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
     223              : 
     224           15 :     socklen_t sockaddrsize = 0;
     225              : 
     226              :     SockAddr sa;
     227           15 :     memset(&sa, 0, sizeof(sa));
     228              : 
     229           15 :     if (addrType == IPAddressType::kIPv6)
     230              :     {
     231            8 :         sa.in6.sin6_family   = AF_INET6;
     232            8 :         sa.in6.sin6_port     = htons(port);
     233            8 :         sa.in6.sin6_flowinfo = 0;
     234            8 :         sa.in6.sin6_addr     = addr.ToIPv6();
     235            8 :         sa.in6.sin6_scope_id = intfId.GetPlatformInterface();
     236            8 :         sockaddrsize         = sizeof(sockaddr_in6);
     237              :     }
     238              : #if INET_CONFIG_ENABLE_IPV4
     239            7 :     else if (addrType == IPAddressType::kIPv4)
     240              :     {
     241            7 :         sa.in.sin_family = AF_INET;
     242            7 :         sa.in.sin_port   = htons(port);
     243            7 :         sa.in.sin_addr   = addr.ToIPv4();
     244            7 :         sockaddrsize     = sizeof(sockaddr_in);
     245              :     }
     246              : #endif // INET_CONFIG_ENABLE_IPV4
     247              :     else
     248              :     {
     249            0 :         return INET_ERROR_WRONG_ADDRESS_TYPE;
     250              :     }
     251              : 
     252              :     // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
     253           15 :     int conRes = connect(mSocket, &sa.any, sockaddrsize);
     254              : 
     255           15 :     if (conRes == -1 && errno != EINPROGRESS)
     256              :     {
     257            0 :         CHIP_ERROR res = CHIP_ERROR_POSIX(errno);
     258            0 :         DoClose(res, true);
     259            0 :         return res;
     260              :     }
     261              : 
     262           15 :     ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer())
     263              :                              .SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
     264              : 
     265           15 :     if (conRes == 0)
     266              :     {
     267            0 :         mState = State::kConnected;
     268              :         // Wait for ability to read on this endpoint.
     269            0 :         ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch));
     270            0 :         if (OnConnectComplete != nullptr)
     271              :         {
     272            0 :             OnConnectComplete(this, CHIP_NO_ERROR);
     273              :         }
     274              :     }
     275              :     else
     276              :     {
     277           15 :         mState = State::kConnecting;
     278              :         // Wait for ability to write on this endpoint.
     279           15 :         ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch));
     280              :     }
     281              : 
     282           15 :     return CHIP_NO_ERROR;
     283              : }
     284              : 
     285           29 : CHIP_ERROR TCPEndPointImplSockets::GetPeerInfo(IPAddress * retAddr, uint16_t * retPort) const
     286              : {
     287           29 :     return GetSocketInfo(getpeername, retAddr, retPort);
     288              : }
     289              : 
     290            1 : CHIP_ERROR TCPEndPointImplSockets::GetLocalInfo(IPAddress * retAddr, uint16_t * retPort) const
     291              : {
     292            1 :     return GetSocketInfo(getsockname, retAddr, retPort);
     293              : }
     294              : 
     295           30 : CHIP_ERROR TCPEndPointImplSockets::GetSocketInfo(int getname(int, sockaddr *, socklen_t *), IPAddress * retAddr,
     296              :                                                  uint16_t * retPort) const
     297              : {
     298           30 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     299              : 
     300              :     SockAddr sa;
     301           28 :     memset(&sa, 0, sizeof(sa));
     302           28 :     socklen_t saLen = sizeof(sa);
     303              : 
     304           28 :     if (getname(mSocket, &sa.any, &saLen) != 0)
     305              :     {
     306            0 :         return CHIP_ERROR_POSIX(errno);
     307              :     }
     308              : 
     309           28 :     if (sa.any.sa_family == AF_INET6)
     310              :     {
     311           16 :         *retAddr = IPAddress(sa.in6.sin6_addr);
     312           16 :         *retPort = ntohs(sa.in6.sin6_port);
     313           16 :         return CHIP_NO_ERROR;
     314              :     }
     315              : 
     316              : #if INET_CONFIG_ENABLE_IPV4
     317           12 :     if (sa.any.sa_family == AF_INET)
     318              :     {
     319           12 :         *retAddr = IPAddress(sa.in.sin_addr);
     320           12 :         *retPort = ntohs(sa.in.sin_port);
     321           12 :         return CHIP_NO_ERROR;
     322              :     }
     323              : #endif // INET_CONFIG_ENABLE_IPV4
     324              : 
     325            0 :     return CHIP_ERROR_INCORRECT_STATE;
     326              : }
     327              : 
     328           22 : CHIP_ERROR TCPEndPointImplSockets::GetInterfaceId(InterfaceId * retInterface)
     329              : {
     330           22 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     331              : 
     332              :     SockAddr sa;
     333           22 :     memset(&sa, 0, sizeof(sa));
     334           22 :     socklen_t saLen = sizeof(sa);
     335              : 
     336           22 :     if (getpeername(mSocket, &sa.any, &saLen) != 0)
     337              :     {
     338            0 :         return CHIP_ERROR_POSIX(errno);
     339              :     }
     340              : 
     341           22 :     if (sa.any.sa_family == AF_INET6)
     342              :     {
     343           12 :         if (IPAddress(sa.in6.sin6_addr).IsIPv6LinkLocal())
     344              :         {
     345            0 :             *retInterface = InterfaceId(sa.in6.sin6_scope_id);
     346              :         }
     347              :         else
     348              :         {
     349              :             // TODO: Is there still a meaningful interface id in this case?
     350           12 :             *retInterface = InterfaceId::Null();
     351              :         }
     352           12 :         return CHIP_NO_ERROR;
     353              :     }
     354              : 
     355              : #if INET_CONFIG_ENABLE_IPV4
     356           10 :     if (sa.any.sa_family == AF_INET)
     357              :     {
     358              :         // No interface id available for IPv4 sockets.
     359           10 :         *retInterface = InterfaceId::Null();
     360           10 :         return CHIP_NO_ERROR;
     361              :     }
     362              : #endif // INET_CONFIG_ENABLE_IPV4
     363              : 
     364            0 :     *retInterface = InterfaceId::Null();
     365            0 :     return INET_ERROR_WRONG_ADDRESS_TYPE;
     366              : }
     367              : 
     368           11 : CHIP_ERROR TCPEndPointImplSockets::SendQueuedImpl(bool queueWasEmpty)
     369              : {
     370           11 :     if (queueWasEmpty)
     371              :     {
     372              :         // Wait for ability to write on this endpoint.
     373           11 :         return static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch);
     374              :     }
     375            0 :     return CHIP_NO_ERROR;
     376              : }
     377              : 
     378           28 : CHIP_ERROR TCPEndPointImplSockets::EnableNoDelay()
     379              : {
     380           28 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     381              : 
     382              : #ifdef TCP_NODELAY
     383              :     // Disable TCP Nagle buffering by setting TCP_NODELAY socket option to true
     384           28 :     int val = 1;
     385           28 :     if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_NODELAY, &val, sizeof(val)) != 0)
     386              :     {
     387            0 :         return CHIP_ERROR_POSIX(errno);
     388              :     }
     389              : #endif // defined(TCP_NODELAY)
     390              : 
     391           28 :     return CHIP_NO_ERROR;
     392              : }
     393              : 
     394           29 : CHIP_ERROR TCPEndPointImplSockets::EnableKeepAlive(uint16_t interval, uint16_t timeoutCount)
     395              : {
     396           29 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     397              : 
     398              :     // Set the idle interval
     399           28 :     int val = interval;
     400           28 :     if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_IDLE_INTERVAL_OPT_NAME, &val, sizeof(val)) != 0)
     401              :     {
     402            0 :         return CHIP_ERROR_POSIX(errno);
     403              :     }
     404              : 
     405              :     // Set the probe retransmission interval.
     406           28 :     val = interval;
     407           28 :     if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_KEEPINTVL, &val, sizeof(val)) != 0)
     408              :     {
     409            0 :         return CHIP_ERROR_POSIX(errno);
     410              :     }
     411              : 
     412              :     // Set the probe timeout count
     413           28 :     val = timeoutCount;
     414           28 :     if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_KEEPCNT, &val, sizeof(val)) != 0)
     415              :     {
     416            0 :         return CHIP_ERROR_POSIX(errno);
     417              :     }
     418              : 
     419              :     // Enable keepalives for the connection.
     420           28 :     val = 1; // enable
     421           28 :     if (setsockopt(mSocket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0)
     422              :     {
     423            0 :         return CHIP_ERROR_POSIX(errno);
     424              :     }
     425              : 
     426           28 :     return CHIP_NO_ERROR;
     427              : }
     428              : 
     429            1 : CHIP_ERROR TCPEndPointImplSockets::DisableKeepAlive()
     430              : {
     431            1 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     432              : 
     433              :     // Disable keepalives on the connection.
     434            0 :     int val = 0; // disable
     435            0 :     if (setsockopt(mSocket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0)
     436              :     {
     437            0 :         return CHIP_ERROR_POSIX(errno);
     438              :     }
     439              : 
     440            0 :     return CHIP_NO_ERROR;
     441              : }
     442              : 
     443           10 : CHIP_ERROR TCPEndPointImplSockets::AckReceive(size_t len)
     444              : {
     445           10 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     446              : 
     447              :     // nothing to do for sockets case
     448            9 :     return CHIP_NO_ERROR;
     449              : }
     450              : 
     451            0 : CHIP_ERROR TCPEndPointImplSockets::SetUserTimeoutImpl(uint32_t userTimeoutMillis)
     452              : {
     453              : #if defined(TCP_USER_TIMEOUT)
     454              :     // Set the user timeout
     455            0 :     uint32_t val = userTimeoutMillis;
     456            0 :     if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_USER_TIMEOUT, &val, sizeof(val)) != 0)
     457              :     {
     458            0 :         return CHIP_ERROR_POSIX(errno);
     459              :     }
     460            0 :     return CHIP_NO_ERROR;
     461              : #else  // TCP_USER_TIMEOUT
     462              :     return CHIP_ERROR_NOT_IMPLEMENTED;
     463              : #endif // defined(TCP_USER_TIMEOUT)
     464              : }
     465              : 
     466           11 : CHIP_ERROR TCPEndPointImplSockets::DriveSendingImpl()
     467              : {
     468           11 :     CHIP_ERROR err = CHIP_NO_ERROR;
     469              : 
     470              : #ifdef MSG_NOSIGNAL
     471           11 :     const int sendFlags = MSG_NOSIGNAL;
     472              : #else
     473              :     const int sendFlags = 0;
     474              : #endif
     475              : 
     476              :     // Pretend send() fails in the while loop below
     477           11 :     INET_FAULT_INJECT(FaultInjection::kFault_Send, {
     478              :         err = CHIP_ERROR_POSIX(EIO);
     479              :         DoClose(err, false);
     480              :         return err;
     481              :     });
     482              : 
     483           24 :     while (!mSendQueue.IsNull())
     484              :     {
     485           13 :         size_t bufLen = mSendQueue->DataLength();
     486              : 
     487           13 :         ssize_t lenSentRaw = send(mSocket, mSendQueue->Start(), bufLen, sendFlags);
     488              : 
     489           13 :         if (lenSentRaw == -1)
     490              :         {
     491            0 :             if (errno != EAGAIN && errno != EWOULDBLOCK)
     492              :             {
     493            0 :                 err = (errno == EPIPE) ? INET_ERROR_PEER_DISCONNECTED : CHIP_ERROR_POSIX(errno);
     494              :             }
     495            0 :             break;
     496              :         }
     497              : 
     498           13 :         if (lenSentRaw < 0 || bufLen < static_cast<size_t>(lenSentRaw))
     499              :         {
     500            0 :             err = CHIP_ERROR_INCORRECT_STATE;
     501            0 :             break;
     502              :         }
     503              : 
     504           13 :         size_t lenSent = static_cast<size_t>(lenSentRaw);
     505              : 
     506              :         // Mark the connection as being active.
     507           13 :         MarkActive();
     508              : 
     509           13 :         if (lenSent < bufLen)
     510              :         {
     511            0 :             mSendQueue->ConsumeHead(lenSent);
     512              :         }
     513              :         else
     514              :         {
     515           13 :             mSendQueue.FreeHead();
     516           13 :             if (mSendQueue.IsNull())
     517              :             {
     518              :                 // Do not wait for ability to write on this endpoint.
     519           11 :                 err = static_cast<System::LayerSockets &>(GetSystemLayer()).ClearCallbackOnPendingWrite(mWatch);
     520           11 :                 if (err != CHIP_NO_ERROR)
     521              :                 {
     522            0 :                     break;
     523              :                 }
     524              :             }
     525              :         }
     526              : 
     527           13 :         if (OnDataSent != nullptr)
     528              :         {
     529            0 :             OnDataSent(this, lenSent);
     530              :         }
     531              : 
     532              : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     533           13 :         mBytesWrittenSinceLastProbe += lenSent;
     534              : 
     535           13 :         bool isProgressing = false;
     536              : 
     537           13 :         err = CheckConnectionProgress(isProgressing);
     538           13 :         if (err != CHIP_NO_ERROR)
     539              :         {
     540            0 :             break;
     541              :         }
     542              : 
     543           13 :         if (!mUserTimeoutTimerRunning)
     544              :         {
     545              :             // Timer was not running before this write. So, start
     546              :             // the timer.
     547              : 
     548            9 :             StartTCPUserTimeoutTimer();
     549              :         }
     550            4 :         else if (isProgressing)
     551              :         {
     552              :             // Progress is being made. So, shift the timer
     553              :             // forward if it was started.
     554              : 
     555            4 :             RestartTCPUserTimeoutTimer();
     556              :         }
     557              : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     558              : 
     559           13 :         if (lenSent < bufLen)
     560              :         {
     561            0 :             break;
     562              :         }
     563              :     }
     564              : 
     565           11 :     if (err == CHIP_NO_ERROR)
     566              :     {
     567              :         // If we're in the SendShutdown state and the send queue is now empty, shutdown writing on the socket.
     568           11 :         if (mState == State::kSendShutdown && mSendQueue.IsNull())
     569              :         {
     570            0 :             if (shutdown(mSocket, SHUT_WR) != 0)
     571              :             {
     572            0 :                 err = CHIP_ERROR_POSIX(errno);
     573              :             }
     574              :         }
     575              :     }
     576              : 
     577           11 :     return err;
     578              : }
     579              : 
     580           15 : void TCPEndPointImplSockets::HandleConnectCompleteImpl()
     581              : {
     582              :     // Wait for ability to read or write on this endpoint.
     583           15 :     CHIP_ERROR err = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch);
     584           15 :     if (err == CHIP_NO_ERROR)
     585              :     {
     586           15 :         err = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch);
     587              :     }
     588           15 :     if (err != CHIP_NO_ERROR)
     589              :     {
     590            0 :         DoClose(err, false);
     591            0 :         return;
     592              :     }
     593              : }
     594              : 
     595           54 : void TCPEndPointImplSockets::DoCloseImpl(CHIP_ERROR err, State oldState)
     596              : {
     597              :     struct linger lingerStruct;
     598              : 
     599              :     // If the socket hasn't been closed already...
     600           54 :     if (mSocket != kInvalidSocketFd)
     601              :     {
     602              :         // If entering the Closed state
     603              :         // OR if entering the Closing state, and there's no unsent data in the send queue
     604              :         // THEN close the socket.
     605           49 :         if (mState == State::kClosed || (mState == State::kClosing && mSendQueue.IsNull()))
     606              :         {
     607              :             // If aborting the connection, ensure we send a TCP RST.
     608           49 :             if (IsConnected(oldState) && err != CHIP_NO_ERROR)
     609              :             {
     610           26 :                 lingerStruct.l_onoff  = 1;
     611           26 :                 lingerStruct.l_linger = 0;
     612              : 
     613           26 :                 if (setsockopt(mSocket, SOL_SOCKET, SO_LINGER, &lingerStruct, sizeof(lingerStruct)) != 0)
     614              :                 {
     615            0 :                     ChipLogError(Inet, "SO_LINGER: %d", errno);
     616              :                 }
     617              :             }
     618              : 
     619           49 :             static_cast<System::LayerSockets &>(GetSystemLayer()).StopWatchingSocket(&mWatch);
     620           49 :             close(mSocket);
     621           49 :             mSocket = kInvalidSocketFd;
     622              :         }
     623              :     }
     624           54 : }
     625              : 
     626              : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     627            0 : void TCPEndPointImplSockets::TCPUserTimeoutHandler()
     628              : {
     629              :     // Set the timer running flag to false
     630            0 :     mUserTimeoutTimerRunning = false;
     631              : 
     632            0 :     bool isProgressing = false;
     633            0 :     CHIP_ERROR err     = CheckConnectionProgress(isProgressing);
     634              : 
     635            0 :     if (err == CHIP_NO_ERROR && mLastTCPKernelSendQueueLen != 0)
     636              :     {
     637              :         // There is data in the TCP Send Queue
     638            0 :         if (isProgressing)
     639              :         {
     640              :             // Data is flowing, so restart the UserTimeout timer
     641              :             // to shift it forward while also resetting the max
     642              :             // poll count.
     643              : 
     644            0 :             StartTCPUserTimeoutTimer();
     645              :         }
     646              :         else
     647              :         {
     648              :             // Close the connection as the TCP UserTimeout has expired
     649            0 :             err = INET_ERROR_TCP_USER_TIMEOUT;
     650              :         }
     651              :     }
     652              : 
     653            0 :     if (err != CHIP_NO_ERROR)
     654              :     {
     655              :         // Close the connection as the TCP UserTimeout has expired
     656            0 :         DoClose(err, false);
     657              :     }
     658            0 : }
     659              : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     660              : 
     661            0 : CHIP_ERROR TCPEndPointImplSockets::BindSrcAddrFromIntf(IPAddressType addrType, InterfaceId intfId)
     662              : {
     663              :     // If we are trying to make a TCP connection over a 'specified target interface',
     664              :     // then we bind the TCPEndPoint to an IP address on that target interface
     665              :     // and use that address as the source address for that connection. This is
     666              :     // done in the event that directly binding the connection to the target
     667              :     // interface is not allowed due to insufficient privileges.
     668            0 :     VerifyOrReturnError(mState != State::kBound, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
     669              : 
     670            0 :     bool ipAddrFound = false;
     671            0 :     for (InterfaceAddressIterator addrIter; addrIter.HasCurrent(); addrIter.Next())
     672              :     {
     673              :         IPAddress curAddr;
     674            0 :         if ((addrIter.GetInterfaceId() == intfId) && (addrIter.GetAddress(curAddr) == CHIP_NO_ERROR))
     675              :         {
     676              :             // Search for an IPv4 address on the TargetInterface
     677              : 
     678              : #if INET_CONFIG_ENABLE_IPV4
     679            0 :             if (addrType == IPAddressType::kIPv4)
     680              :             {
     681            0 :                 if (curAddr.IsIPv4())
     682              :                 {
     683              :                     // Bind to the IPv4 address of the TargetInterface
     684            0 :                     ipAddrFound = true;
     685            0 :                     ReturnErrorOnFailure(Bind(IPAddressType::kIPv4, curAddr, 0, true));
     686              : 
     687            0 :                     break;
     688              :                 }
     689              :             }
     690              : #endif // INET_CONFIG_ENABLE_IPV4
     691            0 :             if (addrType == IPAddressType::kIPv6)
     692              :             {
     693              :                 // Select an IPv6 address on the interface that is not
     694              :                 // a link local or a multicast address.
     695              :                 // TODO: Define a proper IPv6GlobalUnicast address checker.
     696            0 :                 if (!curAddr.IsIPv4() && !curAddr.IsIPv6LinkLocal() && !curAddr.IsMulticast())
     697              :                 {
     698              :                     // Bind to the IPv6 address of the TargetInterface
     699            0 :                     ipAddrFound = true;
     700            0 :                     ReturnErrorOnFailure(Bind(IPAddressType::kIPv6, curAddr, 0, true));
     701              : 
     702            0 :                     break;
     703              :                 }
     704              :             }
     705              :         }
     706            0 :     }
     707              : 
     708            0 :     VerifyOrReturnError(ipAddrFound, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
     709              : 
     710            0 :     return CHIP_NO_ERROR;
     711              : }
     712              : 
     713           37 : CHIP_ERROR TCPEndPointImplSockets::GetSocket(IPAddressType addrType)
     714              : {
     715           37 :     if (mSocket == kInvalidSocketFd)
     716              :     {
     717              :         int family;
     718           37 :         if (addrType == IPAddressType::kIPv6)
     719              :         {
     720           20 :             family = PF_INET6;
     721              : #if INET_CONFIG_ENABLE_IPV4
     722              :         }
     723           17 :         else if (addrType == IPAddressType::kIPv4)
     724              :         {
     725           16 :             family = PF_INET;
     726              : #endif // INET_CONFIG_ENABLE_IPV4
     727              :         }
     728              :         else
     729              :         {
     730            1 :             return INET_ERROR_WRONG_ADDRESS_TYPE;
     731              :         }
     732           36 :         mSocket = ::socket(family, SOCK_STREAM | SOCK_CLOEXEC, 0);
     733           36 :         if (mSocket == -1)
     734              :         {
     735            0 :             return CHIP_ERROR_POSIX(errno);
     736              :         }
     737           36 :         ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).StartWatchingSocket(mSocket, &mWatch));
     738           36 :         mAddrType = addrType;
     739              : 
     740              :         // If creating an IPv6 socket, tell the kernel that it will be IPv6 only.  This makes it
     741              :         // posible to bind two sockets to the same port, one for IPv4 and one for IPv6.
     742              : #ifdef IPV6_V6ONLY
     743           36 :         if (family == PF_INET6)
     744              :         {
     745           20 :             int one = 1;
     746           20 :             setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
     747              :         }
     748              : #endif // defined(IPV6_V6ONLY)
     749              : 
     750              :         // On systems that support it, disable the delivery of SIGPIPE signals when writing to a closed
     751              :         // socket.
     752              : #ifdef SO_NOSIGPIPE
     753              :         {
     754              :             int one = 1;
     755              :             int res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
     756              :             if (res != 0)
     757              :             {
     758              :                 ChipLogError(Inet, "SO_NOSIGPIPE: %d", errno);
     759              :             }
     760              :         }
     761              : #endif // defined(SO_NOSIGPIPE)
     762              :     }
     763            0 :     else if (mAddrType != addrType)
     764              :     {
     765            0 :         return CHIP_ERROR_INCORRECT_STATE;
     766              :     }
     767              : 
     768           36 :     return CHIP_NO_ERROR;
     769              : }
     770              : 
     771              : // static
     772           44 : void TCPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
     773              : {
     774           44 :     reinterpret_cast<TCPEndPointImplSockets *>(data)->HandlePendingIO(events);
     775           44 : }
     776              : 
     777           44 : void TCPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
     778              : {
     779              :     // Prevent the end point from being freed while in the middle of a callback.
     780           44 :     Retain();
     781              : 
     782              :     // If in the Listening state, and the app is ready to receive a connection, and there is a connection
     783              :     // ready to be received on the socket, process the incoming connection.
     784           44 :     if (mState == State::kListening)
     785              :     {
     786           15 :         if (OnConnectionReceived != nullptr && events.Has(System::SocketEventFlags::kRead))
     787              :         {
     788           15 :             HandleIncomingConnection();
     789              :         }
     790              :     }
     791              : 
     792              :     // If in the processes of initiating a connection...
     793           29 :     else if (mState == State::kConnecting)
     794              :     {
     795              :         // The socket being writable indicates the connection has completed (successfully or otherwise).
     796           15 :         if (events.Has(System::SocketEventFlags::kWrite))
     797              :         {
     798              : #ifndef __MBED__
     799              :             // Get the connection result from the socket.
     800              :             int osConRes;
     801           15 :             socklen_t optLen = sizeof(osConRes);
     802           15 :             if (getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &osConRes, &optLen) != 0)
     803              :             {
     804            0 :                 osConRes = errno;
     805              :             }
     806              : #else  // __MBED__
     807              :        // On Mbed OS, connect blocks and never returns EINPROGRESS
     808              :        // The socket option SO_ERROR is not available.
     809              :             int osConRes     = 0;
     810              : #endif // !__MBED__
     811           15 :             CHIP_ERROR conRes = CHIP_ERROR_POSIX(osConRes);
     812              : 
     813              :             // Process the connection result.
     814           15 :             HandleConnectComplete(conRes);
     815              :         }
     816              :     }
     817              : 
     818              :     else
     819              :     {
     820              :         // If in a state where sending is allowed, and there is data to be sent, and the socket is ready for
     821              :         // writing, drive outbound data into the connection.
     822           14 :         if (IsConnected() && !mSendQueue.IsNull() && events.Has(System::SocketEventFlags::kWrite))
     823              :         {
     824            0 :             DriveSending();
     825              :         }
     826              : 
     827              :         // If in a state were receiving is allowed, and the app is ready to receive data, and data is ready
     828              :         // on the socket, receive inbound data from the connection.
     829           28 :         if ((mState == State::kConnected || mState == State::kSendShutdown) && mReceiveEnabled && OnDataReceived != nullptr &&
     830           14 :             events.Has(System::SocketEventFlags::kRead))
     831              :         {
     832           14 :             ReceiveData();
     833              :         }
     834              :     }
     835              : 
     836           44 :     Release();
     837           44 : }
     838              : 
     839           14 : void TCPEndPointImplSockets::ReceiveData()
     840              : {
     841           14 :     System::PacketBufferHandle rcvBuf;
     842           14 :     bool isNewBuf = true;
     843              : 
     844           14 :     if (mRcvQueue.IsNull())
     845              :     {
     846           14 :         rcvBuf = System::PacketBufferHandle::New(kMaxReceiveMessageSize, 0);
     847              :     }
     848              :     else
     849              :     {
     850            0 :         rcvBuf = mRcvQueue->Last();
     851            0 :         if (rcvBuf->AvailableDataLength() == 0)
     852              :         {
     853            0 :             rcvBuf = System::PacketBufferHandle::New(kMaxReceiveMessageSize, 0);
     854              :         }
     855              :         else
     856              :         {
     857            0 :             isNewBuf = false;
     858            0 :             rcvBuf->CompactHead();
     859              :         }
     860              :     }
     861              : 
     862           14 :     if (rcvBuf.IsNull())
     863              :     {
     864            0 :         DoClose(CHIP_ERROR_NO_MEMORY, false);
     865            0 :         return;
     866              :     }
     867              : 
     868              :     // Attempt to receive data from the socket.
     869           14 :     ssize_t rcvLen = recv(mSocket, rcvBuf->Start() + rcvBuf->DataLength(), rcvBuf->AvailableDataLength(), 0);
     870              : 
     871              : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     872              :     CHIP_ERROR err;
     873           14 :     bool isProgressing = false;
     874              : 
     875           14 :     err = CheckConnectionProgress(isProgressing);
     876           14 :     if (err != CHIP_NO_ERROR)
     877              :     {
     878            0 :         DoClose(err, false);
     879              : 
     880            0 :         return;
     881              :     }
     882              : 
     883           14 :     if (mLastTCPKernelSendQueueLen == 0)
     884              :     {
     885              :         // If the output queue has been flushed then stop the timer.
     886              : 
     887           14 :         StopTCPUserTimeoutTimer();
     888              :     }
     889            0 :     else if (isProgressing && mUserTimeoutTimerRunning)
     890              :     {
     891              :         // Progress is being made. So, shift the timer
     892              :         // forward if it was started.
     893            0 :         RestartTCPUserTimeoutTimer();
     894              :     }
     895              : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     896              :     // If an error occurred, abort the connection.
     897           14 :     if (rcvLen < 0)
     898              :     {
     899            5 :         int systemErrno = errno;
     900            5 :         if (systemErrno == EAGAIN)
     901              :         {
     902              :             // Note: in this case, we opt to not retry the recv call,
     903              :             // and instead we expect that the read flags will get
     904              :             // reset correctly upon a subsequent return from the
     905              :             // select call.
     906            0 :             ChipLogError(Inet, "recv: EAGAIN, will retry");
     907              : 
     908            0 :             return;
     909              :         }
     910              : 
     911            5 :         DoClose(CHIP_ERROR_POSIX(systemErrno), false);
     912              :     }
     913              : 
     914              :     else
     915              :     {
     916              :         // Mark the connection as being active.
     917            9 :         MarkActive();
     918              : 
     919              :         // If the peer closed their end of the connection...
     920            9 :         if (rcvLen == 0)
     921              :         {
     922              :             // If in the Connected state and the app has provided an OnPeerClose callback,
     923              :             // enter the ReceiveShutdown state.  Providing an OnPeerClose callback allows
     924              :             // the app to decide whether to keep the send side of the connection open after
     925              :             // the peer has closed. If no OnPeerClose is provided, we assume that the app
     926              :             // wants to close both directions and automatically enter the Closing state.
     927            0 :             if (mState == State::kConnected && OnPeerClose != nullptr)
     928              :             {
     929            0 :                 mState = State::kReceiveShutdown;
     930              :             }
     931              :             else
     932              :             {
     933            0 :                 mState = State::kClosing;
     934              :             }
     935              :             // Do not wait for ability to read on this endpoint.
     936            0 :             (void) static_cast<System::LayerSockets &>(GetSystemLayer()).ClearCallbackOnPendingRead(mWatch);
     937              :             // Call the app's OnPeerClose.
     938            0 :             if (OnPeerClose != nullptr)
     939              :             {
     940            0 :                 OnPeerClose(this);
     941              :             }
     942              :         }
     943              : 
     944              :         // Otherwise, add the new data onto the receive queue.
     945              :         else
     946              :         {
     947            9 :             VerifyOrDie(rcvLen > 0);
     948            9 :             size_t newDataLength = rcvBuf->DataLength() + static_cast<size_t>(rcvLen);
     949            9 :             if (isNewBuf)
     950              :             {
     951            9 :                 rcvBuf->SetDataLength(newDataLength);
     952            9 :                 rcvBuf.RightSize();
     953            9 :                 if (mRcvQueue.IsNull())
     954              :                 {
     955            9 :                     mRcvQueue = std::move(rcvBuf);
     956              :                 }
     957              :                 else
     958              :                 {
     959            0 :                     mRcvQueue->AddToEnd(std::move(rcvBuf));
     960              :                 }
     961              :             }
     962              :             else
     963              :             {
     964            0 :                 rcvBuf->SetDataLength(newDataLength, mRcvQueue);
     965              :             }
     966              :         }
     967              :     }
     968              : 
     969              :     // Drive any received data into the app.
     970           14 :     DriveReceiving();
     971           14 : }
     972              : 
     973           15 : void TCPEndPointImplSockets::HandleIncomingConnection()
     974              : {
     975           15 :     CHIP_ERROR err                 = CHIP_NO_ERROR;
     976           15 :     TCPEndPointImplSockets * conEP = nullptr;
     977              :     IPAddress peerAddr;
     978              :     uint16_t peerPort;
     979              : 
     980              :     SockAddr sa;
     981           15 :     memset(&sa, 0, sizeof(sa));
     982           15 :     socklen_t saLen = sizeof(sa);
     983              : 
     984              :     // Accept the new connection.
     985           15 :     int conSocket = accept(mSocket, &sa.any, &saLen);
     986           15 :     if (conSocket == -1)
     987              :     {
     988            0 :         if (errno == EAGAIN || errno == EWOULDBLOCK)
     989              :         {
     990           13 :             return;
     991              :         }
     992              : 
     993            0 :         err = CHIP_ERROR_POSIX(errno);
     994              :     }
     995              : 
     996              :     // If there's no callback available, fail with an error.
     997           15 :     if (err == CHIP_NO_ERROR && OnConnectionReceived == nullptr)
     998              :     {
     999            0 :         err = CHIP_ERROR_NO_CONNECTION_HANDLER;
    1000              :     }
    1001              : 
    1002              :     // Extract the peer's address information.
    1003           15 :     if (err == CHIP_NO_ERROR)
    1004              :     {
    1005           15 :         if (sa.any.sa_family == AF_INET6)
    1006              :         {
    1007            8 :             peerAddr = IPAddress(sa.in6.sin6_addr);
    1008            8 :             peerPort = ntohs(sa.in6.sin6_port);
    1009              :         }
    1010              : #if INET_CONFIG_ENABLE_IPV4
    1011            7 :         else if (sa.any.sa_family == AF_INET)
    1012              :         {
    1013            7 :             peerAddr = IPAddress(sa.in.sin_addr);
    1014            7 :             peerPort = ntohs(sa.in.sin_port);
    1015              :         }
    1016              : #endif // INET_CONFIG_ENABLE_IPV4
    1017              :         else
    1018              :         {
    1019            0 :             err = CHIP_ERROR_INCORRECT_STATE;
    1020              :         }
    1021              :     }
    1022              : 
    1023              : #if INET_CONFIG_TEST
    1024           15 :     if (TCPEndPoint::sForceEarlyFailureIncomingConnection)
    1025              :     {
    1026            2 :         err = CHIP_ERROR_INCORRECT_STATE;
    1027              :     }
    1028              : #endif
    1029              : 
    1030              :     // Attempt to allocate an end point object.
    1031           15 :     if (err == CHIP_NO_ERROR)
    1032              :     {
    1033           13 :         TCPEndPoint * connectEndPoint = nullptr;
    1034           13 :         err                           = GetEndPointManager().NewEndPoint(&connectEndPoint);
    1035           13 :         conEP                         = static_cast<TCPEndPointImplSockets *>(connectEndPoint);
    1036              :     }
    1037              : 
    1038              :     // If all went well...
    1039           15 :     if (err == CHIP_NO_ERROR)
    1040              :     {
    1041              :         // Put the new end point into the Connected state.
    1042           13 :         conEP->mSocket = conSocket;
    1043           13 :         err            = static_cast<System::LayerSockets &>(GetSystemLayer()).StartWatchingSocket(conSocket, &conEP->mWatch);
    1044           13 :         if (err == CHIP_NO_ERROR)
    1045              :         {
    1046           13 :             conEP->mState = State::kConnected;
    1047              : #if INET_CONFIG_ENABLE_IPV4
    1048           13 :             conEP->mAddrType = (sa.any.sa_family == AF_INET6) ? IPAddressType::kIPv6 : IPAddressType::kIPv4;
    1049              : #else  // !INET_CONFIG_ENABLE_IPV4
    1050              :             conEP->mAddrType = IPAddressType::kIPv6;
    1051              : #endif // !INET_CONFIG_ENABLE_IPV4
    1052              : 
    1053              :             // Wait for ability to read on this endpoint.
    1054           13 :             auto & conEPLayer = static_cast<System::LayerSockets &>(conEP->GetSystemLayer());
    1055           13 :             err               = conEPLayer.SetCallback(conEP->mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(conEP));
    1056           13 :             if (err == CHIP_NO_ERROR)
    1057              :             {
    1058           13 :                 err = conEPLayer.RequestCallbackOnPendingRead(conEP->mWatch);
    1059              :             }
    1060           13 :             if (err == CHIP_NO_ERROR)
    1061              :             {
    1062              :                 // Call the app's callback function.
    1063           13 :                 OnConnectionReceived(this, conEP, peerAddr, peerPort);
    1064           13 :                 return;
    1065              :             }
    1066              :         }
    1067              :     }
    1068              : 
    1069              :     // Otherwise immediately close the connection, clean up and call the app's error callback.
    1070            2 :     if (conSocket != -1)
    1071              :     {
    1072            2 :         close(conSocket);
    1073              :     }
    1074            2 :     if (conEP != nullptr)
    1075              :     {
    1076            0 :         conEP->Release();
    1077              :     }
    1078            2 :     if (OnAcceptError != nullptr)
    1079              :     {
    1080            2 :         OnAcceptError(this, err);
    1081              :     }
    1082              : }
    1083              : 
    1084              : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
    1085              : /**
    1086              :  *  This function probes the TCP output queue and checks if data is successfully
    1087              :  *  being transferred to the other end.
    1088              :  */
    1089           27 : CHIP_ERROR TCPEndPointImplSockets::CheckConnectionProgress(bool & isProgressing)
    1090              : {
    1091           27 :     int currPendingBytesRaw = 0;
    1092              :     uint32_t currPendingBytes; // Will be initialized once we know it's safe.
    1093              : 
    1094              :     // Fetch the bytes pending successful transmission in the TCP out queue.
    1095              : 
    1096              : #ifdef __APPLE__
    1097              :     socklen_t len = sizeof(currPendingBytesRaw);
    1098              :     if (getsockopt(mSocket, SOL_SOCKET, SO_NWRITE, &currPendingBytesRaw, &len) < 0)
    1099              : #else
    1100           27 :     if (ioctl(mSocket, TIOCOUTQ, &currPendingBytesRaw) < 0)
    1101              : #endif
    1102              :     {
    1103            0 :         return CHIP_ERROR_POSIX(errno);
    1104              :     }
    1105              : 
    1106           27 :     if (!CanCastTo<uint32_t>(currPendingBytesRaw))
    1107              :     {
    1108            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1109              :     }
    1110              : 
    1111           27 :     currPendingBytes = static_cast<uint32_t>(currPendingBytesRaw);
    1112              : 
    1113           27 :     if ((currPendingBytes != 0) && (mBytesWrittenSinceLastProbe + mLastTCPKernelSendQueueLen == currPendingBytes))
    1114              :     {
    1115              :         // No progress has been made
    1116              : 
    1117            0 :         isProgressing = false;
    1118              :     }
    1119              :     else
    1120              :     {
    1121              :         // Data is flowing successfully
    1122              : 
    1123           27 :         isProgressing = true;
    1124              :     }
    1125              : 
    1126              :     // Reset the value of the bytes written since the last probe into the tcp
    1127              :     // outqueue was made and update the last tcp outqueue sample.
    1128              : 
    1129           27 :     mBytesWrittenSinceLastProbe = 0;
    1130              : 
    1131           27 :     mLastTCPKernelSendQueueLen = currPendingBytes;
    1132              : 
    1133           27 :     return CHIP_NO_ERROR;
    1134              : }
    1135              : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
    1136              : 
    1137              : } // namespace Inet
    1138              : } // namespace chip
        

Generated by: LCOV version 2.0-1