| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @brief |
| * File contains definitions on how a connection to a peer can be defined. |
| * |
| */ |
| |
| #pragma once |
| |
| #include <inet/IPAddress.h> |
| #include <inet/InetInterface.h> |
| #include <lib/core/CHIPConfig.h> |
| #include <lib/core/DataModelTypes.h> |
| #include <lib/support/CHIPMemString.h> |
| |
| namespace chip { |
| namespace Transport { |
| |
| /** |
| * Communication path defines how two peers communicate. |
| * |
| * When a peer contacts another peer, it defines how the peers communicate. |
| * |
| * Once communication between two peers is established, the same transport |
| * path should be used: a peer contacting another peer over UDP will receive |
| * messages back over UDP. A communication channel established over TCP |
| * will keep the same TCP channel. |
| * |
| */ |
| |
| /** |
| * Here we specified Type to be uint8_t, so the PeerAddress can be serialized easily. |
| */ |
| enum class Type : uint8_t |
| { |
| kUndefined, |
| kUdp, |
| kBle, |
| kTcp, |
| }; |
| |
| /** |
| * Describes how a peer on a CHIP network can be addressed. |
| */ |
| class PeerAddress |
| { |
| public: |
| PeerAddress() : mIPAddress(Inet::IPAddress::Any), mTransportType(Type::kUndefined) {} |
| PeerAddress(const Inet::IPAddress & addr, Type type) : mIPAddress(addr), mTransportType(type) {} |
| PeerAddress(Type type) : mTransportType(type) {} |
| |
| PeerAddress(PeerAddress &&) = default; |
| PeerAddress(const PeerAddress &) = default; |
| PeerAddress & operator=(const PeerAddress &) = default; |
| PeerAddress & operator=(PeerAddress &&) = default; |
| |
| const Inet::IPAddress & GetIPAddress() const { return mIPAddress; } |
| PeerAddress & SetIPAddress(const Inet::IPAddress & addr) |
| { |
| mIPAddress = addr; |
| return *this; |
| } |
| |
| Type GetTransportType() const { return mTransportType; } |
| PeerAddress & SetTransportType(Type type) |
| { |
| mTransportType = type; |
| return *this; |
| } |
| |
| uint16_t GetPort() const { return mPort; } |
| PeerAddress & SetPort(uint16_t port) |
| { |
| mPort = port; |
| return *this; |
| } |
| |
| Inet::InterfaceId GetInterface() const { return mInterface; } |
| PeerAddress & SetInterface(Inet::InterfaceId interface) |
| { |
| mInterface = interface; |
| return *this; |
| } |
| |
| bool IsInitialized() const { return mTransportType != Type::kUndefined; } |
| |
| bool IsMulticast() { return Type::kUdp == mTransportType && mIPAddress.IsIPv6Multicast(); } |
| |
| bool operator==(const PeerAddress & other) const |
| { |
| return (mTransportType == other.mTransportType) && (mIPAddress == other.mIPAddress) && (mPort == other.mPort) && |
| (mInterface == other.mInterface); |
| } |
| |
| bool operator!=(const PeerAddress & other) const { return !(*this == other); } |
| |
| /// Maximum size of the string outputes by ToString. Format is of the form: |
| /// "UDP:<ip>:<port>" |
| static constexpr size_t kMaxToStringSize = 3 // type: UDP/TCP/BLE |
| + 1 // splitter : |
| + 2 // brackets around address |
| + Inet::IPAddress::kMaxStringLength // address |
| + 1 // splitter % |
| + Inet::InterfaceId::kMaxIfNameLength // interface |
| + 1 // splitter : |
| + 5 // port: 16 bit interger |
| + 1; // NullTerminator |
| |
| template <size_t N> |
| inline void ToString(char (&buf)[N]) const |
| { |
| ToString(buf, N); |
| } |
| |
| void ToString(char * buf, size_t bufSize) const |
| { |
| char ip_addr[Inet::IPAddress::kMaxStringLength]; |
| |
| char interface[Inet::InterfaceId::kMaxIfNameLength + 1] = {}; // +1 to prepend '%' |
| if (mInterface.IsPresent()) |
| { |
| interface[0] = '%'; |
| interface[1] = 0; |
| CHIP_ERROR err = mInterface.GetInterfaceName(interface + 1, sizeof(interface) - 1); |
| if (err != CHIP_NO_ERROR) |
| { |
| Platform::CopyString(interface, sizeof(interface), "%(err)"); |
| } |
| } |
| |
| switch (mTransportType) |
| { |
| case Type::kUndefined: |
| snprintf(buf, bufSize, "UNDEFINED"); |
| break; |
| case Type::kUdp: |
| mIPAddress.ToString(ip_addr); |
| #if INET_CONFIG_ENABLE_IPV4 |
| if (mIPAddress.IsIPv4()) |
| snprintf(buf, bufSize, "UDP:%s%s:%d", ip_addr, interface, mPort); |
| else |
| #endif |
| snprintf(buf, bufSize, "UDP:[%s%s]:%d", ip_addr, interface, mPort); |
| break; |
| case Type::kTcp: |
| mIPAddress.ToString(ip_addr); |
| #if INET_CONFIG_ENABLE_IPV4 |
| if (mIPAddress.IsIPv4()) |
| snprintf(buf, bufSize, "TCP:%s%s:%d", ip_addr, interface, mPort); |
| else |
| #endif |
| snprintf(buf, bufSize, "TCP:[%s%s]:%d", ip_addr, interface, mPort); |
| break; |
| case Type::kBle: |
| // Note that BLE does not currently use any specific address. |
| snprintf(buf, bufSize, "BLE"); |
| break; |
| default: |
| snprintf(buf, bufSize, "ERROR"); |
| break; |
| } |
| } |
| |
| /****** Factory methods for convenience ******/ |
| |
| static PeerAddress Uninitialized() { return PeerAddress(Inet::IPAddress::Any, Type::kUndefined); } |
| |
| static PeerAddress BLE() { return PeerAddress(Type::kBle); } |
| static PeerAddress UDP(const Inet::IPAddress & addr) { return PeerAddress(addr, Type::kUdp); } |
| static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port) { return UDP(addr).SetPort(port); } |
| |
| /** |
| * Parses a PeerAddress from the given IP address string with UDP type. For example, |
| * "192.168.1.4", "fe80::2", "fe80::1%wlan0". Notably this will also include the network scope |
| * ID in either index or name form (e.g. %wlan0, %14). |
| */ |
| static PeerAddress UDP(char * addrStr, uint16_t port) { return PeerAddress::FromString(addrStr, port, Type::kUdp); } |
| static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface) |
| { |
| return UDP(addr).SetPort(port).SetInterface(interface); |
| } |
| static PeerAddress TCP(const Inet::IPAddress & addr) { return PeerAddress(addr, Type::kTcp); } |
| static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port) { return TCP(addr).SetPort(port); } |
| |
| /** |
| * Parses a PeerAddress from the given IP address string with TCP type. For example, |
| * "192.168.1.4", "fe80::2", "fe80::1%wlan0". Notably this will also include the network scope |
| * ID in either index or name form (e.g. %wlan0, %14). |
| */ |
| static PeerAddress TCP(char * addrStr, uint16_t port) { return PeerAddress::FromString(addrStr, port, Type::kTcp); } |
| static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface) |
| { |
| return TCP(addr).SetPort(port).SetInterface(interface); |
| } |
| |
| static PeerAddress Multicast(chip::FabricId fabric, chip::GroupId group) |
| { |
| constexpr uint8_t scope = 0x05; // Site-Local |
| constexpr uint8_t prefixLength = 0x40; // 64-bit long network prefix field |
| // The network prefix portion of the Multicast Address is the 64-bit bitstring formed by concatenating: |
| // * 0xFD to designate a locally assigned ULA prefix |
| // * The upper 56-bits of the Fabric ID for the network in big-endian order |
| const uint64_t prefix = 0xfd00000000000000 | ((fabric >> 8) & 0x00ffffffffffffff); |
| // The 32-bit group identifier portion of the Multicast Address is the 32-bits formed by: |
| // * The lower 8-bits of the Fabric ID |
| // * 0x00 |
| // * The 16-bits Group Identifier in big-endian order |
| uint32_t groupId = static_cast<uint32_t>((fabric << 24) & 0xff000000) | group; |
| return UDP(Inet::IPAddress::MakeIPv6PrefixMulticast(scope, prefixLength, prefix, groupId)); |
| } |
| |
| private: |
| static PeerAddress FromString(char * addrStr, uint16_t port, Type type) |
| { |
| Inet::IPAddress addr; |
| Inet::InterfaceId interfaceId; |
| Inet::IPAddress::FromString(addrStr, addr, interfaceId); |
| return PeerAddress(addr, type).SetPort(port).SetInterface(interfaceId); |
| } |
| Inet::IPAddress mIPAddress = {}; |
| Type mTransportType = Type::kUndefined; |
| uint16_t mPort = CHIP_PORT; ///< Relevant for UDP data sending. |
| Inet::InterfaceId mInterface = Inet::InterfaceId::Null(); |
| }; |
| |
| } // namespace Transport |
| } // namespace chip |