Matter SDK Coverage Report
Current view: top level - transport/raw - Tuple.h (source / functions) Coverage Total Hit
Test: SHA:db08debc068562b264a2df3a7f3a8cc1d0b3aba1 Lines: 47.1 % 51 24
Test Date: 2025-10-02 07:10:30 Functions: 26.4 % 125 33

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : /**
      19              :  * @file
      20              :  *
      21              :  * Defines a compound transport type (tuple) that can merge several transports
      22              :  * to look like a single one.
      23              :  */
      24              : #pragma once
      25              : 
      26              : #include <tuple>
      27              : #include <type_traits>
      28              : 
      29              : #include <transport/raw/Base.h>
      30              : 
      31              : namespace chip {
      32              : namespace Transport {
      33              : 
      34              : /**
      35              :  * Groups together several transports of different types and presents them as a unified transport.
      36              :  *
      37              :  * The usage intent is to be able to group several distinct transport types and make them look
      38              :  * as a single transport.
      39              :  *
      40              :  * Having an example class definition of `Tuple<UDP, UDP, TCP>`
      41              :  *
      42              :  * Is equivalent to:
      43              :  *
      44              :  * ~~~~~~~~~
      45              :  *    class TupleOfUdpUdpTcp : public BASE {
      46              :  *       private:
      47              :  *          UDP mUdp1;
      48              :  *          UDP mUdp2;
      49              :  *          TCP mTcp3;
      50              :  *       public:
      51              :  *          Init(UDPListenParameters &, UDPListenParameters&, TCPListenParameters) {...}
      52              :  *          CHIP_ERROR SendMessage(...) override;
      53              :  *          bool CanSendToPeer(...) override;
      54              :  *    }
      55              :  * ~~~~~~~~~
      56              :  *
      57              :  * The intent of this is to allow applications to use any transport types without CHIP pre-defining
      58              :  * popular mappings (like UDP only, UDP and BLE, BLE only etc.) and without using \#ifdefs to create
      59              :  * a single 'standard transport'.
      60              :  *
      61              :  * Transport logic:
      62              :  *   - Every transport can decide if a 'PeerAddress' can be sent over 'self'
      63              :  *
      64              :  *   - Within a mixed tuple, if several transports support a peer address (e.g. TCP and UDP both
      65              :  *     support IP), the first one found wins.
      66              :  *
      67              :  *   - Expected message sending logic:
      68              :  *     - BLE transports only support BLE. TCP/UDP support IP addresses
      69              :  *     - Multicasts only supported by UDP
      70              :  *
      71              :  * @tparam TransportTypes the ORDERED list of transport types grouped together. Order matters in
      72              :  *         determining what transport is used when multiple transports can reach a Peer.
      73              :  *
      74              :  * Transports (TransportTypes) are assumed to have an Init call with EXACTLY one argument and returning
      75              :  * a CHIP_ERROR, with a signature like:
      76              :  *
      77              :  *    CHIP_ERROR Init(AnyType);
      78              :  *
      79              :  */
      80              : template <typename... TransportTypes>
      81              : class Tuple : public Base
      82              : {
      83              : public:
      84        15114 :     CHIP_ERROR SendMessage(const PeerAddress & address, System::PacketBufferHandle && msgBuf) override
      85              :     {
      86        15114 :         return SendMessageImpl<0>(address, std::move(msgBuf));
      87              :     }
      88              : 
      89            0 :     CHIP_ERROR MulticastGroupJoinLeave(const PeerAddress & address, bool join) override
      90              :     {
      91            0 :         return MulticastGroupJoinLeaveImpl<0>(address, join);
      92              :     }
      93              : 
      94            0 :     bool CanSendToPeer(const PeerAddress & address) override { return CanSendToPeerImpl<0>(address); }
      95              : 
      96              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
      97            0 :     CHIP_ERROR TCPConnect(const PeerAddress & address, AppTCPConnectionCallbackCtxt * appState,
      98              :                           ActiveTCPConnectionHolder & peerConnState) override
      99              :     {
     100            0 :         return TCPConnectImpl<0>(address, appState, peerConnState);
     101              :     }
     102              : 
     103              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     104              : 
     105           50 :     void Close() override { return CloseImpl<0>(); }
     106              : 
     107              :     /**
     108              :      * Initialization method that forwards arguments for initialization to each of the underlying
     109              :      * transports.
     110              :      *
     111              :      * Transports are assumed to have an Init call with EXACTLY one argument. This method MUST initialize
     112              :      * all underlying transports.
     113              :      *
     114              :      * @param delegate the delegate to handle messages.
     115              :      * @param args     initialization arguments, forwarded as-is to the underlying transports.
     116              :      */
     117              :     template <typename... Args, typename std::enable_if<(sizeof...(Args) == sizeof...(TransportTypes))>::type * = nullptr>
     118           50 :     CHIP_ERROR Init(RawTransportDelegate * delegate, Args &&... args)
     119              :     {
     120           50 :         return InitImpl(delegate, std::forward<Args>(args)...);
     121              :     }
     122              : 
     123              : private:
     124              :     /**
     125              :      * Recursive cansend implementation iterating through transport members.
     126              :      *
     127              :      * Will return true if any transport with index N and up can CanSendToPeer(address);
     128              :      *
     129              :      * @tparam N the index of the underlying transport to check for CanSendToPeer
     130              :      *
     131              :      * @param address what address to check.
     132              :      */
     133              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     134            0 :     bool CanSendToPeerImpl(const PeerAddress & address)
     135              :     {
     136            0 :         return std::get<N>(mTransports).CanSendToPeer(address) || CanSendToPeerImpl<N + 1>(address);
     137              :     }
     138              : 
     139              :     /**
     140              :      * CanSend template for out of range N. Always returns false.
     141              :      */
     142              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     143            0 :     bool CanSendToPeerImpl(const PeerAddress & address)
     144              :     {
     145            0 :         return false;
     146              :     }
     147              : 
     148              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     149              :     /**
     150              :      * Recursive TCPConnect implementation iterating through transport members.
     151              :      *
     152              :      * @tparam N the index of the underlying transport to send disconnect to
     153              :      *
     154              :      * @param address what address to connect to.
     155              :      */
     156              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     157            0 :     CHIP_ERROR TCPConnectImpl(const PeerAddress & address, AppTCPConnectionCallbackCtxt * appState,
     158              :                               ActiveTCPConnectionHolder & peerConnState)
     159              :     {
     160            0 :         Base * base = &std::get<N>(mTransports);
     161            0 :         if (base->CanSendToPeer(address))
     162              :         {
     163            0 :             return base->TCPConnect(address, appState, peerConnState);
     164              :         }
     165            0 :         return TCPConnectImpl<N + 1>(address, appState, peerConnState);
     166              :     }
     167              : 
     168              :     /**
     169              :      * TCPConnectImpl template for out of range N.
     170              :      */
     171              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     172            0 :     CHIP_ERROR TCPConnectImpl(const PeerAddress & address, AppTCPConnectionCallbackCtxt * appState,
     173              :                               ActiveTCPConnectionHolder & peerConnState)
     174              :     {
     175            0 :         return CHIP_ERROR_NO_MESSAGE_HANDLER;
     176              :     }
     177              : 
     178              :     /**
     179              :      * Recursive disconnect implementation iterating through transport members.
     180              :      *
     181              :      * @tparam N the index of the underlying transport to send disconnect to
     182              :      *
     183              :      * @param address what address to disconnect from.
     184              :      */
     185              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     186              :     void TCPDisconnectImpl(const PeerAddress & address)
     187              :     {
     188              :         std::get<N>(mTransports).TCPDisconnect(address);
     189              :         TCPDisconnectImpl<N + 1>(address);
     190              :     }
     191              : 
     192              :     /**
     193              :      * TCPDisconnectImpl template for out of range N.
     194              :      */
     195              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     196              :     void TCPDisconnectImpl(const PeerAddress & address)
     197              :     {}
     198              : 
     199              :     /**
     200              :      * Recursive disconnect implementation iterating through transport members.
     201              :      *
     202              :      * @tparam N the index of the underlying transport to send disconnect to
     203              :      *
     204              :      * @param conn pointer to the connection to the peer.
     205              :      */
     206              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     207              :     void TCPDisconnectImpl(ActiveTCPConnectionHolder & conn, bool shouldAbort = 0)
     208              :     {
     209              :         std::get<N>(mTransports).TCPDisconnect(conn, shouldAbort);
     210              :         TCPDisconnectImpl<N + 1>(conn, shouldAbort);
     211              :     }
     212              : 
     213              :     /**
     214              :      * TCPDisconnectImpl template for out of range N.
     215              :      */
     216              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     217              :     void TCPDisconnectImpl(ActiveTCPConnectionHolder & conn, bool shouldAbort = 0)
     218              :     {}
     219              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     220              : 
     221              :     /**
     222              :      * Recursive disconnect implementation iterating through transport members.
     223              :      *
     224              :      * @tparam N the index of the underlying transport to send close to
     225              :      */
     226              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     227           54 :     void CloseImpl()
     228              :     {
     229           54 :         std::get<N>(mTransports).Close();
     230           54 :         CloseImpl<N + 1>();
     231           54 :     }
     232              : 
     233              :     /**
     234              :      * CloseImpl template for out of range N.
     235              :      */
     236              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     237           50 :     void CloseImpl()
     238           50 :     {}
     239              : 
     240              :     /**
     241              :      * Recursive sendmessage implementation iterating through transport members.
     242              :      *
     243              :      * Message is sent through the first transport from index N or above, which returns 'CanSendToPeer'
     244              :      *
     245              :      * @tparam N the index of the underlying transport to run SendMessage throug.
     246              :      *
     247              :      * @param address where to send the message
     248              :      * @param msgBuf the message to send.  Includes all CHIP message fields except optional length.
     249              :      */
     250              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     251        15114 :     CHIP_ERROR SendMessageImpl(const PeerAddress & address, System::PacketBufferHandle && msgBuf)
     252              :     {
     253        15114 :         Base * base = &std::get<N>(mTransports);
     254        15114 :         if (base->CanSendToPeer(address))
     255              :         {
     256        15114 :             return base->SendMessage(address, std::move(msgBuf));
     257              :         }
     258            0 :         return SendMessageImpl<N + 1>(address, std::move(msgBuf));
     259              :     }
     260              : 
     261              :     /**
     262              :      * SendMessageImpl when N is out of range. Always returns an error code.
     263              :      */
     264              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     265            0 :     CHIP_ERROR SendMessageImpl(const PeerAddress & address, System::PacketBufferHandle msgBuf)
     266              :     {
     267            0 :         return CHIP_ERROR_NO_MESSAGE_HANDLER;
     268              :     }
     269              : 
     270              :     /**
     271              :      * Recursive GroupJoinLeave implementation iterating through transport members.
     272              :      *
     273              :      * Listener is activated through the first transport from index N or above, which returns 'CanListenMulticast'
     274              :      *
     275              :      * @tparam N the index of the underlying transport to run GroupJoinLeave through.
     276              :      *
     277              :      * @param address where to send the message
     278              :      * @param join a boolean indicating if the transport should join or leave the group
     279              :      */
     280              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     281            0 :     CHIP_ERROR MulticastGroupJoinLeaveImpl(const PeerAddress & address, bool join)
     282              :     {
     283            0 :         Base * base = &std::get<N>(mTransports);
     284            0 :         if (base->CanListenMulticast())
     285              :         {
     286            0 :             return base->MulticastGroupJoinLeave(address, join);
     287              :         }
     288            0 :         return MulticastGroupJoinLeaveImpl<N + 1>(address, join);
     289              :     }
     290              : 
     291              :     /**
     292              :      * GroupJoinLeave when N is out of range. Always returns an error code.
     293              :      */
     294              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     295            0 :     CHIP_ERROR MulticastGroupJoinLeaveImpl(const PeerAddress & address, bool join)
     296              :     {
     297            0 :         return CHIP_ERROR_NO_MESSAGE_HANDLER;
     298              :     }
     299              : 
     300              :     /**
     301              :      * Recursive init implementation iterating through transport members
     302              :      *
     303              :      * Given a set of arguments 'a1, a2, a3, ... aN' will call an Init method on the last N
     304              :      * transports.
     305              :      *
     306              :      * Method is expected to be called initially with exactly sizeof(TransportTypes) to initialize
     307              :      * all transports.
     308              :      *
     309              :      * @param arg the next initialize argument to pass to the transport Init method
     310              :      * @param rest tail arguments to be passed to the rest of transport Init methods.
     311              :      */
     312              :     template <typename InitArg, typename... Rest>
     313           54 :     CHIP_ERROR InitImpl(RawTransportDelegate * delegate, InitArg && arg, Rest &&... rest)
     314              :     {
     315           54 :         auto transport = &std::get<sizeof...(TransportTypes) - sizeof...(Rest) - 1>(mTransports);
     316              : 
     317           54 :         CHIP_ERROR err = transport->Init(std::forward<InitArg>(arg));
     318           54 :         if (err != CHIP_NO_ERROR)
     319              :         {
     320            0 :             return err;
     321              :         }
     322              : 
     323           54 :         transport->SetDelegate(delegate);
     324              : 
     325           54 :         return InitImpl(delegate, std::forward<Rest>(rest)...);
     326              :     }
     327              : 
     328              :     /**
     329              :      * Base case where initialization finishes.
     330              :      *
     331              :      * Provided to ensure that recursive InitImpl finishes compiling.
     332              :      */
     333           50 :     CHIP_ERROR InitImpl(RawTransportDelegate * delegate) { return CHIP_NO_ERROR; }
     334              : 
     335              :     std::tuple<TransportTypes...> mTransports;
     336              : 
     337              : public:
     338              :     template <size_t i>
     339         2556 :     auto GetImplAtIndex() -> decltype(std::get<i>(mTransports)) &
     340              :     {
     341         2556 :         return std::get<i>(mTransports);
     342              :     }
     343              : 
     344              :     std::tuple<TransportTypes...> & GetTransports() { return mTransports; }
     345              : };
     346              : 
     347              : } // namespace Transport
     348              : } // namespace chip
        

Generated by: LCOV version 2.0-1