LCOV - code coverage report
Current view: top level - transport/raw - Tuple.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 18 49 36.7 %
Date: 2024-02-15 08:20:41 Functions: 11 31 35.5 %

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

Generated by: LCOV version 1.14