Matter SDK Coverage Report
Current view: top level - inet - TCPEndPointImplSockets.cpp (source / functions) Coverage Total Hit
Test: SHA:e98a48c2e59f85a25417956e1d105721433aa5d1 Lines: 70.3 % 397 279
Test Date: 2026-01-09 16:53:50 Functions: 81.5 % 27 22

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2025 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           24 : CHIP_ERROR TCPEndPointImplSockets::BindImpl(IPAddressType addrType, const IPAddress & addr, uint16_t port, bool reuseAddr)
      71              : {
      72           24 :     CHIP_ERROR res = GetSocket(addrType);
      73              : 
      74           48 :     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           48 :     if (res == CHIP_NO_ERROR)
      98              :     {
      99              :         SockAddr sa;
     100           23 :         memset(&sa, 0, sizeof(sa));
     101           23 :         socklen_t sockaddrsize = 0;
     102              : 
     103           23 :         if (addrType == IPAddressType::kIPv6)
     104              :         {
     105           13 :             sa.in6.sin6_family   = AF_INET6;
     106           13 :             sa.in6.sin6_port     = htons(port);
     107           13 :             sa.in6.sin6_flowinfo = 0;
     108           13 :             sa.in6.sin6_addr     = addr.ToIPv6();
     109           13 :             sa.in6.sin6_scope_id = 0;
     110              : 
     111           13 :             sockaddrsize = sizeof(sa.in6);
     112              :         }
     113              : #if INET_CONFIG_ENABLE_IPV4
     114           10 :         else if (addrType == IPAddressType::kIPv4)
     115              :         {
     116           10 :             sa.in.sin_family = AF_INET;
     117           10 :             sa.in.sin_port   = htons(port);
     118           10 :             sa.in.sin_addr   = addr.ToIPv4();
     119              : 
     120           10 :             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           46 :         if (res == CHIP_NO_ERROR)
     129              :         {
     130              :             // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
     131           23 :             if (bind(mSocket, &sa.any, sockaddrsize) != 0)
     132              :             {
     133            0 :                 res = CHIP_ERROR_POSIX(errno);
     134              :             }
     135              :         }
     136              :     }
     137              : 
     138           24 :     return res;
     139              : }
     140              : 
     141           23 : CHIP_ERROR TCPEndPointImplSockets::ListenImpl(uint16_t backlog)
     142              : {
     143           23 :     if (listen(mSocket, backlog) != 0)
     144              :     {
     145            0 :         return CHIP_ERROR_POSIX(errno);
     146              :     }
     147              : 
     148              :     // Enable non-blocking mode for the socket.
     149           23 :     int flags = fcntl(mSocket, F_GETFL, 0);
     150           23 :     fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
     151              : 
     152              :     // Wait for ability to read on this endpoint.
     153           23 :     CHIP_ERROR res = static_cast<System::LayerSockets &>(GetSystemLayer())
     154           23 :                          .SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this));
     155           46 :     if (res == CHIP_NO_ERROR)
     156              :     {
     157           23 :         res = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch);
     158              :     }
     159              : 
     160           23 :     return res;
     161              : }
     162              : 
     163           17 : CHIP_ERROR TCPEndPointImplSockets::ConnectImpl(const IPAddress & addr, uint16_t port, InterfaceId intfId)
     164              : {
     165           17 :     IPAddressType addrType = addr.Type();
     166              : 
     167           17 :     ReturnErrorOnFailure(GetSocket(addrType));
     168              : 
     169           17 :     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           17 :         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           17 :     int flags = fcntl(mSocket, F_GETFL, 0);
     222           17 :     fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
     223              : 
     224           17 :     socklen_t sockaddrsize = 0;
     225              : 
     226              :     SockAddr sa;
     227           17 :     memset(&sa, 0, sizeof(sa));
     228              : 
     229           17 :     if (addrType == IPAddressType::kIPv6)
     230              :     {
     231            9 :         sa.in6.sin6_family   = AF_INET6;
     232            9 :         sa.in6.sin6_port     = htons(port);
     233            9 :         sa.in6.sin6_flowinfo = 0;
     234            9 :         sa.in6.sin6_addr     = addr.ToIPv6();
     235            9 :         sa.in6.sin6_scope_id = intfId.GetPlatformInterface();
     236            9 :         sockaddrsize         = sizeof(sockaddr_in6);
     237              :     }
     238              : #if INET_CONFIG_ENABLE_IPV4
     239            8 :     else if (addrType == IPAddressType::kIPv4)
     240              :     {
     241            8 :         sa.in.sin_family = AF_INET;
     242            8 :         sa.in.sin_port   = htons(port);
     243            8 :         sa.in.sin_addr   = addr.ToIPv4();
     244            8 :         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           17 :     int conRes = connect(mSocket, &sa.any, sockaddrsize);
     254              : 
     255           17 :     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           17 :     ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer())
     263              :                              .SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
     264              : 
     265           17 :     TCPEndPointHandle handle(this);
     266           17 :     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(handle, CHIP_NO_ERROR);
     274              :         }
     275              :     }
     276              :     else
     277              :     {
     278           17 :         mState = State::kConnecting;
     279              :         // Wait for ability to write on this endpoint.
     280           17 :         ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch));
     281              :     }
     282              : 
     283           17 :     return CHIP_NO_ERROR;
     284           17 : }
     285              : 
     286           29 : CHIP_ERROR TCPEndPointImplSockets::GetPeerInfo(IPAddress * retAddr, uint16_t * retPort) const
     287              : {
     288           29 :     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           30 : CHIP_ERROR TCPEndPointImplSockets::GetSocketInfo(int getname(int, sockaddr *, socklen_t *), IPAddress * retAddr,
     297              :                                                  uint16_t * retPort) const
     298              : {
     299           30 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     300              : 
     301              :     SockAddr sa;
     302           28 :     memset(&sa, 0, sizeof(sa));
     303           28 :     socklen_t saLen = sizeof(sa);
     304              : 
     305           28 :     if (getname(mSocket, &sa.any, &saLen) != 0)
     306              :     {
     307            0 :         return CHIP_ERROR_POSIX(errno);
     308              :     }
     309              : 
     310           28 :     if (sa.any.sa_family == AF_INET6)
     311              :     {
     312           16 :         *retAddr = IPAddress(sa.in6.sin6_addr);
     313           16 :         *retPort = ntohs(sa.in6.sin6_port);
     314           16 :         return CHIP_NO_ERROR;
     315              :     }
     316              : 
     317              : #if INET_CONFIG_ENABLE_IPV4
     318           12 :     if (sa.any.sa_family == AF_INET)
     319              :     {
     320           12 :         *retAddr = IPAddress(sa.in.sin_addr);
     321           12 :         *retPort = ntohs(sa.in.sin_port);
     322           12 :         return CHIP_NO_ERROR;
     323              :     }
     324              : #endif // INET_CONFIG_ENABLE_IPV4
     325              : 
     326            0 :     return CHIP_ERROR_INCORRECT_STATE;
     327              : }
     328              : 
     329           22 : CHIP_ERROR TCPEndPointImplSockets::GetInterfaceId(InterfaceId * retInterface)
     330              : {
     331           22 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     332              : 
     333              :     SockAddr sa;
     334           22 :     memset(&sa, 0, sizeof(sa));
     335           22 :     socklen_t saLen = sizeof(sa);
     336              : 
     337           22 :     if (getpeername(mSocket, &sa.any, &saLen) != 0)
     338              :     {
     339            0 :         return CHIP_ERROR_POSIX(errno);
     340              :     }
     341              : 
     342           22 :     if (sa.any.sa_family == AF_INET6)
     343              :     {
     344           12 :         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           12 :             *retInterface = InterfaceId::Null();
     352              :         }
     353           12 :         return CHIP_NO_ERROR;
     354              :     }
     355              : 
     356              : #if INET_CONFIG_ENABLE_IPV4
     357           10 :     if (sa.any.sa_family == AF_INET)
     358              :     {
     359              :         // No interface id available for IPv4 sockets.
     360           10 :         *retInterface = InterfaceId::Null();
     361           10 :         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           11 : CHIP_ERROR TCPEndPointImplSockets::SendQueuedImpl(bool queueWasEmpty)
     370              : {
     371           11 :     if (queueWasEmpty)
     372              :     {
     373              :         // Wait for ability to write on this endpoint.
     374           11 :         return static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch);
     375              :     }
     376            0 :     return CHIP_NO_ERROR;
     377              : }
     378              : 
     379           30 : CHIP_ERROR TCPEndPointImplSockets::EnableNoDelay()
     380              : {
     381           30 :     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           30 :     int val = 1;
     386           30 :     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           30 :     return CHIP_NO_ERROR;
     393              : }
     394              : 
     395           31 : CHIP_ERROR TCPEndPointImplSockets::EnableKeepAlive(uint16_t interval, uint16_t timeoutCount)
     396              : {
     397           31 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     398              : 
     399              :     // Set the idle interval
     400           30 :     int val = interval;
     401           30 :     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           30 :     val = interval;
     408           30 :     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           30 :     val = timeoutCount;
     415           30 :     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           30 :     val = 1; // enable
     422           30 :     if (setsockopt(mSocket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0)
     423              :     {
     424            0 :         return CHIP_ERROR_POSIX(errno);
     425              :     }
     426              : 
     427           30 :     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           10 : CHIP_ERROR TCPEndPointImplSockets::AckReceive(size_t len)
     445              : {
     446           10 :     VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
     447              : 
     448              :     // nothing to do for sockets case
     449            9 :     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           11 : CHIP_ERROR TCPEndPointImplSockets::DriveSendingImpl()
     468              : {
     469           11 :     CHIP_ERROR err = CHIP_NO_ERROR;
     470              : 
     471              : #ifdef MSG_NOSIGNAL
     472           11 :     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           11 :     INET_FAULT_INJECT(FaultInjection::kFault_Send, {
     479              :         err = CHIP_ERROR_POSIX(EIO);
     480              :         DoClose(err, false);
     481              :         return err;
     482              :     });
     483              : 
     484           11 :     TCPEndPointHandle handle(this);
     485           24 :     while (!mSendQueue.IsNull())
     486              :     {
     487           13 :         size_t bufLen = mSendQueue->DataLength();
     488              : 
     489           13 :         ssize_t lenSentRaw = send(mSocket, mSendQueue->Start(), bufLen, sendFlags);
     490              : 
     491           13 :         if (lenSentRaw == -1)
     492              :         {
     493            0 :             if (errno != EAGAIN && errno != EWOULDBLOCK)
     494              :             {
     495            0 :                 err = (errno == EPIPE) ? INET_ERROR_PEER_DISCONNECTED : CHIP_ERROR_POSIX(errno);
     496              :             }
     497            0 :             break;
     498              :         }
     499              : 
     500           13 :         if (lenSentRaw < 0 || bufLen < static_cast<size_t>(lenSentRaw))
     501              :         {
     502            0 :             err = CHIP_ERROR_INCORRECT_STATE;
     503            0 :             break;
     504              :         }
     505              : 
     506           13 :         size_t lenSent = static_cast<size_t>(lenSentRaw);
     507              : 
     508              :         // Mark the connection as being active.
     509           13 :         MarkActive();
     510              : 
     511           13 :         if (lenSent < bufLen)
     512              :         {
     513            0 :             mSendQueue->ConsumeHead(lenSent);
     514              :         }
     515              :         else
     516              :         {
     517           13 :             mSendQueue.FreeHead();
     518           13 :             if (mSendQueue.IsNull())
     519              :             {
     520              :                 // Do not wait for ability to write on this endpoint.
     521           11 :                 err = static_cast<System::LayerSockets &>(GetSystemLayer()).ClearCallbackOnPendingWrite(mWatch);
     522           22 :                 if (err != CHIP_NO_ERROR)
     523              :                 {
     524            0 :                     break;
     525              :                 }
     526              :             }
     527              :         }
     528              : 
     529           13 :         if (OnDataSent != nullptr)
     530              :         {
     531            0 :             OnDataSent(handle, lenSent);
     532              :         }
     533              : 
     534              : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     535           13 :         mBytesWrittenSinceLastProbe += lenSent;
     536              : 
     537           13 :         bool isProgressing = false;
     538              : 
     539           13 :         err = CheckConnectionProgress(isProgressing);
     540           26 :         if (err != CHIP_NO_ERROR)
     541              :         {
     542            0 :             break;
     543              :         }
     544              : 
     545           13 :         if (!mUserTimeoutTimerRunning)
     546              :         {
     547              :             // Timer was not running before this write. So, start
     548              :             // the timer.
     549              : 
     550            9 :             StartTCPUserTimeoutTimer();
     551              :         }
     552            4 :         else if (isProgressing)
     553              :         {
     554              :             // Progress is being made. So, shift the timer
     555              :             // forward if it was started.
     556              : 
     557            4 :             RestartTCPUserTimeoutTimer();
     558              :         }
     559              : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     560              : 
     561           13 :         if (lenSent < bufLen)
     562              :         {
     563            0 :             break;
     564              :         }
     565              :     }
     566              : 
     567           22 :     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           11 :         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           11 :     return err;
     580           11 : }
     581              : 
     582           17 : void TCPEndPointImplSockets::HandleConnectCompleteImpl()
     583              : {
     584              :     // Wait for ability to read or write on this endpoint.
     585           17 :     CHIP_ERROR err = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch);
     586           34 :     if (err == CHIP_NO_ERROR)
     587              :     {
     588           17 :         err = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch);
     589              :     }
     590           34 :     if (err != CHIP_NO_ERROR)
     591              :     {
     592            0 :         DoClose(err, false);
     593            0 :         return;
     594              :     }
     595              : }
     596              : 
     597           60 : void TCPEndPointImplSockets::DoCloseImpl(CHIP_ERROR err, State oldState)
     598              : {
     599              :     struct linger lingerStruct;
     600              : 
     601              :     // If the socket hasn't been closed already...
     602           60 :     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           55 :         if (mState == State::kClosed || (mState == State::kClosing && mSendQueue.IsNull()))
     608              :         {
     609              :             // If aborting the connection, ensure we send a TCP RST.
     610           87 :             if (IsConnected(oldState) && err != CHIP_NO_ERROR)
     611              :             {
     612           26 :                 lingerStruct.l_onoff  = 1;
     613           26 :                 lingerStruct.l_linger = 0;
     614              : 
     615           26 :                 if (setsockopt(mSocket, SOL_SOCKET, SO_LINGER, &lingerStruct, sizeof(lingerStruct)) != 0)
     616              :                 {
     617            0 :                     ChipLogError(Inet, "SO_LINGER: %d", errno);
     618              :                 }
     619              :             }
     620              : 
     621           55 :             TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets &>(GetSystemLayer()).StopWatchingSocket(&mWatch);
     622           55 :             close(mSocket);
     623           55 :             mSocket = kInvalidSocketFd;
     624              :         }
     625              :     }
     626           60 : }
     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           41 : CHIP_ERROR TCPEndPointImplSockets::GetSocket(IPAddressType addrType)
     716              : {
     717           41 :     if (mSocket == kInvalidSocketFd)
     718              :     {
     719              :         int family;
     720           41 :         if (addrType == IPAddressType::kIPv6)
     721              :         {
     722           22 :             family = PF_INET6;
     723              : #if INET_CONFIG_ENABLE_IPV4
     724              :         }
     725           19 :         else if (addrType == IPAddressType::kIPv4)
     726              :         {
     727           18 :             family = PF_INET;
     728              : #endif // INET_CONFIG_ENABLE_IPV4
     729              :         }
     730              :         else
     731              :         {
     732            1 :             return INET_ERROR_WRONG_ADDRESS_TYPE;
     733              :         }
     734           40 :         mSocket = ::socket(family, SOCK_STREAM | SOCK_CLOEXEC, 0);
     735           40 :         if (mSocket == -1)
     736              :         {
     737            0 :             return CHIP_ERROR_POSIX(errno);
     738              :         }
     739            0 :         auto connectionCleanup = ScopeExit([&]() {
     740            0 :             close(mSocket);
     741            0 :             mSocket = kInvalidSocketFd;
     742           40 :         });
     743           40 :         ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).StartWatchingSocket(mSocket, &mWatch));
     744              :         auto watchCleanup = ScopeExit(
     745           40 :             [&]() { TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets &>(GetSystemLayer()).StopWatchingSocket(&mWatch); });
     746           40 :         mAddrType = addrType;
     747              : 
     748              :         // If creating an IPv6 socket, tell the kernel that it will be IPv6 only.  This makes it
     749              :         // posible to bind two sockets to the same port, one for IPv4 and one for IPv6.
     750              : #ifdef IPV6_V6ONLY
     751           40 :         if (family == PF_INET6)
     752              :         {
     753           22 :             int one = 1;
     754           22 :             setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
     755              :         }
     756              : #endif // defined(IPV6_V6ONLY)
     757              : 
     758              :         // On systems that support it, disable the delivery of SIGPIPE signals when writing to a closed
     759              :         // socket.
     760              : #ifdef SO_NOSIGPIPE
     761              :         {
     762              :             int one = 1;
     763              :             int res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
     764              :             if (res != 0)
     765              :             {
     766              :                 ChipLogError(Inet, "SO_NOSIGPIPE: %d", errno);
     767              :             }
     768              :         }
     769              : #endif // defined(SO_NOSIGPIPE)
     770           40 :         watchCleanup.release();
     771           40 :         connectionCleanup.release();
     772           40 :     }
     773            0 :     else if (mAddrType != addrType)
     774              :     {
     775            0 :         return CHIP_ERROR_INCORRECT_STATE;
     776              :     }
     777              : 
     778           40 :     return CHIP_NO_ERROR;
     779              : }
     780              : 
     781              : // static
     782           52 : void TCPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
     783              : {
     784           52 :     reinterpret_cast<TCPEndPointImplSockets *>(data)->HandlePendingIO(events);
     785           52 : }
     786              : 
     787           52 : void TCPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
     788              : {
     789              :     // Prevent the end point from being freed while in the middle of a callback.
     790           52 :     TCPEndPointHandle handle(this);
     791              : 
     792              :     // If in the Listening state, and the app is ready to receive a connection, and there is a connection
     793              :     // ready to be received on the socket, process the incoming connection.
     794           52 :     if (mState == State::kListening)
     795              :     {
     796           17 :         if (OnConnectionReceived != nullptr && events.Has(System::SocketEventFlags::kRead))
     797              :         {
     798           17 :             CHIP_ERROR error = HandleIncomingConnection();
     799           34 :             if (error != CHIP_NO_ERROR && OnAcceptError != nullptr)
     800              :             {
     801            2 :                 OnAcceptError(handle, error);
     802              :             }
     803              :         }
     804              :     }
     805              : 
     806              :     // If in the processes of initiating a connection...
     807           35 :     else if (mState == State::kConnecting)
     808              :     {
     809              :         // The socket being writable indicates the connection has completed (successfully or otherwise).
     810           17 :         if (events.Has(System::SocketEventFlags::kWrite))
     811              :         {
     812              : #ifndef __MBED__
     813              :             // Get the connection result from the socket.
     814              :             int osConRes;
     815           17 :             socklen_t optLen = sizeof(osConRes);
     816           17 :             if (getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &osConRes, &optLen) != 0)
     817              :             {
     818            0 :                 osConRes = errno;
     819              :             }
     820              : #else  // __MBED__
     821              :        // On Mbed OS, connect blocks and never returns EINPROGRESS
     822              :        // The socket option SO_ERROR is not available.
     823              :             int osConRes = 0;
     824              : #endif // !__MBED__
     825           17 :             CHIP_ERROR conRes = CHIP_ERROR_POSIX(osConRes);
     826              : 
     827              :             // Process the connection result.
     828           17 :             HandleConnectComplete(conRes);
     829              :         }
     830              :     }
     831              : 
     832              :     else
     833              :     {
     834              :         // If in a state where sending is allowed, and there is data to be sent, and the socket is ready for
     835              :         // writing, drive outbound data into the connection.
     836           18 :         if (IsConnected() && !mSendQueue.IsNull() && events.Has(System::SocketEventFlags::kWrite))
     837              :         {
     838            0 :             TEMPORARY_RETURN_IGNORED DriveSending();
     839              :         }
     840              : 
     841              :         // If in a state were receiving is allowed, and the app is ready to receive data, and data is ready
     842              :         // on the socket, receive inbound data from the connection.
     843           36 :         if ((mState == State::kConnected || mState == State::kSendShutdown) && mReceiveEnabled && OnDataReceived != nullptr &&
     844           18 :             events.Has(System::SocketEventFlags::kRead))
     845              :         {
     846           16 :             ReceiveData();
     847              :         }
     848              :     }
     849           52 : }
     850              : 
     851           16 : void TCPEndPointImplSockets::ReceiveData()
     852              : {
     853           16 :     System::PacketBufferHandle rcvBuf;
     854           16 :     bool isNewBuf = true;
     855              : 
     856           16 :     if (mRcvQueue.IsNull())
     857              :     {
     858           16 :         rcvBuf = System::PacketBufferHandle::New(kMaxReceiveMessageSize, 0);
     859              :     }
     860              :     else
     861              :     {
     862            0 :         rcvBuf = mRcvQueue->Last();
     863            0 :         if (rcvBuf->AvailableDataLength() == 0)
     864              :         {
     865            0 :             rcvBuf = System::PacketBufferHandle::New(kMaxReceiveMessageSize, 0);
     866              :         }
     867              :         else
     868              :         {
     869            0 :             isNewBuf = false;
     870            0 :             rcvBuf->CompactHead();
     871              :         }
     872              :     }
     873              : 
     874           16 :     if (rcvBuf.IsNull())
     875              :     {
     876            0 :         DoClose(CHIP_ERROR_NO_MEMORY, false);
     877            0 :         return;
     878              :     }
     879              : 
     880              :     // Attempt to receive data from the socket.
     881           16 :     ssize_t rcvLen = recv(mSocket, rcvBuf->Start() + rcvBuf->DataLength(), rcvBuf->AvailableDataLength(), 0);
     882              : 
     883              : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     884              :     CHIP_ERROR err;
     885           16 :     bool isProgressing = false;
     886              : 
     887           16 :     err = CheckConnectionProgress(isProgressing);
     888           32 :     if (err != CHIP_NO_ERROR)
     889              :     {
     890            0 :         DoClose(err, false);
     891              : 
     892            0 :         return;
     893              :     }
     894              : 
     895           16 :     if (mLastTCPKernelSendQueueLen == 0)
     896              :     {
     897              :         // If the output queue has been flushed then stop the timer.
     898              : 
     899           16 :         StopTCPUserTimeoutTimer();
     900              :     }
     901            0 :     else if (isProgressing && mUserTimeoutTimerRunning)
     902              :     {
     903              :         // Progress is being made. So, shift the timer
     904              :         // forward if it was started.
     905            0 :         RestartTCPUserTimeoutTimer();
     906              :     }
     907              : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
     908           16 :     TCPEndPointHandle handle(this);
     909              :     // If an error occurred, abort the connection.
     910           16 :     if (rcvLen < 0)
     911              :     {
     912            5 :         int systemErrno = errno;
     913            5 :         if (systemErrno == EAGAIN)
     914              :         {
     915              :             // Note: in this case, we opt to not retry the recv call,
     916              :             // and instead we expect that the read flags will get
     917              :             // reset correctly upon a subsequent return from the
     918              :             // select call.
     919            0 :             ChipLogError(Inet, "recv: EAGAIN, will retry");
     920              : 
     921            0 :             return;
     922              :         }
     923              : 
     924            5 :         DoClose(CHIP_ERROR_POSIX(systemErrno), false);
     925              :     }
     926              :     else
     927              :     {
     928              :         // Mark the connection as being active.
     929           11 :         MarkActive();
     930              : 
     931              :         // If the peer closed their end of the connection...
     932           11 :         if (rcvLen == 0)
     933              :         {
     934              :             // If in the Connected state and the app has provided an OnPeerClose callback,
     935              :             // enter the ReceiveShutdown state.  Providing an OnPeerClose callback allows
     936              :             // the app to decide whether to keep the send side of the connection open after
     937              :             // the peer has closed. If no OnPeerClose is provided, we assume that the app
     938              :             // wants to close both directions and automatically enter the Closing state.
     939            2 :             if (mState == State::kConnected && OnPeerClose != nullptr)
     940              :             {
     941            0 :                 mState = State::kReceiveShutdown;
     942              :             }
     943              :             else
     944              :             {
     945            2 :                 mState = State::kClosing;
     946              :             }
     947              :             // Do not wait for ability to read on this endpoint.
     948            2 :             (void) static_cast<System::LayerSockets &>(GetSystemLayer()).ClearCallbackOnPendingRead(mWatch);
     949              :             // Call the app's OnPeerClose.
     950            2 :             if (OnPeerClose != nullptr)
     951              :             {
     952            0 :                 OnPeerClose(handle);
     953              :             }
     954              :         }
     955              : 
     956              :         // Otherwise, add the new data onto the receive queue.
     957              :         else
     958              :         {
     959            9 :             VerifyOrDie(rcvLen > 0);
     960            9 :             size_t newDataLength = rcvBuf->DataLength() + static_cast<size_t>(rcvLen);
     961            9 :             if (isNewBuf)
     962              :             {
     963            9 :                 rcvBuf->SetDataLength(newDataLength);
     964            9 :                 rcvBuf.RightSize();
     965            9 :                 if (mRcvQueue.IsNull())
     966              :                 {
     967            9 :                     mRcvQueue = std::move(rcvBuf);
     968              :                 }
     969              :                 else
     970              :                 {
     971            0 :                     mRcvQueue->AddToEnd(std::move(rcvBuf));
     972              :                 }
     973              :             }
     974              :             else
     975              :             {
     976            0 :                 rcvBuf->SetDataLength(newDataLength, mRcvQueue);
     977              :             }
     978              :         }
     979              :     }
     980              : 
     981              :     // Drive any received data into the app.
     982           16 :     DriveReceiving(handle);
     983           16 : }
     984              : 
     985           17 : CHIP_ERROR TCPEndPointImplSockets::HandleIncomingConnection()
     986              : {
     987              :     IPAddress peerAddr;
     988              :     uint16_t peerPort;
     989              : 
     990              :     SockAddr sa;
     991           17 :     memset(&sa, 0, sizeof(sa));
     992           17 :     socklen_t saLen = sizeof(sa);
     993              : 
     994              :     // Accept the new connection.
     995           17 :     int conSocket       = accept(mSocket, &sa.any, &saLen);
     996            2 :     auto failureCleanup = ScopeExit([&] {
     997            2 :         if (conSocket != -1)
     998              :         {
     999            2 :             close(conSocket);
    1000              :         }
    1001           17 :     });
    1002              : 
    1003           17 :     if (conSocket == -1)
    1004              :     {
    1005            0 :         if (errno == EAGAIN || errno == EWOULDBLOCK)
    1006              :         {
    1007            0 :             return CHIP_NO_ERROR;
    1008              :         }
    1009              : 
    1010            0 :         return CHIP_ERROR_POSIX(errno);
    1011              :     }
    1012              : 
    1013              : #ifdef __APPLE__
    1014              :     // On Darwin, if the client closes the connection just as it is being accepted, it is
    1015              :     // possible for accept() to return a socket but saLen is 0. Ignore the connection.
    1016              :     VerifyOrReturnError(saLen != 0, CHIP_NO_ERROR);
    1017              : #endif
    1018              : 
    1019              :     // If there's no callback available, fail with an error.
    1020           17 :     VerifyOrReturnError(OnConnectionReceived != nullptr, CHIP_ERROR_NO_CONNECTION_HANDLER);
    1021              : 
    1022              :     // Extract the peer's address information.
    1023           17 :     if (sa.any.sa_family == AF_INET6)
    1024              :     {
    1025            9 :         peerAddr = IPAddress(sa.in6.sin6_addr);
    1026            9 :         peerPort = ntohs(sa.in6.sin6_port);
    1027              :     }
    1028              : #if INET_CONFIG_ENABLE_IPV4
    1029            8 :     else if (sa.any.sa_family == AF_INET)
    1030              :     {
    1031            8 :         peerAddr = IPAddress(sa.in.sin_addr);
    1032            8 :         peerPort = ntohs(sa.in.sin_port);
    1033              :     }
    1034              : #endif // INET_CONFIG_ENABLE_IPV4
    1035              :     else
    1036              :     {
    1037            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1038              :     }
    1039              : 
    1040              : #if INET_CONFIG_TEST
    1041           17 :     if (TCPEndPoint::sForceEarlyFailureIncomingConnection)
    1042              :     {
    1043            2 :         return CHIP_ERROR_INCORRECT_STATE;
    1044              :     }
    1045              : #endif
    1046              : 
    1047              :     // Attempt to allocate an end point object.
    1048           15 :     TCPEndPointHandle connectEndPoint;
    1049           15 :     ReturnErrorOnFailure(GetEndPointManager().NewEndPoint(connectEndPoint));
    1050           15 :     auto & conEP = static_cast<TCPEndPointImplSockets &>(*connectEndPoint);
    1051              : 
    1052              :     // If all went well...
    1053              :     // Put the new end point into the Connected state.
    1054           15 :     ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).StartWatchingSocket(conSocket, &conEP.mWatch));
    1055              : 
    1056           15 :     failureCleanup.release(); // Transfer ownership of socket to conEp
    1057           15 :     conEP.mSocket = conSocket;
    1058           15 :     conEP.mState  = State::kConnected;
    1059              : #if INET_CONFIG_ENABLE_IPV4
    1060           15 :     conEP.mAddrType = (sa.any.sa_family == AF_INET6) ? IPAddressType::kIPv6 : IPAddressType::kIPv4;
    1061              : #else  // !INET_CONFIG_ENABLE_IPV4
    1062              :     conEP.mAddrType = IPAddressType::kIPv6;
    1063              : #endif // !INET_CONFIG_ENABLE_IPV4
    1064              : 
    1065              :     // Wait for ability to read on this endpoint.
    1066           15 :     auto & conEPLayer = static_cast<System::LayerSockets &>(conEP.GetSystemLayer());
    1067           15 :     ReturnErrorOnFailure(conEPLayer.SetCallback(conEP.mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(&conEP)));
    1068              : 
    1069           15 :     ReturnErrorOnFailure(conEPLayer.RequestCallbackOnPendingRead(conEP.mWatch));
    1070              : 
    1071              :     // Call the app's callback function.
    1072           15 :     TCPEndPointHandle handle(this);
    1073           15 :     OnConnectionReceived(handle, connectEndPoint, peerAddr, peerPort);
    1074              : 
    1075           15 :     return CHIP_NO_ERROR;
    1076           17 : }
    1077              : 
    1078              : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
    1079              : /**
    1080              :  *  This function probes the TCP output queue and checks if data is successfully
    1081              :  *  being transferred to the other end.
    1082              :  */
    1083           29 : CHIP_ERROR TCPEndPointImplSockets::CheckConnectionProgress(bool & isProgressing)
    1084              : {
    1085           29 :     int currPendingBytesRaw = 0;
    1086              :     uint32_t currPendingBytes; // Will be initialized once we know it's safe.
    1087              : 
    1088              :     // Fetch the bytes pending successful transmission in the TCP out queue.
    1089              : 
    1090              : #ifdef __APPLE__
    1091              :     socklen_t len = sizeof(currPendingBytesRaw);
    1092              :     if (getsockopt(mSocket, SOL_SOCKET, SO_NWRITE, &currPendingBytesRaw, &len) < 0)
    1093              : #else
    1094           29 :     if (ioctl(mSocket, TIOCOUTQ, &currPendingBytesRaw) < 0)
    1095              : #endif
    1096              :     {
    1097            0 :         return CHIP_ERROR_POSIX(errno);
    1098              :     }
    1099              : 
    1100           29 :     if (!CanCastTo<uint32_t>(currPendingBytesRaw))
    1101              :     {
    1102            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1103              :     }
    1104              : 
    1105           29 :     currPendingBytes = static_cast<uint32_t>(currPendingBytesRaw);
    1106              : 
    1107           29 :     if ((currPendingBytes != 0) && (mBytesWrittenSinceLastProbe + mLastTCPKernelSendQueueLen == currPendingBytes))
    1108              :     {
    1109              :         // No progress has been made
    1110              : 
    1111            0 :         isProgressing = false;
    1112              :     }
    1113              :     else
    1114              :     {
    1115              :         // Data is flowing successfully
    1116              : 
    1117           29 :         isProgressing = true;
    1118              :     }
    1119              : 
    1120              :     // Reset the value of the bytes written since the last probe into the tcp
    1121              :     // outqueue was made and update the last tcp outqueue sample.
    1122              : 
    1123           29 :     mBytesWrittenSinceLastProbe = 0;
    1124              : 
    1125           29 :     mLastTCPKernelSendQueueLen = currPendingBytes;
    1126              : 
    1127           29 :     return CHIP_NO_ERROR;
    1128              : }
    1129              : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
    1130              : 
    1131              : } // namespace Inet
    1132              : } // namespace chip
        

Generated by: LCOV version 2.0-1