# Transport classes ###### tags: `CHIP` `Matter` `Firmware` `Engineer` > 2022/03/26 > CHIP git hash code 67b4746ad8 In this post, we will try to give you an idea how transport classes look like. ## Class diagram ![](https://i.imgur.com/tVGxmai.jpg) About this diagram: 1. I tried to follow the UML standard, But not exactly. 2. I didn't really list all functions/members in each classes, I just put on some to give you a idea how it looks like and make it easier to understand. 3. The blue text is not the exactly function/member in the original class, I kind of expend the template arguments. 4. It's using delegate design pattern, you will see this how it assign the delegation later. ## Tuple In transport/raw/Tuple.h, it describes the idea of the tuple class. But I think that's also the core of the design of this transport class. > Groups together several transports of different types and presents them as a unified transport. > The usage intent is to be able to group several distinct transport types and make them look as a single transport. So, whenever CHIP stack wants to send out a message, it will do something like this: `mTransportMgr->SendMessage(*destination, std::move(msgBuf));` ### std::tuple This transport class uses truple to group different type of transport. I don't really dig into the std::tuple source code, but I know enough to use and understand the tuple api. If you don't really know what a tuple is, check the describe in transport/raw/Tuple.h ```cpp=1 /* * Having an example class definition of `Tuple<UDP, UDP, TCP>` * * Is equivalent to: * * ~~~~~~~~~ * class TupleOfUdpUdpTcp : public BASE { * private: * UDP mUdp1; * UDP mUdp2; * TCP mTcp3; * public: * Init(UDPListenParameters &, UDPListenParameters&, TCPListenParameters) {...} * CHIP_ERROR SendMessage(...) override; * bool CanSendToPeer(...) override; * } * ~~~~~~~~~ * / ``` ## Init In this class, most of member function use recursive call to walk through the tuple. And I would like to use the init function as an example to show how the recursive call works. So, let's start with this function in TransportMgr.h: ```cpp=1 template <typename... Args> CHIP_ERROR Init(Args &&... transportInitArgs) { ReturnErrorOnFailure(mTransport.Init(this, std::forward<Args>(transportInitArgs)...)); return TransportMgrBase::Init(&mTransport); } ``` As you can see, the first line of code calls the Init function of mTransport, so let's follow it to the Tuple.h file: ```cpp=1 template <typename... Args, typename std::enable_if<(sizeof...(Args) == sizeof...(TransportTypes))>::type * = nullptr> CHIP_ERROR Init(RawTransportDelegate * delegate, Args &&... args) { return InitImpl(delegate, std::forward<Args>(args)...); } ``` ```cpp=1 /* * So here is the recursive call, I will use the TransportMgr class in the server.h as an example. * * using ServerTransportMgr = * chip::TransportMgr<chip::Transport::UDP * chip::Transport::UDP, * chip::Transport::BLE<kMaxBlePendingPackets> */ template <typename InitArg, typename... Rest> CHIP_ERROR InitImpl(RawTransportDelegate * delegate, InitArg && arg, Rest &&... rest) { /* Try to extract one transport instance from the tuple by ascending order. * So we totally have 3 transports in our example and that means * * ==first round== * sizeof...(TransportTypes) = 3 * sizeof...(Rest) = 2 * And this line of code = * auto transport = &std::get<0>(mTransports) * * ==second round== * sizeof...(TransportTypes) = 3 * sizeof...(Rest) = 1 * And this line of code = * auto transport = &std::get<1>(mTransports) * * ==third round== * sizeof...(TransportTypes) = 3 * sizeof...(Rest) = 0 * And this line of code = * auto transport = &std::get<2>(mTransports) */ auto transport = &std::get<sizeof...(TransportTypes) - sizeof...(Rest) - 1>(mTransports); // Calling the init function of the just extracted transport instance. CHIP_ERROR err = transport->Init(std::forward<InitArg>(arg)); if (err != CHIP_NO_ERROR) { return err; } // the delegate transport->SetDelegate(delegate); // Recrusive call. // And there is actually fourth round of recursive call, but it will go the next function because the std::forward<Rest>(rest) is actually empty. return InitImpl(delegate, std::forward<Rest>(rest)...); } // The fourth round CHIP_ERROR InitImpl(RawTransportDelegate * delegate) { return CHIP_NO_ERROR; } ``` So I put some comments to the code to explain what happens in this funtion by a example. And you can find the exactly pattern in many other member functions in this class. ## SendMessage Basically, nothing specially in this function, but here is the transport logic you may want to know first(in the Tuple.h file): ```cpp=1 /* * Transport logic: * - Every transport can decide if a 'PeerAddress' can be sent over 'self' * * - Within a mixed tuple, if several transports support a peer address (e.g. TCP and UDP both * support IP), the first one found wins. * * - Expected message sending logic: * - BLE transports only support BLE. TCP/UDP support IP addresses * - Multicasts only supported by UDP */ ``` ## That's all I think the rest of this class is quite easy to undetstand, so I will stop this post here and hopelly this post would help you to understand this class better.