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

Generated by: LCOV version 2.0-1