Matter SDK Coverage Report
Current view: top level - transport/raw - Tuple.h (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 27.3 % 66 18
Test Date: 2025-02-22 08:08:07 Functions: 26.5 % 49 13

            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            0 :     CHIP_ERROR SendMessage(const PeerAddress & address, System::PacketBufferHandle && msgBuf) override
      85              :     {
      86            0 :         return SendMessageImpl<0>(address, std::move(msgBuf));
      87              :     }
      88              : 
      89            0 :     CHIP_ERROR MulticastGroupJoinLeave(const Transport::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, Transport::AppTCPConnectionCallbackCtxt * appState,
      98              :                           Transport::ActiveTCPConnectionState ** peerConnState) override
      99              :     {
     100            0 :         return TCPConnectImpl<0>(address, appState, peerConnState);
     101              :     }
     102              : 
     103            0 :     void TCPDisconnect(const PeerAddress & address) override { return TCPDisconnectImpl<0>(address); }
     104              : 
     105            0 :     void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0) override
     106              :     {
     107            0 :         return TCPDisconnectImpl<0>(conn, shouldAbort);
     108              :     }
     109              : 
     110              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     111              : 
     112            1 :     void Close() override { return CloseImpl<0>(); }
     113              : 
     114              :     /**
     115              :      * Initialization method that forwards arguments for initialization to each of the underlying
     116              :      * transports.
     117              :      *
     118              :      * Transports are assumed to have an Init call with EXACTLY one argument. This method MUST initialize
     119              :      * all underlying transports.
     120              :      *
     121              :      * @param delegate the delegate to handle messages.
     122              :      * @param args     initialization arguments, forwarded as-is to the underlying transports.
     123              :      */
     124              :     template <typename... Args, typename std::enable_if<(sizeof...(Args) == sizeof...(TransportTypes))>::type * = nullptr>
     125            1 :     CHIP_ERROR Init(RawTransportDelegate * delegate, Args &&... args)
     126              :     {
     127            1 :         return InitImpl(delegate, std::forward<Args>(args)...);
     128              :     }
     129              : 
     130              : private:
     131              :     /**
     132              :      * Recursive cansend implementation iterating through transport members.
     133              :      *
     134              :      * Will return true if any transport with index N and up can CanSendToPeer(address);
     135              :      *
     136              :      * @tparam N the index of the underlying transport to check for CanSendToPeer
     137              :      *
     138              :      * @param address what address to check.
     139              :      */
     140              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     141            0 :     bool CanSendToPeerImpl(const PeerAddress & address)
     142              :     {
     143            0 :         return std::get<N>(mTransports).CanSendToPeer(address) || CanSendToPeerImpl<N + 1>(address);
     144              :     }
     145              : 
     146              :     /**
     147              :      * CanSend template for out of range N. Always returns false.
     148              :      */
     149              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     150            0 :     bool CanSendToPeerImpl(const PeerAddress & address)
     151              :     {
     152            0 :         return false;
     153              :     }
     154              : 
     155              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     156              :     /**
     157              :      * Recursive TCPConnect implementation iterating through transport members.
     158              :      *
     159              :      * @tparam N the index of the underlying transport to send disconnect to
     160              :      *
     161              :      * @param address what address to connect to.
     162              :      */
     163              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     164            0 :     CHIP_ERROR TCPConnectImpl(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState,
     165              :                               Transport::ActiveTCPConnectionState ** peerConnState)
     166              :     {
     167            0 :         Base * base = &std::get<N>(mTransports);
     168            0 :         if (base->CanSendToPeer(address))
     169              :         {
     170            0 :             return base->TCPConnect(address, appState, peerConnState);
     171              :         }
     172            0 :         return TCPConnectImpl<N + 1>(address, appState, peerConnState);
     173              :     }
     174              : 
     175              :     /**
     176              :      * TCPConnectImpl template for out of range N.
     177              :      */
     178              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     179            0 :     CHIP_ERROR TCPConnectImpl(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState,
     180              :                               Transport::ActiveTCPConnectionState ** peerConnState)
     181              :     {
     182            0 :         return CHIP_ERROR_NO_MESSAGE_HANDLER;
     183              :     }
     184              : 
     185              :     /**
     186              :      * Recursive disconnect implementation iterating through transport members.
     187              :      *
     188              :      * @tparam N the index of the underlying transport to send disconnect to
     189              :      *
     190              :      * @param address what address to disconnect from.
     191              :      */
     192              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     193            0 :     void TCPDisconnectImpl(const PeerAddress & address)
     194              :     {
     195            0 :         std::get<N>(mTransports).TCPDisconnect(address);
     196            0 :         TCPDisconnectImpl<N + 1>(address);
     197            0 :     }
     198              : 
     199              :     /**
     200              :      * TCPDisconnectImpl template for out of range N.
     201              :      */
     202              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     203            0 :     void TCPDisconnectImpl(const PeerAddress & address)
     204            0 :     {}
     205              : 
     206              :     /**
     207              :      * Recursive disconnect implementation iterating through transport members.
     208              :      *
     209              :      * @tparam N the index of the underlying transport to send disconnect to
     210              :      *
     211              :      * @param conn pointer to the connection to the peer.
     212              :      */
     213              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     214            0 :     void TCPDisconnectImpl(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0)
     215              :     {
     216            0 :         std::get<N>(mTransports).TCPDisconnect(conn, shouldAbort);
     217            0 :         TCPDisconnectImpl<N + 1>(conn, shouldAbort);
     218            0 :     }
     219              : 
     220              :     /**
     221              :      * TCPDisconnectImpl template for out of range N.
     222              :      */
     223              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     224            0 :     void TCPDisconnectImpl(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0)
     225            0 :     {}
     226              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     227              : 
     228              :     /**
     229              :      * Recursive disconnect implementation iterating through transport members.
     230              :      *
     231              :      * @tparam N the index of the underlying transport to send close to
     232              :      */
     233              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     234            4 :     void CloseImpl()
     235              :     {
     236            4 :         std::get<N>(mTransports).Close();
     237            4 :         CloseImpl<N + 1>();
     238            4 :     }
     239              : 
     240              :     /**
     241              :      * CloseImpl template for out of range N.
     242              :      */
     243              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     244            1 :     void CloseImpl()
     245            1 :     {}
     246              : 
     247              :     /**
     248              :      * Recursive sendmessage implementation iterating through transport members.
     249              :      *
     250              :      * Message is sent through the first transport from index N or above, which returns 'CanSendToPeer'
     251              :      *
     252              :      * @tparam N the index of the underlying transport to run SendMessage throug.
     253              :      *
     254              :      * @param address where to send the message
     255              :      * @param msgBuf the message to send.  Includes all CHIP message fields except optional length.
     256              :      */
     257              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     258            0 :     CHIP_ERROR SendMessageImpl(const PeerAddress & address, System::PacketBufferHandle && msgBuf)
     259              :     {
     260            0 :         Base * base = &std::get<N>(mTransports);
     261            0 :         if (base->CanSendToPeer(address))
     262              :         {
     263            0 :             return base->SendMessage(address, std::move(msgBuf));
     264              :         }
     265            0 :         return SendMessageImpl<N + 1>(address, std::move(msgBuf));
     266              :     }
     267              : 
     268              :     /**
     269              :      * SendMessageImpl when N is out of range. Always returns an error code.
     270              :      */
     271              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     272            0 :     CHIP_ERROR SendMessageImpl(const PeerAddress & address, System::PacketBufferHandle msgBuf)
     273              :     {
     274            0 :         return CHIP_ERROR_NO_MESSAGE_HANDLER;
     275              :     }
     276              : 
     277              :     /**
     278              :      * Recursive GroupJoinLeave implementation iterating through transport members.
     279              :      *
     280              :      * Listener is activated through the first transport from index N or above, which returns 'CanListenMulticast'
     281              :      *
     282              :      * @tparam N the index of the underlying transport to run GroupJoinLeave through.
     283              :      *
     284              :      * @param address where to send the message
     285              :      * @param join a boolean indicating if the transport should join or leave the group
     286              :      */
     287              :     template <size_t N, typename std::enable_if<(N < sizeof...(TransportTypes))>::type * = nullptr>
     288            0 :     CHIP_ERROR MulticastGroupJoinLeaveImpl(const Transport::PeerAddress & address, bool join)
     289              :     {
     290            0 :         Base * base = &std::get<N>(mTransports);
     291            0 :         if (base->CanListenMulticast())
     292              :         {
     293            0 :             return base->MulticastGroupJoinLeave(address, join);
     294              :         }
     295            0 :         return MulticastGroupJoinLeaveImpl<N + 1>(address, join);
     296              :     }
     297              : 
     298              :     /**
     299              :      * GroupJoinLeave when N is out of range. Always returns an error code.
     300              :      */
     301              :     template <size_t N, typename std::enable_if<(N >= sizeof...(TransportTypes))>::type * = nullptr>
     302            0 :     CHIP_ERROR MulticastGroupJoinLeaveImpl(const Transport::PeerAddress & address, bool join)
     303              :     {
     304            0 :         return CHIP_ERROR_NO_MESSAGE_HANDLER;
     305              :     }
     306              : 
     307              :     /**
     308              :      * Recursive init implementation iterating through transport members
     309              :      *
     310              :      * Given a set of arguments 'a1, a2, a3, ... aN' will call an Init method on the last N
     311              :      * transports.
     312              :      *
     313              :      * Method is expected to be called initially with exactly sizeof(TransportTypes) to initialize
     314              :      * all transports.
     315              :      *
     316              :      * @param arg the next initialize argument to pass to the transport Init method
     317              :      * @param rest tail arguments to be passed to the rest of transport Init methods.
     318              :      */
     319              :     template <typename InitArg, typename... Rest>
     320            4 :     CHIP_ERROR InitImpl(RawTransportDelegate * delegate, InitArg && arg, Rest &&... rest)
     321              :     {
     322            4 :         auto transport = &std::get<sizeof...(TransportTypes) - sizeof...(Rest) - 1>(mTransports);
     323              : 
     324            4 :         CHIP_ERROR err = transport->Init(std::forward<InitArg>(arg));
     325            4 :         if (err != CHIP_NO_ERROR)
     326              :         {
     327            0 :             return err;
     328              :         }
     329              : 
     330            4 :         transport->SetDelegate(delegate);
     331              : 
     332            4 :         return InitImpl(delegate, std::forward<Rest>(rest)...);
     333              :     }
     334              : 
     335              :     /**
     336              :      * Base case where initialization finishes.
     337              :      *
     338              :      * Provided to ensure that recursive InitImpl finishes compiling.
     339              :      */
     340            1 :     CHIP_ERROR InitImpl(RawTransportDelegate * delegate) { return CHIP_NO_ERROR; }
     341              : 
     342              :     std::tuple<TransportTypes...> mTransports;
     343              : 
     344              : public:
     345              :     template <size_t i>
     346            1 :     auto GetImplAtIndex() -> decltype(std::get<i>(mTransports)) &
     347              :     {
     348            1 :         return std::get<i>(mTransports);
     349              :     }
     350              : 
     351              :     std::tuple<TransportTypes...> & GetTransports() { return mTransports; }
     352              : };
     353              : 
     354              : } // namespace Transport
     355              : } // namespace chip
        

Generated by: LCOV version 2.0-1