diff --git a/src/app/CASESessionManager.cpp b/src/app/CASESessionManager.cpp index 047562fabb03f9..393527ad8a7abe 100644 --- a/src/app/CASESessionManager.cpp +++ b/src/app/CASESessionManager.cpp @@ -92,7 +92,7 @@ void CASESessionManager::OnNodeIdResolved(const Dnssd::ResolvedNodeData & nodeDa VerifyOrReturn(session != nullptr, ChipLogDetail(Controller, "OnNodeIdResolved was called for a device with no active sessions, ignoring it.")); - LogErrorOnFailure(session->UpdateDeviceData(session->ToPeerAddress(nodeData), nodeData.GetMRPConfig())); + LogErrorOnFailure(session->UpdateDeviceData(OperationalDeviceProxy::ToPeerAddress(nodeData), nodeData.GetMRPConfig())); } void CASESessionManager::OnNodeIdResolutionFailed(const PeerId & peer, CHIP_ERROR error) diff --git a/src/app/OperationalDeviceProxy.h b/src/app/OperationalDeviceProxy.h index 95cca4a8825455..92f82c320ab4d1 100644 --- a/src/app/OperationalDeviceProxy.h +++ b/src/app/OperationalDeviceProxy.h @@ -178,19 +178,31 @@ class DLL_EXPORT OperationalDeviceProxy : public DeviceProxy, SessionReleaseDele static Transport::PeerAddress ToPeerAddress(const Dnssd::ResolvedNodeData & nodeData) { - Inet::InterfaceId interfaceId = Inet::InterfaceId::Null(); - - // TODO - Revisit usage of InterfaceID only for addresses that are IPv6 LLA - // Only use the DNS-SD resolution's InterfaceID for addresses that are IPv6 LLA. - // For all other addresses, we should rely on the device's routing table to route messages sent. - // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread, - // mDNS advertisements are not usually received on the same interface the peer is reachable on. - if (nodeData.mAddress[0].IsIPv6LinkLocal()) + Transport::PeerAddress address = Transport::PeerAddress(Transport::Type::kUdp); + address.SetPort(nodeData.mPort); + + for (unsigned i = 0; i < nodeData.mNumIPs; i++) { - interfaceId = nodeData.mInterfaceId; + const auto addr = nodeData.mAddress[i]; + // Only use the mDNS resolution's InterfaceID for addresses that are IPv6 LLA. + // For all other addresses, we should rely on the device's routing table to route messages sent. + // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread, + // mDNS advertisements are not usually received on the same interface the peer is reachable on. + // TODO: Right now, just use addr0, but we should really push all the addresses and interfaces to + // the device and allow it to make a proper decision about which addresses are preferred and reachable. + CHIP_ERROR err = address.AppendDestination(nodeData.mAddress[i], + addr.IsIPv6LinkLocal() ? nodeData.mInterfaceId : Inet::InterfaceId::Null()); + + if (err != CHIP_NO_ERROR) + { + char addr_str[Inet::IPAddress::kMaxStringLength]; + addr.ToString(addr_str); + + ChipLogError(Controller, "Could not append IP address %s: %s", addr_str, err.AsString()); + } } - return Transport::PeerAddress::UDP(nodeData.mAddress[0], nodeData.mPort, interfaceId); + return address; } private: diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 7046c768df4625..5c62aef675c9c1 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -554,23 +554,6 @@ CHIP_ERROR DeviceController::OpenCommissioningWindowInternal() } #if CHIP_DEVICE_CONFIG_ENABLE_DNSSD -Transport::PeerAddress DeviceController::ToPeerAddress(const chip::Dnssd::ResolvedNodeData & nodeData) const -{ - Inet::InterfaceId interfaceId; - - // Only use the mDNS resolution's InterfaceID for addresses that are IPv6 LLA. - // For all other addresses, we should rely on the device's routing table to route messages sent. - // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread, - // mDNS advertisements are not usually received on the same interface the peer is reachable on. - // TODO: Right now, just use addr0, but we should really push all the addresses and interfaces to - // the device and allow it to make a proper decision about which addresses are preferred and reachable. - if (nodeData.mAddress[0].IsIPv6LinkLocal()) - { - interfaceId = nodeData.mInterfaceId; - } - - return Transport::PeerAddress::UDP(nodeData.mAddress[0], nodeData.mPort, interfaceId); -} void DeviceController::OnNodeIdResolved(const chip::Dnssd::ResolvedNodeData & nodeData) { diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index f922cedbaf9e75..039a281cdfc65d 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -353,8 +353,6 @@ class DLL_EXPORT DeviceController : public SessionRecoveryDelegate PersistentStorageDelegate * mStorageDelegate = nullptr; #if CHIP_DEVICE_CONFIG_ENABLE_DNSSD - Transport::PeerAddress ToPeerAddress(const chip::Dnssd::ResolvedNodeData & nodeData) const; - DeviceAddressUpdateDelegate * mDeviceAddressUpdateDelegate = nullptr; // TODO(cecille): Make this configuarable. static constexpr int kMaxCommissionableNodes = 10; diff --git a/src/controller/CommissioneeDeviceProxy.h b/src/controller/CommissioneeDeviceProxy.h index ca3715a23c6710..6f21ba5025cacb 100644 --- a/src/controller/CommissioneeDeviceProxy.h +++ b/src/controller/CommissioneeDeviceProxy.h @@ -216,7 +216,7 @@ class CommissioneeDeviceProxy : public DeviceProxy, public SessionReleaseDelegat Messaging::ExchangeManager * GetExchangeManager() const override { return mExchangeMgr; } - void SetAddress(const Inet::IPAddress & deviceAddr) { mDeviceAddress.SetIPAddress(deviceAddr); } + void SetAddress(const Inet::IPAddress & deviceAddr) { mDeviceAddress.SetSingleIPAddress(deviceAddr); } PASESession & GetPairing() { return mPairing; } diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 72d579b1fdb72e..7a6300522a90d0 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -324,7 +324,7 @@ ChipError::StorageType pychip_DeviceController_ConnectIP(chip::Controller::Devic VerifyOrReturnError(chip::Inet::IPAddress::FromString(peerAddrStr, peerAddr), CHIP_ERROR_INVALID_ARGUMENT.AsInteger()); // TODO: IP rendezvous should use TCP connection. - addr.SetTransportType(chip::Transport::Type::kUdp).SetIPAddress(peerAddr); + addr.SetTransportType(chip::Transport::Type::kUdp).SetSingleIPAddress(peerAddr); params.SetPeerAddress(addr).SetDiscriminator(0); devCtrl->ReleaseOperationalDevice(nodeid); @@ -380,7 +380,7 @@ ChipError::StorageType pychip_DeviceController_EstablishPASESessionIP(chip::Cont chip::Transport::PeerAddress addr; RendezvousParameters params = chip::RendezvousParameters().SetSetupPINCode(setupPINCode); VerifyOrReturnError(chip::Inet::IPAddress::FromString(peerAddrStr, peerAddr), CHIP_ERROR_INVALID_ARGUMENT.AsInteger()); - addr.SetTransportType(chip::Transport::Type::kUdp).SetIPAddress(peerAddr); + addr.SetTransportType(chip::Transport::Type::kUdp).SetSingleIPAddress(peerAddr); params.SetPeerAddress(addr).SetDiscriminator(0); return devCtrl->EstablishPASEConnection(nodeid, params).AsInteger(); } diff --git a/src/transport/raw/BUILD.gn b/src/transport/raw/BUILD.gn index ae3aeb58f8e3e9..d13c3adb5e3861 100644 --- a/src/transport/raw/BUILD.gn +++ b/src/transport/raw/BUILD.gn @@ -22,6 +22,7 @@ static_library("raw") { "Base.h", "MessageHeader.cpp", "MessageHeader.h", + "PeerAddress.cpp", "PeerAddress.h", "TCP.cpp", "TCP.h", diff --git a/src/transport/raw/PeerAddress.cpp b/src/transport/raw/PeerAddress.cpp new file mode 100644 index 00000000000000..1bfb3c9f703560 --- /dev/null +++ b/src/transport/raw/PeerAddress.cpp @@ -0,0 +1,124 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#include "PeerAddress.h" + +#include + +namespace chip { +namespace Transport { + +namespace { + +/// Formats IP addresses into a format suitable for PeerAddress::ToString +/// Specifically it will add the first IP address, interface used and port +/// and a marker if more than one IP address is contained in the input list +/// +/// Examples: +/// NONE:123 // when addresses are empty +/// 10.20.30.40:5040 // exactly one IP address in the destination list with null interface +/// 10.0.0.10%wlan0:123 (+3 more) // 4 input addresses in the list +/// %:port +void AddIpInfo(StringBuilderBase & dest, uint16_t port, Span destinations) +{ + if (destinations.empty()) + { + dest.Add(":NONE:"); + } + else + { + // First address information. + // + // In time, peer addresses should have an 'active address' to determine which IP is + // used to communicate with peers, in which case the output here should be the current + // active address rather than just the first in the list. + + dest.Add(":"); + auto first = destinations.begin(); + + { + char ip_addr[Inet::IPAddress::kMaxStringLength]; + first->ipAddress.ToString(ip_addr); + if (first->ipAddress.IsIPv6()) + { + dest.Add("["); + } + dest.Add(ip_addr); + } + + if (first->interface.IsPresent()) + { + dest.Add("%"); + + char interface[Inet::InterfaceId::kMaxIfNameLength] = {}; // +1 to prepend '%' + + if (first->interface.GetInterfaceName(interface, sizeof(interface)) != CHIP_NO_ERROR) + { + dest.Add("(err)"); + } + else + { + dest.Add(interface); + } + } + if (first->ipAddress.IsIPv6()) + { + dest.Add("]"); + } + dest.Add(":"); + } + dest.Add(port); + + if (destinations.size() > 1) + { + dest.Add(" (+"); + dest.Add(static_cast(destinations.size() - 1)); + dest.Add(" more)"); + } +} + +} // namespace + +void PeerAddress::ToString(char * buf, size_t bufSize) const +{ + StringBuilderBase out(buf, bufSize); + + switch (mTransportType) + { + case Type::kUndefined: + out.Add("UNDEFINED"); + break; + case Type::kUdp: + out.Add("UDP"); + AddIpInfo(out, mPort, Span(mDestinations, mNumValidDestinations)); + break; + case Type::kTcp: + out.Add("TCP"); + AddIpInfo(out, mPort, Span(mDestinations, mNumValidDestinations)); + break; + case Type::kBle: + // Note that BLE does not currently use any specific address. + out.Add("BLE"); + break; + default: + out.Add("ERROR"); + break; + } +} + +} // namespace Transport +} // namespace chip diff --git a/src/transport/raw/PeerAddress.h b/src/transport/raw/PeerAddress.h index 69318d027da747..c0338420dd755b 100644 --- a/src/transport/raw/PeerAddress.h +++ b/src/transport/raw/PeerAddress.h @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace chip { @@ -62,8 +63,35 @@ enum class Type : uint8_t class PeerAddress { public: - PeerAddress() : mIPAddress(Inet::IPAddress::Any), mTransportType(Type::kUndefined) {} - PeerAddress(const Inet::IPAddress & addr, Type type) : mIPAddress(addr), mTransportType(type) {} + /// Target destinations for Peer addresses + struct IPDestination + { + Inet::IPAddress ipAddress; + Inet::InterfaceId interface = Inet::InterfaceId::Null(); + + void Set(const Inet::IPAddress & ip, const Inet::InterfaceId & iface) + { + ipAddress = ip; + interface = iface; + } + + bool operator==(const IPDestination & other) const + { + return (ipAddress == other.ipAddress) && (interface == other.interface); + } + + bool operator!=(const IPDestination & other) const { return !(*this == other); } + }; + + // When using DNSSD, a peer may be discovered at multiple addresses. + // This controls how many addresses can be kept. + static constexpr unsigned kMaxPeerDestinations = 3; + + PeerAddress() : mTransportType(Type::kUndefined) {} + PeerAddress(const Inet::IPAddress & addr, Type type) : mTransportType(type) + { + AppendDestination(addr, Inet::InterfaceId::Null()); + } PeerAddress(Type type) : mTransportType(type) {} PeerAddress(PeerAddress &&) = default; @@ -71,11 +99,31 @@ class PeerAddress PeerAddress & operator=(const PeerAddress &) = default; PeerAddress & operator=(PeerAddress &&) = default; - const Inet::IPAddress & GetIPAddress() const { return mIPAddress; } - PeerAddress & SetIPAddress(const Inet::IPAddress & addr) + const Inet::IPAddress & GetIPAddress() const { - mIPAddress = addr; - return *this; + if (mNumValidDestinations > 0) + { + return mDestinations[0].ipAddress; + } + else + { + return Inet::IPAddress::Any; // not initialized really + } + } + + /// Add another IP address to the list of internal IP addresses that + /// are considred valid. + /// + /// Returns failure if insufficient memory available to append more + /// addresses + CHIP_ERROR AppendDestination(const Inet::IPAddress & addr, const Inet::InterfaceId & interface) + { + if (mNumValidDestinations >= kMaxPeerDestinations) + { + return CHIP_ERROR_NO_MEMORY; + } + mDestinations[mNumValidDestinations++].Set(addr, interface); + return CHIP_NO_ERROR; } Type GetTransportType() const { return mTransportType; } @@ -92,27 +140,75 @@ class PeerAddress return *this; } - Inet::InterfaceId GetInterface() const { return mInterface; } - PeerAddress & SetInterface(Inet::InterfaceId interface) + Inet::InterfaceId GetInterface() const { - mInterface = interface; + if (mNumValidDestinations > 0) + { + return mDestinations[0].interface; + } + else + { + return Inet::InterfaceId::Null(); + } + } + + /// DEPRECATED: Setting this has several drawbacks: + /// - Interface is not set and LL ip addresses will not work without a + /// set interface + /// - Nodes are generally expected to support multiple IP addresses when + /// discovered using DNSSD. + PeerAddress & SetSingleIPAddress(const Inet::IPAddress & addr) + { + // NOTE: mDestinations[0].interface is NOT changed in any way + mDestinations[0].ipAddress = addr; + mNumValidDestinations = 1; return *this; } bool IsInitialized() const { return mTransportType != Type::kUndefined; } - bool IsMulticast() { return Type::kUdp == mTransportType && mIPAddress.IsIPv6Multicast(); } + bool IsMulticast() + { + if (Type::kUdp != mTransportType) + { + return false; + } + + if (mNumValidDestinations == 0) + { + return false; + } + + // Assumption here is that if any IP address is multicast, the entire object should + // be multicast + return mDestinations[0].ipAddress.IsIPv6Multicast(); + } bool operator==(const PeerAddress & other) const { - return (mTransportType == other.mTransportType) && (mIPAddress == other.mIPAddress) && (mPort == other.mPort) && - (mInterface == other.mInterface); + if ((mTransportType != other.mTransportType) || (mPort != other.mPort) || + mNumValidDestinations != other.mNumValidDestinations) + { + return false; + } + + // NOTE: we do NOT try to order/treat as a set all destinations here. + // Check that the valid destinations are identical only, including order. + for (unsigned i = 0; i < mNumValidDestinations; i++) + { + if (mDestinations[i] != other.mDestinations[i]) + { + return false; + } + } + + return true; } bool operator!=(const PeerAddress & other) const { return !(*this == other); } /// Maximum size of the string outputes by ToString. Format is of the form: - /// "UDP::" + /// "UDP:: (+N more)" static constexpr size_t kMaxToStringSize = 3 // type: UDP/TCP/BLE + 1 // splitter : + 2 // brackets around address @@ -121,79 +217,41 @@ class PeerAddress + Inet::InterfaceId::kMaxIfNameLength // interface + 1 // splitter : + 5 // port: 16 bit interger + + 3 // " (+" + + 2 // integer for "more", low digits expected + + 6 // " more)" + 1; // NullTerminator + static_assert(kMaxPeerDestinations < 100, "for maxStringSize to be correct for the 'more' part"); + template 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; - } - } + void ToString(char * buf, size_t bufSize) const; /****** Factory methods for convenience ******/ - static PeerAddress Uninitialized() { return PeerAddress(Inet::IPAddress::Any, Type::kUndefined); } + static PeerAddress Uninitialized() { return PeerAddress(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); } - static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface) + + static PeerAddress UDP(const Inet::IPAddress & addr, uint16_t port = CHIP_PORT, + Inet::InterfaceId interface = Inet::InterfaceId::Null()) { - return UDP(addr).SetPort(port).SetInterface(interface); + PeerAddress result = PeerAddress(Type::kUdp); + result.SetPort(port).AppendDestination(addr, interface); + return result; } - 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); } - static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId interface) + + static PeerAddress TCP(const Inet::IPAddress & addr, uint16_t port = CHIP_PORT, + Inet::InterfaceId interface = Inet::InterfaceId::Null()) { - return TCP(addr).SetPort(port).SetInterface(interface); + PeerAddress result = PeerAddress(Type::kTcp); + result.SetPort(port).AppendDestination(addr, interface); + return result; } static PeerAddress Multicast(chip::FabricId fabric, chip::GroupId group) @@ -209,14 +267,15 @@ class PeerAddress // * 0x00 // * The 16-bits Group Identifier in big-endian order uint32_t groupId = static_cast((fabric << 24) & 0xff000000) | group; + return UDP(Inet::IPAddress::MakeIPv6PrefixMulticast(scope, prefixLength, prefix, groupId)); } private: - Inet::IPAddress mIPAddress = {}; - Type mTransportType = Type::kUndefined; - uint16_t mPort = CHIP_PORT; ///< Relevant for UDP data sending. - Inet::InterfaceId mInterface = Inet::InterfaceId::Null(); + IPDestination mDestinations[kMaxPeerDestinations] = {}; + unsigned mNumValidDestinations = 0; + Type mTransportType = Type::kUndefined; + uint16_t mPort = CHIP_PORT; ///< Relevant for UDP data sending. }; } // namespace Transport diff --git a/src/transport/raw/tests/TestPeerAddress.cpp b/src/transport/raw/tests/TestPeerAddress.cpp index b6d67e8342b7b0..3ac323120b10d4 100644 --- a/src/transport/raw/tests/TestPeerAddress.cpp +++ b/src/transport/raw/tests/TestPeerAddress.cpp @@ -37,16 +37,21 @@ #include +namespace { + using namespace chip; +using chip::Inet::InterfaceId; +using chip::Inet::IPAddress; +using chip::Transport::PeerAddress; /** * Test correct identification of IPv6 multicast addresses. */ void TestPeerAddressMulticast(nlTestSuite * inSuite, void * inContext) { - constexpr chip::FabricId fabric = 0xa1a2a4a8b1b2b4b8; - constexpr chip::GroupId group = 0xe10f; - chip::Transport::PeerAddress addr = chip::Transport::PeerAddress::Multicast(fabric, group); + constexpr chip::FabricId fabric = 0xa1a2a4a8b1b2b4b8; + constexpr chip::GroupId group = 0xe10f; + PeerAddress addr = PeerAddress::Multicast(fabric, group); NL_TEST_ASSERT(inSuite, chip::Transport::Type::kUdp == addr.GetTransportType()); NL_TEST_ASSERT(inSuite, addr.IsMulticast()); @@ -62,18 +67,91 @@ void TestPeerAddressMulticast(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, !memcmp(expected, result, NL_INET_IPV6_ADDR_LEN_IN_BYTES)); } +void TestToString(nlTestSuite * inSuite, void * inContext) +{ + char buff[PeerAddress::kMaxToStringSize]; + IPAddress ip; + { + IPAddress::FromString("::1", ip); + PeerAddress::UDP(ip, 1122).ToString(buff); + + NL_TEST_ASSERT(inSuite, !strcmp(buff, "UDP:[::1]:1122")); + } + + { + IPAddress::FromString("::1", ip); + PeerAddress::TCP(ip, 1122).ToString(buff); + + NL_TEST_ASSERT(inSuite, !strcmp(buff, "TCP:[::1]:1122")); + } + + { + PeerAddress::BLE().ToString(buff); + NL_TEST_ASSERT(inSuite, !strcmp(buff, "BLE")); + } + + { + IPAddress::FromString("1223::3456:789a", ip); + PeerAddress::UDP(ip, 8080).ToString(buff); + + NL_TEST_ASSERT(inSuite, !strcmp(buff, "UDP:[1223::3456:789a]:8080")); + } + + { + + PeerAddress udp = PeerAddress(Transport::Type::kUdp); + udp.SetPort(5840); + + IPAddress::FromString("::1", ip); + udp.AppendDestination(ip, InterfaceId::Null()); + IPAddress::FromString("1223::3456:789a", ip); + udp.AppendDestination(ip, InterfaceId::Null()); + + udp.ToString(buff); + NL_TEST_ASSERT(inSuite, !strcmp(buff, "UDP:[::1]:5840 (+1 more)")); + } + + { + + PeerAddress udp = PeerAddress(Transport::Type::kUdp); + udp.SetPort(5840); + udp.ToString(buff); + NL_TEST_ASSERT(inSuite, !strcmp(buff, "UDP:NONE:5840")); + } +} + +void TestAppendDestinationLimit(nlTestSuite * inSuite, void * inContext) +{ + IPAddress ip; + IPAddress::FromString("::1", ip); + + PeerAddress udp = PeerAddress(Transport::Type::kUdp); + udp.SetPort(123); + + for (unsigned i = 0; i < PeerAddress::kMaxPeerDestinations; i++) + { + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR == udp.AppendDestination(ip, InterfaceId::Null())); + } + + NL_TEST_ASSERT(inSuite, CHIP_NO_ERROR != udp.AppendDestination(ip, InterfaceId::Null())); +} + /** * Test Suite. It lists all the test functions. */ // clang-format off -static const nlTest sTests[] = +const nlTest sTests[] = { NL_TEST_DEF("PeerAddress Multicast", TestPeerAddressMulticast), + NL_TEST_DEF("ToString", TestToString), + NL_TEST_DEF("AppendDestination", TestAppendDestinationLimit), NL_TEST_SENTINEL() }; // clang-format on +} // namespace + int TestPeerAddress(void) { // clang-format off