/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 |