Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit 9238c86

Browse files
author
Jay Logue
authored
Merge pull request #393 from openweave/feature/udp-rework
Weave over UDP changes
2 parents e8ad459 + 54baa9b commit 9238c86

25 files changed

+1623
-677
lines changed

Diff for: build/config/standalone/WeaveProjectConfig.h

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#ifndef WEAVEPROJECTCONFIG_H
2525
#define WEAVEPROJECTCONFIG_H
2626

27+
28+
#define WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT 1
29+
2730
// Configure WDM for event offload
2831
#define WEAVE_CONFIG_EVENT_LOGGING_WDM_OFFLOAD 1
2932

Diff for: src/adaptations/device-layer/include/Weave/DeviceLayer/ESP32/WeavePlatformConfig.h

-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929

3030
// ==================== General Platform Adaptations ====================
3131

32-
#define WEAVE_CONFIG_MAX_INTERFACES 4
33-
#define WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS 4
3432
#define WEAVE_CONFIG_MAX_TUNNELS 0
3533
#define WEAVE_CONFIG_ENABLE_TUNNELING 1
3634
#define WEAVE_CONFIG_PERSISTED_STORAGE_ENC_MSG_CNTR_ID "enc-msg-counter"

Diff for: src/adaptations/device-layer/include/Weave/DeviceLayer/nRF5/WeavePlatformConfig.h

-8
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,6 @@
108108
#define WEAVE_LOG_FILTERING 0
109109
#endif // WEAVE_LOG_FILTERING
110110

111-
#ifndef WEAVE_CONFIG_MAX_INTERFACES
112-
#define WEAVE_CONFIG_MAX_INTERFACES 4
113-
#endif // WEAVE_CONFIG_MAX_INTERFACES
114-
115-
#ifndef WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS
116-
#define WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS 4
117-
#endif // WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS
118-
119111
#ifndef WEAVE_CONFIG_BDX_MAX_NUM_TRANSFERS
120112
#define WEAVE_CONFIG_BDX_MAX_NUM_TRANSFERS 1
121113
#endif // WEAVE_CONFIG_BDX_MAX_NUM_TRANSFERS

Diff for: src/device-manager/WeaveDeviceManager.cpp

+26-30
Original file line numberDiff line numberDiff line change
@@ -422,25 +422,23 @@ WEAVE_ERROR WeaveDeviceManager::InitiateDeviceEnumeration()
422422

423423
WeaveLogProgress(DeviceManager, "Sending IdentifyRequest to enumerate devices");
424424

425-
// Send the Identify message.
425+
// Send an Identify message over UDP to the specified rendezvous address. Typically the rendezvous address
426+
// will be an multicast/broadcast address, however this can be changed by the application.
426427
//
427-
// If the 'enumerate-devices link-local' option is enabled, AND the message layer is not bound to
428-
// a specific local IPv6 address, THEN ...
428+
// If the rendezvous address is an IPv6 multicast address and the local node is a member of a Weave fabric,
429+
// then the source address of the Identify message will be one of the node's Weave addresses.
429430
//
430-
// Send the multicast identify request from the host's link-local addresses, rather than
431-
// from its site-local or global addresses. This results in the device responding using its
432-
// link-local address, which in turn causes the device manager to connect to the device using the
433-
// link-local address. This is all to work around a bug in OS X/iOS that prevents those systems
434-
// from communicating on any site-local IPv6 subnets when in the presence of a router that is
435-
// advertising a default route to the Internet at large. (See DOLO-2479).
431+
// However, if the application has enabled the 'rendezvous link-local' option, force the use of default
432+
// source address selection by passing the DefaultMulticastSourceAddress flag to SendMessage(). For typical
433+
// multicast rendezvous addresses (e.g. FF02::1 all-nodes, link-local), this will result in the source address
434+
// of the Identify message being the local node's link-local address.
436435
//
437-
// We disable the 'enumerate-devices link-local' feature when the message layer is bound to a specific
438-
// address because binding to a specific address is generally used when testing the device manager
439-
// and a mock-device running on a single host with a single interface. In this case multicasting
440-
// using the interface's single link-local address doesn't work.
436+
// Note that the Weave Message Layer will *always* perform default source address selection if the local
437+
// node is not a member of a Weave fabric (which is true for most uses of the WeaveDeviceManager class).
438+
// Thus the state of the 'rendezvous link-local' option is moot in those contexts.
441439
//
442-
sendFlags = (mRendezvousLinkLocal && !mMessageLayer->IsBoundToLocalIPv6Address())
443-
? ExchangeContext::kSendFlag_MulticastFromLinkLocal
440+
sendFlags = (mRendezvousLinkLocal)
441+
? ExchangeContext::kSendFlag_DefaultMulticastSourceAddress
444442
: 0;
445443
err = mCurReq->SendMessage(kWeaveProfile_DeviceDescription, kMessageType_IdentifyRequest, msgBuf, sendFlags);
446444
msgBuf = NULL;
@@ -2751,25 +2749,23 @@ WEAVE_ERROR WeaveDeviceManager::InitiateConnection()
27512749

27522750
mConState = kConnectionState_IdentifyDevice;
27532751

2754-
// Send the Identify message.
2752+
// Send an Identify message over UDP to the specified rendezvous address. Typically the rendezvous address
2753+
// will be a multicast/broadcast address, however this can be changed by the application.
27552754
//
2756-
// If performing a multicast identify, AND the 'rendezvous link-local' option is enabled,
2757-
// AND the message layer is not bound to a specific local IPv6 address, THEN ...
2755+
// If the rendezvous address is an IPv6 multicast address and the local node is a member of a Weave fabric,
2756+
// then the source address of the Identify message will be one of the node's Weave addresses.
27582757
//
2759-
// Send the multicast identify request from the host's link-local addresses, rather than
2760-
// from its site-local or global addresses. This results in the device responding using its
2761-
// link-local address, which in turn causes the device manager to connect to the device using the
2762-
// link-local address. This is all to work around a bug in OS X/iOS that prevents those systems
2763-
// from communicating on any site-local IPv6 subnets when in the presence of a router that is
2764-
// advertising a default route to the Internet at large. (See DOLO-2479).
2758+
// However, if the application has enabled the 'rendezvous link-local' option, force the use of default
2759+
// source address selection by passing the DefaultMulticastSourceAddress flag to SendMessage(). For typical
2760+
// multicast rendezvous addresses (e.g. FF02::1 all-nodes, link-local), this will result in the source address
2761+
// of the Identify message being the local node's link-local address.
27652762
//
2766-
// We disable the 'rendezvous link-local' feature when the message layer is bound to a specific
2767-
// address because binding to a specific address is generally used when testing the device manager
2768-
// and a mock-device running on a single host with a single interface. In this case multicasting
2769-
// using the interface's single link-local address doesn't work.
2763+
// Note that the Weave Message Layer will *always* perform default source address selection if the local
2764+
// node is not a member of a Weave fabric (which is true for most uses of the WeaveDeviceManager class).
2765+
// Thus the state of the 'rendezvous link-local' option is moot in those contexts.
27702766
//
2771-
sendFlags = (mDeviceAddr.IsMulticast() && mRendezvousLinkLocal && !mMessageLayer->IsBoundToLocalIPv6Address())
2772-
? ExchangeContext::kSendFlag_MulticastFromLinkLocal
2767+
sendFlags = (mRendezvousLinkLocal)
2768+
? ExchangeContext::kSendFlag_DefaultMulticastSourceAddress
27732769
: 0;
27742770
err = mCurReq->SendMessage(kWeaveProfile_DeviceDescription, kMessageType_IdentifyRequest, msgBuf, sendFlags);
27752771
msgBuf = NULL;

Diff for: src/inet/IPAddress.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ bool IPAddress::IsMulticast(void) const
263263
return (IsIPv6Multicast() || IsIPv4Multicast());
264264
}
265265

266+
bool IPAddress::IsIPv6(void) const
267+
{
268+
return *this != Any && !IsIPv4();
269+
}
270+
266271
// Is address an IPv6 multicast address?
267272
bool IPAddress::IsIPv6Multicast(void) const
268273
{
@@ -460,5 +465,16 @@ IPAddress IPAddress::MakeIPv6PrefixMulticast(uint8_t aScope, uint8_t aPrefixLeng
460465
return (MakeIPv6TransientMulticast(lFlags, aScope, lGroupId));
461466
}
462467

468+
IPAddress IPAddress::MakeIPv4Broadcast(void)
469+
{
470+
IPAddress ipAddr;
471+
ipAddr.Addr[0] = 0;
472+
ipAddr.Addr[1] = 0;
473+
ipAddr.Addr[2] = htonl(0xFFFF);
474+
ipAddr.Addr[3] = 0xFFFFFFFF;
475+
return ipAddr;
476+
}
477+
478+
463479
} // namespace Inet
464480
} // namespace nl

Diff for: src/inet/IPAddress.h

+19
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,18 @@ class NL_DLL_EXPORT IPAddress
139139
*/
140140
uint32_t Addr[4];
141141

142+
/**
143+
* @brief Test whether address is IPv6 compatible.
144+
*
145+
* @details
146+
* Use this method to check if the address belongs to the IPv6 address
147+
* family. Note well: the unspecified address is not an IPv6 address.
148+
*
149+
* @retval true The address is IPv6 and not the unspecified address.
150+
* @retval false The address is IPv4 or the unspecified address.
151+
*/
152+
bool IsIPv6(void) const;
153+
142154
/**
143155
* @brief Test whether address is IPv6 global unicast address.
144156
*
@@ -632,6 +644,13 @@ class NL_DLL_EXPORT IPAddress
632644
*/
633645
static IPAddress MakeIPv6PrefixMulticast(uint8_t aScope, uint8_t aPrefixLength, const uint64_t &aPrefix, uint32_t aGroupId);
634646

647+
/**
648+
* @brief Construct an IPv4 broadcast address.
649+
*
650+
* @return The constructed IP address.
651+
*/
652+
static IPAddress MakeIPv4Broadcast(void);
653+
635654
/**
636655
* @brief The distinguished unspecified IP address object.
637656
*

Diff for: src/inet/IPEndPointBasis.cpp

+15-11
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int
931931
res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, (void*)&one, sizeof (one));
932932
if (res != 0)
933933
{
934-
WeaveLogError(Inet, "SO_REUSEPORT: %d", errno);
934+
WeaveLogError(Inet, "SO_REUSEPORT failed: %d", errno);
935935
}
936936
#endif // defined(SO_REUSEPORT)
937937
@@ -940,33 +940,37 @@ INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int
940940
// the same port, one for IPv4 and one for IPv6.
941941
942942
#ifdef IPV6_V6ONLY
943-
#if INET_CONFIG_ENABLE_IPV4
944943
if (aAddressType == kIPAddressType_IPv6)
945-
#endif // INET_CONFIG_ENABLE_IPV4
946944
{
947945
res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &one, sizeof (one));
948946
if (res != 0)
949947
{
950-
WeaveLogError(Inet, "IPV6_V6ONLY: %d", errno);
948+
WeaveLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
951949
}
952950
}
953951
#endif // defined(IPV6_V6ONLY)
954952
955953
#if INET_CONFIG_ENABLE_IPV4
956954
#ifdef IP_PKTINFO
957-
res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, (void *) &one, sizeof (one));
958-
if (res != 0)
955+
if (aAddressType == kIPAddressType_IPv4)
959956
{
960-
WeaveLogError(Inet, "IP_PKTINFO: %d", errno);
957+
res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, (void *) &one, sizeof (one));
958+
if (res != 0)
959+
{
960+
WeaveLogError(Inet, "IP_PKTINFO failed: %d", errno);
961+
}
961962
}
962963
#endif // defined(IP_PKTINFO)
963964
#endif // INET_CONFIG_ENABLE_IPV4
964965
965966
#ifdef IPV6_RECVPKTINFO
966-
res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &one, sizeof (one));
967-
if (res != 0)
967+
if (aAddressType == kIPAddressType_IPv6)
968968
{
969-
WeaveLogError(Inet, "IPV6_PKTINFO: %d", errno);
969+
res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &one, sizeof (one));
970+
if (res != 0)
971+
{
972+
WeaveLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
973+
}
970974
}
971975
#endif // defined(IPV6_RECVPKTINFO)
972976
@@ -979,7 +983,7 @@ INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int
979983
res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof (one));
980984
if (res != 0)
981985
{
982-
WeaveLogError(Inet, "SO_NOSIGPIPE: %d", errno);
986+
WeaveLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
983987
}
984988
}
985989
#endif // defined(SO_NOSIGPIPE)

Diff for: src/inet/UDPEndPoint.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,30 @@ INET_ERROR UDPEndPoint::Bind(IPAddressType addrType, IPAddress addr, uint16_t po
223223
mBoundPort = port;
224224
mBoundIntfId = intfId;
225225

226+
// If an ephemeral port was requested, retrieve the actual bound port.
227+
if (port == 0)
228+
{
229+
union
230+
{
231+
struct sockaddr any;
232+
struct sockaddr_in in;
233+
struct sockaddr_in6 in6;
234+
} boundAddr;
235+
socklen_t boundAddrLen = sizeof(boundAddr);
236+
237+
if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
238+
{
239+
if (boundAddr.any.sa_family == AF_INET)
240+
{
241+
mBoundPort = ntohs(boundAddr.in.sin_port);
242+
}
243+
else if (boundAddr.any.sa_family == AF_INET6)
244+
{
245+
mBoundPort = ntohs(boundAddr.in6.sin6_port);
246+
}
247+
}
248+
}
249+
226250
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
227251

228252
if (res == INET_NO_ERROR)
@@ -734,6 +758,17 @@ InterfaceId UDPEndPoint::GetBoundInterface(void)
734758
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
735759
}
736760

761+
uint16_t UDPEndPoint::GetBoundPort(void)
762+
{
763+
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
764+
return mUDP->local_port;
765+
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
766+
767+
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
768+
return mBoundPort;
769+
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
770+
}
771+
737772
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
738773

739774
void UDPEndPoint::HandleDataReceived(PacketBuffer *msg)

Diff for: src/inet/UDPEndPoint.h

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class IPPacketInfo;
5656
INET_ERROR Bind(IPAddressType addrType, IPAddress addr, uint16_t port, InterfaceId intfId = INET_NULL_INTERFACEID);
5757
INET_ERROR BindInterface(IPAddressType addrType, InterfaceId intf);
5858
InterfaceId GetBoundInterface(void);
59+
uint16_t GetBoundPort(void);
5960
INET_ERROR Listen(void);
6061
INET_ERROR SendTo(IPAddress addr, uint16_t port, Weave::System::PacketBuffer *msg, uint16_t sendFlags = 0);
6162
INET_ERROR SendTo(IPAddress addr, uint16_t port, InterfaceId intfId, Weave::System::PacketBuffer *msg, uint16_t sendFlags = 0);

Diff for: src/lib/core/ExchangeContext.cpp

+39-3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ enum {
6565
kFlagMsgRcvdFromPeer = 0x0080, /// When set, signifies that at least one message has been received from peer on this exchange context.
6666
kFlagAutoReleaseKey = 0x0100, /// Automatically release the message encryption key when the exchange context is freed.
6767
kFlagAutoReleaseConnection = 0x0200, /// Automatically release the associated WeaveConnection when the exchange context is freed.
68+
kFlagUseEphemeralUDPPort = 0x0400, /// When set, use the local ephemeral UDP port as the source port for outbound messages.
6869
};
6970

7071
/**
@@ -313,6 +314,35 @@ void ExchangeContext::SetShouldAutoReleaseConnection(bool autoReleaseCon)
313314
SetFlag(mFlags, static_cast<uint16_t>(kFlagAutoReleaseConnection), autoReleaseCon);
314315
}
315316

317+
/**
318+
* @fn bool ExchangeContext::UseEphemeralUDPPort(void) const
319+
*
320+
* Return whether outbound messages sent via the exchange should be sent from
321+
* the local ephemeral UDP port.
322+
*/
323+
324+
#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
325+
326+
bool ExchangeContext::UseEphemeralUDPPort(void) const
327+
{
328+
return GetFlag(mFlags, static_cast<uint16_t>(kFlagUseEphemeralUDPPort));
329+
}
330+
331+
#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
332+
333+
#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
334+
335+
/**
336+
* Set whether outbound messages sent via the exchange should be sent from
337+
* the local ephemeral UDP port.
338+
*/
339+
void ExchangeContext::SetUseEphemeralUDPPort(bool val)
340+
{
341+
SetFlag(mFlags, static_cast<uint16_t>(kFlagUseEphemeralUDPPort), val);
342+
}
343+
344+
#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
345+
316346
/**
317347
* Send a Weave message on this exchange.
318348
*
@@ -524,10 +554,16 @@ WEAVE_ERROR ExchangeContext::SendMessage(uint32_t profileId, uint8_t msgType, Pa
524554
msgInfo->Flags |= kWeaveMessageFlag_ReuseMessageId;
525555
if (sendFlags & kSendFlag_ReuseSourceId)
526556
msgInfo->Flags |= kWeaveMessageFlag_ReuseSourceId;
527-
if (sendFlags & kSendFlag_MulticastFromLinkLocal)
528-
msgInfo->Flags |= kWeaveMessageFlag_MulticastFromLinkLocal;
557+
if (sendFlags & kSendFlag_DefaultMulticastSourceAddress)
558+
msgInfo->Flags |= kWeaveMessageFlag_DefaultMulticastSourceAddress;
559+
560+
SetFlag(msgInfo->Flags, kWeaveMessageFlag_FromInitiator, IsInitiator());
561+
562+
#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
563+
SetFlag(msgInfo->Flags, kWeaveMessageFlag_ViaEphemeralUDPPort, UseEphemeralUDPPort());
564+
#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
529565

530-
// Send the message via UDP or TCP based on the presence of a connection.
566+
// Send the message via UDP or TCP/BLE based on the presence of a connection.
531567
if (Con != NULL)
532568
{
533569
// Hook the message received callback on the connection so that the WeaveExchangeManager gets

0 commit comments

Comments
 (0)