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 <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 757 : PeerAddress() : mIPAddress(Inet::IPAddress::Any), mTransportType(Type::kUndefined) { mId.mRemoteId = kUndefinedNodeId; }
68 24 : PeerAddress(const Inet::IPAddress & addr, Type type) : mIPAddress(addr), mTransportType(type)
69 : {
70 24 : mId.mRemoteId = kUndefinedNodeId;
71 24 : }
72 0 : PeerAddress(Type type) : mTransportType(type) { mId.mRemoteId = kUndefinedNodeId; }
73 0 : PeerAddress(Type type, NodeId remoteId) : mTransportType(type) { mId.mRemoteId = remoteId; }
74 :
75 : PeerAddress(PeerAddress &&) = default;
76 0 : PeerAddress(const PeerAddress &) = default;
77 1876 : PeerAddress & operator=(const PeerAddress &) = default;
78 26 : PeerAddress & operator=(PeerAddress &&) = default;
79 :
80 14909 : const Inet::IPAddress & GetIPAddress() const { return mIPAddress; }
81 0 : PeerAddress & SetIPAddress(const Inet::IPAddress & addr)
82 : {
83 0 : mIPAddress = addr;
84 0 : return *this;
85 : }
86 :
87 0 : NodeId GetRemoteId() const { return mId.mRemoteId; }
88 :
89 : // NB: 0xFFFF is not allowed for NFC ShortId.
90 : uint16_t GetNFCShortId() const { return mId.mNFCShortId; }
91 :
92 7114 : Type GetTransportType() const { return mTransportType; }
93 0 : PeerAddress & SetTransportType(Type type)
94 : {
95 0 : mTransportType = type;
96 0 : return *this;
97 : }
98 :
99 53 : uint16_t GetPort() const { return mPort; }
100 0 : PeerAddress & SetPort(uint16_t port)
101 : {
102 0 : mPort = port;
103 0 : return *this;
104 : }
105 :
106 128 : Inet::InterfaceId GetInterface() const { return mInterface; }
107 14934 : PeerAddress & SetInterface(Inet::InterfaceId interface)
108 : {
109 14934 : mInterface = interface;
110 14934 : return *this;
111 : }
112 :
113 : bool IsInitialized() const { return mTransportType != Type::kUndefined; }
114 :
115 : bool IsMulticast() { return Type::kUdp == mTransportType && mIPAddress.IsIPv6Multicast(); }
116 :
117 12810 : bool operator==(const PeerAddress & other) const
118 : {
119 : // Compare common fields
120 25615 : if (mTransportType != other.mTransportType || mIPAddress != other.mIPAddress || mPort != other.mPort ||
121 12805 : mInterface != other.mInterface)
122 : {
123 5 : return false;
124 : }
125 :
126 : // Compare transport-type-specific fields
127 12805 : if (mTransportType == Type::kNfc)
128 : {
129 0 : return mId.mNFCShortId == other.mId.mNFCShortId;
130 : }
131 :
132 : // For other transport types, no additional fields to compare
133 12805 : return true;
134 : }
135 :
136 14796 : bool operator!=(const PeerAddress & other) const { return !(*this == other); }
137 :
138 : /// Maximum size of the string outputes by ToString. Format is of the form:
139 : /// "UDP:<ip>:<port>"
140 : static constexpr size_t kMaxToStringSize = 3 // type: UDP/TCP/BLE
141 : + 1 // splitter :
142 : + 2 // brackets around address
143 : + Inet::IPAddress::kMaxStringLength // address
144 : + 1 // splitter %
145 : + Inet::InterfaceId::kMaxIfNameLength // interface
146 : + 1 // splitter :
147 : + 5 // port: 16 bit interger
148 : + 1; // NullTerminator
149 :
150 : template <size_t N>
151 15045 : inline void ToString(char (&buf)[N]) const
152 : {
153 15045 : ToString(buf, N);
154 15045 : }
155 :
156 15045 : void ToString(char * buf, size_t bufSize) const
157 : {
158 : char ip_addr[Inet::IPAddress::kMaxStringLength];
159 :
160 15045 : char interface[Inet::InterfaceId::kMaxIfNameLength + 1] = {}; // +1 to prepend '%'
161 15045 : if (mInterface.IsPresent())
162 : {
163 0 : interface[0] = '%';
164 0 : interface[1] = 0;
165 0 : CHIP_ERROR err = mInterface.GetInterfaceName(interface + 1, sizeof(interface) - 1);
166 0 : if (err != CHIP_NO_ERROR)
167 : {
168 0 : Platform::CopyString(interface, sizeof(interface), "%(err)");
169 : }
170 : }
171 :
172 15045 : switch (mTransportType)
173 : {
174 47 : case Type::kUndefined:
175 47 : snprintf(buf, bufSize, "UNDEFINED");
176 47 : break;
177 14957 : case Type::kUdp:
178 14957 : mIPAddress.ToString(ip_addr);
179 : #if INET_CONFIG_ENABLE_IPV4
180 14957 : if (mIPAddress.IsIPv4())
181 0 : snprintf(buf, bufSize, "UDP:%s%s:%d", ip_addr, interface, mPort);
182 : else
183 : #endif
184 14957 : snprintf(buf, bufSize, "UDP:[%s%s]:%d", ip_addr, interface, mPort);
185 14957 : break;
186 41 : case Type::kTcp:
187 41 : mIPAddress.ToString(ip_addr);
188 : #if INET_CONFIG_ENABLE_IPV4
189 41 : if (mIPAddress.IsIPv4())
190 15 : snprintf(buf, bufSize, "TCP:%s%s:%d", ip_addr, interface, mPort);
191 : else
192 : #endif
193 26 : snprintf(buf, bufSize, "TCP:[%s%s]:%d", ip_addr, interface, mPort);
194 41 : break;
195 0 : case Type::kWiFiPAF:
196 0 : snprintf(buf, bufSize, "Wi-Fi PAF");
197 0 : break;
198 0 : case Type::kBle:
199 : // Note that BLE does not currently use any specific address.
200 0 : snprintf(buf, bufSize, "BLE");
201 0 : break;
202 0 : case Type::kNfc:
203 0 : snprintf(buf, bufSize, "NFC:%d", mId.mNFCShortId);
204 0 : break;
205 0 : default:
206 0 : snprintf(buf, bufSize, "ERROR");
207 0 : break;
208 : }
209 15045 : }
210 :
211 : /****** Factory methods for convenience ******/
212 :
213 24 : static PeerAddress Uninitialized() { return PeerAddress(Inet::IPAddress::Any, Type::kUndefined); }
214 :
215 0 : static PeerAddress BLE() { return PeerAddress(Type::kBle); }
216 :
217 : // NB: 0xFFFF is not allowed for NFC ShortId.
218 : static constexpr PeerAddress NFC() { return PeerAddress(kUndefinedNFCShortId()); }
219 : static constexpr PeerAddress NFC(const uint16_t shortId) { return PeerAddress(shortId); }
220 :
221 0 : static PeerAddress UDP(const Inet::IPAddress & addr) { return PeerAddress(addr, Type::kUdp); }
222 0 : static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port) { return UDP(addr).SetPort(port); }
223 :
224 : /**
225 : * Parses a PeerAddress from the given IP address string with UDP type. For example,
226 : * "192.168.1.4", "fe80::2", "fe80::1%wlan0". Notably this will also include the network scope
227 : * ID in either index or name form (e.g. %wlan0, %14).
228 : */
229 : static PeerAddress UDP(char * addrStr, uint16_t port) { return PeerAddress::FromString(addrStr, port, Type::kUdp); }
230 2 : static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface)
231 : {
232 2 : return UDP(addr).SetPort(port).SetInterface(interface);
233 : }
234 0 : static PeerAddress TCP(const Inet::IPAddress & addr) { return PeerAddress(addr, Type::kTcp); }
235 : static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port) { return TCP(addr).SetPort(port); }
236 :
237 : /**
238 : * Parses a PeerAddress from the given IP address string with TCP type. For example,
239 : * "192.168.1.4", "fe80::2", "fe80::1%wlan0". Notably this will also include the network scope
240 : * ID in either index or name form (e.g. %wlan0, %14).
241 : */
242 : static PeerAddress TCP(char * addrStr, uint16_t port) { return PeerAddress::FromString(addrStr, port, Type::kTcp); }
243 27 : static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface)
244 : {
245 27 : return TCP(addr).SetPort(port).SetInterface(interface);
246 : }
247 :
248 0 : static PeerAddress WiFiPAF(NodeId remoteId) { return PeerAddress(Type::kWiFiPAF, remoteId); }
249 :
250 4 : static PeerAddress Multicast(chip::FabricId fabric, chip::GroupId group)
251 : {
252 4 : constexpr uint8_t scope = 0x05; // Site-Local
253 4 : constexpr uint8_t prefixLength = 0x40; // 64-bit long network prefix field
254 : // The network prefix portion of the Multicast Address is the 64-bit bitstring formed by concatenating:
255 : // * 0xFD to designate a locally assigned ULA prefix
256 : // * The upper 56-bits of the Fabric ID for the network in big-endian order
257 4 : const uint64_t prefix = 0xfd00000000000000 | ((fabric >> 8) & 0x00ffffffffffffff);
258 : // The 32-bit group identifier portion of the Multicast Address is the 32-bits formed by:
259 : // * The lower 8-bits of the Fabric ID
260 : // * 0x00
261 : // * The 16-bits Group Identifier in big-endian order
262 4 : uint32_t groupId = static_cast<uint32_t>((fabric << 24) & 0xff000000) | group;
263 4 : return UDP(Inet::IPAddress::MakeIPv6PrefixMulticast(scope, prefixLength, prefix, groupId));
264 : }
265 :
266 : private:
267 : constexpr PeerAddress(uint16_t shortId) : mTransportType(Type::kNfc), mId{ .mNFCShortId = shortId } {}
268 :
269 : static PeerAddress FromString(char * addrStr, uint16_t port, Type type)
270 : {
271 : Inet::IPAddress addr;
272 : Inet::InterfaceId interfaceId;
273 : Inet::IPAddress::FromString(addrStr, addr, interfaceId);
274 : return PeerAddress(addr, type).SetPort(port).SetInterface(interfaceId);
275 : }
276 :
277 : static constexpr uint16_t kUndefinedNFCShortId() { return 0xFFFF; }
278 :
279 : Inet::IPAddress mIPAddress = {};
280 : Type mTransportType = Type::kUndefined;
281 : uint16_t mPort = CHIP_PORT; ///< Relevant for UDP data sending.
282 : Inet::InterfaceId mInterface = Inet::InterfaceId::Null();
283 :
284 : union Id
285 : {
286 : NodeId mRemoteId;
287 : uint16_t mNFCShortId;
288 : } mId;
289 : };
290 :
291 : } // namespace Transport
292 : } // namespace chip
|