Coverage Report

Created: 2026-02-12 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/connectedhomeip/src/transport/raw/PeerAddress.h
Line
Count
Source
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
 * @brief
20
 *    File contains definitions on how a connection to a peer can be defined.
21
 *
22
 */
23
24
#pragma once
25
26
#include <inet/IPAddress.h>
27
#include <inet/InetInterface.h>
28
#include <lib/core/CHIPConfig.h>
29
#include <lib/core/DataModelTypes.h>
30
#include <lib/support/CHIPMemString.h>
31
32
namespace chip {
33
namespace Transport {
34
35
/**
36
 * Communication path defines how two peers communicate.
37
 *
38
 * When a peer contacts another peer, it defines how the peers communicate.
39
 *
40
 * Once communication between two peers is established, the same transport
41
 * path should be used: a peer contacting another peer over UDP will receive
42
 * messages back over UDP. A communication channel established over TCP
43
 * will keep the same TCP channel.
44
 *
45
 */
46
47
/**
48
 * Here we specified Type to be uint8_t, so the PeerAddress can be serialized easily.
49
 */
50
enum class Type : uint8_t
51
{
52
    kUndefined,
53
    kUdp,
54
    kBle,
55
    kTcp,
56
    kWiFiPAF,
57
    kNfc,
58
    kLast = kNfc, // This is not an actual transport type, it just refers to the last transport type
59
};
60
61
/**
62
 * Describes how a peer on a CHIP network can be addressed.
63
 */
64
class PeerAddress
65
{
66
public:
67
4.92k
    constexpr PeerAddress() : mTransportType(Type::kUndefined), mId{ .mRemoteId = kUndefinedNodeId } {}
68
    constexpr PeerAddress(const Inet::IPAddress & addr, Type type) :
69
0
        mIPAddress(addr), mTransportType(type), mId{ .mRemoteId = kUndefinedNodeId }
70
0
    {}
71
1.88k
    constexpr PeerAddress(Type type) : mTransportType(type), mId{ .mRemoteId = kUndefinedNodeId } {}
72
0
    constexpr PeerAddress(Type type, NodeId remoteId) : mTransportType(type), mId{ .mRemoteId = remoteId } {}
73
74
    constexpr PeerAddress(PeerAddress &&)        = default;
75
3.35k
    constexpr PeerAddress(const PeerAddress &)   = default;
76
3.25k
    PeerAddress & operator=(const PeerAddress &) = default;
77
0
    PeerAddress & operator=(PeerAddress &&)      = default;
78
79
2.44k
    const Inet::IPAddress & GetIPAddress() const { return mIPAddress; }
80
    PeerAddress & SetIPAddress(const Inet::IPAddress & addr)
81
0
    {
82
0
        mIPAddress = addr;
83
0
        return *this;
84
0
    }
85
86
1.64k
    NodeId GetRemoteId() const { return mId.mRemoteId; }
87
88
    // NB: 0xFFFF is not allowed for NFC ShortId.
89
0
    uint16_t GetNFCShortId() const { return mId.mNFCShortId; }
90
91
25.7k
    Type GetTransportType() const { return mTransportType; }
92
    PeerAddress & SetTransportType(Type type)
93
0
    {
94
0
        mTransportType = type;
95
0
        return *this;
96
0
    }
97
98
0
    uint16_t GetPort() const { return mPort; }
99
    PeerAddress & SetPort(uint16_t port)
100
0
    {
101
0
        mPort = port;
102
0
        return *this;
103
0
    }
104
105
0
    Inet::InterfaceId GetInterface() const { return mInterface; }
106
    PeerAddress & SetInterface(Inet::InterfaceId interface)
107
1.67k
    {
108
1.67k
        mInterface = interface;
109
1.67k
        return *this;
110
1.67k
    }
111
112
0
    bool IsInitialized() const { return mTransportType != Type::kUndefined; }
113
114
0
    bool IsMulticast() { return Type::kUdp == mTransportType && mIPAddress.IsIPv6Multicast(); }
115
116
    bool operator==(const PeerAddress & other) const;
117
0
    bool operator!=(const PeerAddress & other) const { return !(*this == other); }
118
119
    /// Maximum size of the string outputes by ToString. Format is of the form:
120
    /// "UDP:<ip>:<port>"
121
    static constexpr size_t kMaxToStringSize = 3 // type: UDP/TCP/BLE
122
        + 1                                      // splitter :
123
        + 2                                      // brackets around address
124
        + Inet::IPAddress::kMaxStringLength      // address
125
        + 1                                      // splitter %
126
        + Inet::InterfaceId::kMaxIfNameLength    // interface
127
        + 1                                      // splitter :
128
        + 5                                      // port: 16 bit interger
129
        + 1;                                     // NullTerminator
130
131
    template <size_t N>
132
    inline void ToString(char (&buf)[N]) const
133
3.12k
    {
134
3.12k
        ToString(buf, N);
135
3.12k
    }
136
137
    void ToString(char * buf, size_t bufSize) const
138
3.12k
    {
139
3.12k
        char ip_addr[Inet::IPAddress::kMaxStringLength];
140
141
3.12k
        char interface[Inet::InterfaceId::kMaxIfNameLength + 1] = {}; // +1 to prepend '%'
142
3.12k
        if (mInterface.IsPresent())
143
0
        {
144
0
            interface[0]   = '%';
145
0
            interface[1]   = 0;
146
0
            CHIP_ERROR err = mInterface.GetInterfaceName(interface + 1, sizeof(interface) - 1);
147
0
            if (err != CHIP_NO_ERROR)
148
0
            {
149
0
                Platform::CopyString(interface, sizeof(interface), "%(err)");
150
0
            }
151
0
        }
152
153
3.12k
        switch (mTransportType)
154
3.12k
        {
155
354
        case Type::kUndefined:
156
354
            snprintf(buf, bufSize, "UNDEFINED");
157
354
            break;
158
762
        case Type::kUdp:
159
762
            mIPAddress.ToString(ip_addr);
160
762
#if INET_CONFIG_ENABLE_IPV4
161
762
            if (mIPAddress.IsIPv4())
162
0
                snprintf(buf, bufSize, "UDP:%s%s:%d", ip_addr, interface, mPort);
163
762
            else
164
762
#endif
165
762
                snprintf(buf, bufSize, "UDP:[%s%s]:%d", ip_addr, interface, mPort);
166
762
            break;
167
0
        case Type::kTcp:
168
0
            mIPAddress.ToString(ip_addr);
169
0
#if INET_CONFIG_ENABLE_IPV4
170
0
            if (mIPAddress.IsIPv4())
171
0
                snprintf(buf, bufSize, "TCP:%s%s:%d", ip_addr, interface, mPort);
172
0
            else
173
0
#endif
174
0
                snprintf(buf, bufSize, "TCP:[%s%s]:%d", ip_addr, interface, mPort);
175
0
            break;
176
1.64k
        case Type::kWiFiPAF:
177
1.64k
            snprintf(buf, bufSize, "Wi-Fi PAF");
178
1.64k
            break;
179
250
        case Type::kBle:
180
            // Note that BLE does not currently use any specific address.
181
250
            snprintf(buf, bufSize, "BLE");
182
250
            break;
183
110
        case Type::kNfc:
184
110
            snprintf(buf, bufSize, "NFC:%d", mId.mNFCShortId);
185
110
            break;
186
0
        default:
187
0
            snprintf(buf, bufSize, "ERROR");
188
0
            break;
189
3.12k
        }
190
3.12k
    }
191
192
    /****** Factory methods for convenience ******/
193
194
16
    static constexpr PeerAddress Uninitialized() { return PeerAddress(Type::kUndefined); }
195
196
0
    static constexpr PeerAddress BLE() { return PeerAddress(Type::kBle); }
197
198
    // NB: 0xFFFF is not allowed for NFC ShortId.
199
0
    static constexpr PeerAddress NFC() { return PeerAddress(kUndefinedNFCShortId()); }
200
0
    static constexpr PeerAddress NFC(const uint16_t shortId) { return PeerAddress(shortId); }
201
202
0
    static PeerAddress UDP(const Inet::IPAddress & addr) { return PeerAddress(addr, Type::kUdp); }
203
0
    static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port) { return UDP(addr).SetPort(port); }
204
205
    /**
206
     * Parses a PeerAddress from the given IP address string with UDP type. For example,
207
     * "192.168.1.4", "fe80::2", "fe80::1%wlan0". Notably this will also include the network scope
208
     * ID in either index or name form (e.g. %wlan0, %14).
209
     */
210
0
    static PeerAddress UDP(char * addrStr, uint16_t port) { return PeerAddress::FromString(addrStr, port, Type::kUdp); }
211
    static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface)
212
0
    {
213
0
        return UDP(addr).SetPort(port).SetInterface(interface);
214
0
    }
215
0
    static PeerAddress TCP(const Inet::IPAddress & addr) { return PeerAddress(addr, Type::kTcp); }
216
0
    static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port) { return TCP(addr).SetPort(port); }
217
218
    /**
219
     * Parses a PeerAddress from the given IP address string with TCP type. For example,
220
     * "192.168.1.4", "fe80::2", "fe80::1%wlan0". Notably this will also include the network scope
221
     * ID in either index or name form (e.g. %wlan0, %14).
222
     */
223
0
    static PeerAddress TCP(char * addrStr, uint16_t port) { return PeerAddress::FromString(addrStr, port, Type::kTcp); }
224
    static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface)
225
0
    {
226
0
        return TCP(addr).SetPort(port).SetInterface(interface);
227
0
    }
228
229
0
    static constexpr PeerAddress WiFiPAF(NodeId remoteId) { return PeerAddress(Type::kWiFiPAF, remoteId); }
230
231
    static PeerAddress Multicast(chip::FabricId fabric, chip::GroupId group)
232
0
    {
233
0
        constexpr uint8_t scope        = 0x05; // Site-Local
234
0
        constexpr uint8_t prefixLength = 0x40; // 64-bit long network prefix field
235
        // The network prefix portion of the Multicast Address is the 64-bit bitstring formed by concatenating:
236
        // * 0xFD to designate a locally assigned ULA prefix
237
        // * The upper 56-bits of the Fabric ID for the network in big-endian order
238
0
        const uint64_t prefix = 0xfd00000000000000 | ((fabric >> 8) & 0x00ffffffffffffff);
239
        // The 32-bit group identifier portion of the Multicast Address is the 32-bits formed by:
240
        // * The lower 8-bits of the Fabric ID
241
        // * 0x00
242
        // * The 16-bits Group Identifier in big-endian order
243
0
        uint32_t groupId = static_cast<uint32_t>((fabric << 24) & 0xff000000) | group;
244
0
        return UDP(Inet::IPAddress::MakeIPv6PrefixMulticast(scope, prefixLength, prefix, groupId));
245
0
    }
246
247
    static PeerAddress Groupcast()
248
0
    {
249
0
        constexpr uint8_t scope        = 0x05; // Site-Local
250
0
        constexpr uint8_t prefixLength = 0x40; // 64-bit long network prefix field
251
0
        // IANA assigned address
252
0
        return UDP(Inet::IPAddress::MakeIPv6PrefixMulticast(scope, prefixLength, 0xff05000000000000, 0xfa));
253
0
    }
254
255
private:
256
0
    constexpr PeerAddress(uint16_t shortId) : mTransportType(Type::kNfc), mId{ .mNFCShortId = shortId } {}
257
258
    static PeerAddress FromString(char * addrStr, uint16_t port, Type type)
259
0
    {
260
0
        Inet::IPAddress addr;
261
0
        Inet::InterfaceId interfaceId;
262
0
        Inet::IPAddress::FromString(addrStr, addr, interfaceId);
263
0
        return PeerAddress(addr, type).SetPort(port).SetInterface(interfaceId);
264
0
    }
265
266
0
    static constexpr uint16_t kUndefinedNFCShortId() { return 0xFFFF; }
267
268
    Inet::IPAddress mIPAddress   = {};
269
    Type mTransportType          = Type::kUndefined;
270
    uint16_t mPort               = CHIP_PORT; ///< Relevant for UDP data sending.
271
    Inet::InterfaceId mInterface = Inet::InterfaceId::Null();
272
273
    union Id
274
    {
275
        NodeId mRemoteId;
276
        uint16_t mNFCShortId;
277
    } mId;
278
};
279
280
} // namespace Transport
281
} // namespace chip