# 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

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.