LCOV - code coverage report
Current view: top level - inet - TCPEndPointImplSockets.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 250 394 63.5 %
Date: 2024-02-15 08:20:41 Functions: 20 24 83.3 %

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

Generated by: LCOV version 1.14