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