blob: d97398bc79566f1ef4c7c2d407b963134acca62a [file] [log] [blame]
/*
*
* 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