Matter SDK Coverage Report
Current view: top level - inet - TCPEndPointImplSockets.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 67.4 % 393 265
Test Date: 2025-01-17 19:00:11 Functions: 87.5 % 24 21

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