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

Weave over UDP changes #393

Merged
merged 8 commits into from
Nov 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build/config/standalone/WeaveProjectConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#ifndef WEAVEPROJECTCONFIG_H
#define WEAVEPROJECTCONFIG_H


#define WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT 1

// Configure WDM for event offload
#define WEAVE_CONFIG_EVENT_LOGGING_WDM_OFFLOAD 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@

// ==================== General Platform Adaptations ====================

#define WEAVE_CONFIG_MAX_INTERFACES 4
#define WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS 4
#define WEAVE_CONFIG_MAX_TUNNELS 0
#define WEAVE_CONFIG_ENABLE_TUNNELING 1
#define WEAVE_CONFIG_PERSISTED_STORAGE_ENC_MSG_CNTR_ID "enc-msg-counter"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,6 @@
#define WEAVE_LOG_FILTERING 0
#endif // WEAVE_LOG_FILTERING

#ifndef WEAVE_CONFIG_MAX_INTERFACES
#define WEAVE_CONFIG_MAX_INTERFACES 4
#endif // WEAVE_CONFIG_MAX_INTERFACES

#ifndef WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS
#define WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS 4
#endif // WEAVE_CONFIG_MAX_LOCAL_ADDR_UDP_ENDPOINTS

#ifndef WEAVE_CONFIG_BDX_MAX_NUM_TRANSFERS
#define WEAVE_CONFIG_BDX_MAX_NUM_TRANSFERS 1
#endif // WEAVE_CONFIG_BDX_MAX_NUM_TRANSFERS
Expand Down
56 changes: 26 additions & 30 deletions src/device-manager/WeaveDeviceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,25 +422,23 @@ WEAVE_ERROR WeaveDeviceManager::InitiateDeviceEnumeration()

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

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

mConState = kConnectionState_IdentifyDevice;

// Send the Identify message.
// Send an Identify message over UDP to the specified rendezvous address. Typically the rendezvous address
// will be a multicast/broadcast address, however this can be changed by the application.
//
// If performing a multicast identify, AND the 'rendezvous link-local' option is enabled,
// AND the message layer is not bound to a specific local IPv6 address, THEN ...
// If the rendezvous address is an IPv6 multicast address and the local node is a member of a Weave fabric,
// then the source address of the Identify message will be one of the node's Weave addresses.
//
// Send the multicast identify request from the host's link-local addresses, rather than
// from its site-local or global addresses. This results in the device responding using its
// link-local address, which in turn causes the device manager to connect to the device using the
// link-local address. This is all to work around a bug in OS X/iOS that prevents those systems
// from communicating on any site-local IPv6 subnets when in the presence of a router that is
// advertising a default route to the Internet at large. (See DOLO-2479).
// However, if the application has enabled the 'rendezvous link-local' option, force the use of default
// source address selection by passing the DefaultMulticastSourceAddress flag to SendMessage(). For typical
// multicast rendezvous addresses (e.g. FF02::1 all-nodes, link-local), this will result in the source address
// of the Identify message being the local node's link-local address.
//
// We disable the 'rendezvous link-local' feature when the message layer is bound to a specific
// address because binding to a specific address is generally used when testing the device manager
// and a mock-device running on a single host with a single interface. In this case multicasting
// using the interface's single link-local address doesn't work.
// Note that the Weave Message Layer will *always* perform default source address selection if the local
// node is not a member of a Weave fabric (which is true for most uses of the WeaveDeviceManager class).
// Thus the state of the 'rendezvous link-local' option is moot in those contexts.
//
sendFlags = (mDeviceAddr.IsMulticast() && mRendezvousLinkLocal && !mMessageLayer->IsBoundToLocalIPv6Address())
? ExchangeContext::kSendFlag_MulticastFromLinkLocal
sendFlags = (mRendezvousLinkLocal)
? ExchangeContext::kSendFlag_DefaultMulticastSourceAddress
: 0;
err = mCurReq->SendMessage(kWeaveProfile_DeviceDescription, kMessageType_IdentifyRequest, msgBuf, sendFlags);
msgBuf = NULL;
Expand Down
16 changes: 16 additions & 0 deletions src/inet/IPAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,11 @@ bool IPAddress::IsMulticast(void) const
return (IsIPv6Multicast() || IsIPv4Multicast());
}

bool IPAddress::IsIPv6(void) const
{
return *this != Any && !IsIPv4();
}

// Is address an IPv6 multicast address?
bool IPAddress::IsIPv6Multicast(void) const
{
Expand Down Expand Up @@ -460,5 +465,16 @@ IPAddress IPAddress::MakeIPv6PrefixMulticast(uint8_t aScope, uint8_t aPrefixLeng
return (MakeIPv6TransientMulticast(lFlags, aScope, lGroupId));
}

IPAddress IPAddress::MakeIPv4Broadcast(void)
{
IPAddress ipAddr;
ipAddr.Addr[0] = 0;
ipAddr.Addr[1] = 0;
ipAddr.Addr[2] = htonl(0xFFFF);
ipAddr.Addr[3] = 0xFFFFFFFF;
return ipAddr;
}


} // namespace Inet
} // namespace nl
19 changes: 19 additions & 0 deletions src/inet/IPAddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ class NL_DLL_EXPORT IPAddress
*/
uint32_t Addr[4];

/**
* @brief Test whether address is IPv6 compatible.
*
* @details
* Use this method to check if the address belongs to the IPv6 address
* family. Note well: the unspecified address is not an IPv6 address.
*
* @retval true The address is IPv6 and not the unspecified address.
* @retval false The address is IPv4 or the unspecified address.
*/
bool IsIPv6(void) const;

/**
* @brief Test whether address is IPv6 global unicast address.
*
Expand Down Expand Up @@ -632,6 +644,13 @@ class NL_DLL_EXPORT IPAddress
*/
static IPAddress MakeIPv6PrefixMulticast(uint8_t aScope, uint8_t aPrefixLength, const uint64_t &aPrefix, uint32_t aGroupId);

/**
* @brief Construct an IPv4 broadcast address.
*
* @return The constructed IP address.
*/
static IPAddress MakeIPv4Broadcast(void);

/**
* @brief The distinguished unspecified IP address object.
*
Expand Down
26 changes: 15 additions & 11 deletions src/inet/IPEndPointBasis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int
res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, (void*)&one, sizeof (one));
if (res != 0)
{
WeaveLogError(Inet, "SO_REUSEPORT: %d", errno);
WeaveLogError(Inet, "SO_REUSEPORT failed: %d", errno);
}
#endif // defined(SO_REUSEPORT)

Expand All @@ -940,33 +940,37 @@ INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int
// the same port, one for IPv4 and one for IPv6.

#ifdef IPV6_V6ONLY
#if INET_CONFIG_ENABLE_IPV4
if (aAddressType == kIPAddressType_IPv6)
#endif // INET_CONFIG_ENABLE_IPV4
{
res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &one, sizeof (one));
if (res != 0)
{
WeaveLogError(Inet, "IPV6_V6ONLY: %d", errno);
WeaveLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
}
}
#endif // defined(IPV6_V6ONLY)

#if INET_CONFIG_ENABLE_IPV4
#ifdef IP_PKTINFO
res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, (void *) &one, sizeof (one));
if (res != 0)
if (aAddressType == kIPAddressType_IPv4)
{
WeaveLogError(Inet, "IP_PKTINFO: %d", errno);
res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, (void *) &one, sizeof (one));
if (res != 0)
{
WeaveLogError(Inet, "IP_PKTINFO failed: %d", errno);
}
}
#endif // defined(IP_PKTINFO)
#endif // INET_CONFIG_ENABLE_IPV4

#ifdef IPV6_RECVPKTINFO
res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &one, sizeof (one));
if (res != 0)
if (aAddressType == kIPAddressType_IPv6)
{
WeaveLogError(Inet, "IPV6_PKTINFO: %d", errno);
res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &one, sizeof (one));
if (res != 0)
{
WeaveLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
}
}
#endif // defined(IPV6_RECVPKTINFO)

Expand All @@ -979,7 +983,7 @@ INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int
res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof (one));
if (res != 0)
{
WeaveLogError(Inet, "SO_NOSIGPIPE: %d", errno);
WeaveLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
}
}
#endif // defined(SO_NOSIGPIPE)
Expand Down
35 changes: 35 additions & 0 deletions src/inet/UDPEndPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,30 @@ INET_ERROR UDPEndPoint::Bind(IPAddressType addrType, IPAddress addr, uint16_t po
mBoundPort = port;
mBoundIntfId = intfId;

// If an ephemeral port was requested, retrieve the actual bound port.
if (port == 0)
{
union
{
struct sockaddr any;
struct sockaddr_in in;
struct sockaddr_in6 in6;
} boundAddr;
socklen_t boundAddrLen = sizeof(boundAddr);

if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
{
if (boundAddr.any.sa_family == AF_INET)
{
mBoundPort = ntohs(boundAddr.in.sin_port);
}
else if (boundAddr.any.sa_family == AF_INET6)
{
mBoundPort = ntohs(boundAddr.in6.sin6_port);
}
}
}

#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS

if (res == INET_NO_ERROR)
Expand Down Expand Up @@ -734,6 +758,17 @@ InterfaceId UDPEndPoint::GetBoundInterface(void)
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}

uint16_t UDPEndPoint::GetBoundPort(void)
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
return mUDP->local_port;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP

#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
return mBoundPort;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}

#if WEAVE_SYSTEM_CONFIG_USE_LWIP

void UDPEndPoint::HandleDataReceived(PacketBuffer *msg)
Expand Down
1 change: 1 addition & 0 deletions src/inet/UDPEndPoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class IPPacketInfo;
INET_ERROR Bind(IPAddressType addrType, IPAddress addr, uint16_t port, InterfaceId intfId = INET_NULL_INTERFACEID);
INET_ERROR BindInterface(IPAddressType addrType, InterfaceId intf);
InterfaceId GetBoundInterface(void);
uint16_t GetBoundPort(void);
INET_ERROR Listen(void);
INET_ERROR SendTo(IPAddress addr, uint16_t port, Weave::System::PacketBuffer *msg, uint16_t sendFlags = 0);
INET_ERROR SendTo(IPAddress addr, uint16_t port, InterfaceId intfId, Weave::System::PacketBuffer *msg, uint16_t sendFlags = 0);
Expand Down
42 changes: 39 additions & 3 deletions src/lib/core/ExchangeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ enum {
kFlagMsgRcvdFromPeer = 0x0080, /// When set, signifies that at least one message has been received from peer on this exchange context.
kFlagAutoReleaseKey = 0x0100, /// Automatically release the message encryption key when the exchange context is freed.
kFlagAutoReleaseConnection = 0x0200, /// Automatically release the associated WeaveConnection when the exchange context is freed.
kFlagUseEphemeralUDPPort = 0x0400, /// When set, use the local ephemeral UDP port as the source port for outbound messages.
};

/**
Expand Down Expand Up @@ -313,6 +314,35 @@ void ExchangeContext::SetShouldAutoReleaseConnection(bool autoReleaseCon)
SetFlag(mFlags, static_cast<uint16_t>(kFlagAutoReleaseConnection), autoReleaseCon);
}

/**
* @fn bool ExchangeContext::UseEphemeralUDPPort(void) const
*
* Return whether outbound messages sent via the exchange should be sent from
* the local ephemeral UDP port.
*/

#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT

bool ExchangeContext::UseEphemeralUDPPort(void) const
{
return GetFlag(mFlags, static_cast<uint16_t>(kFlagUseEphemeralUDPPort));
}

#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT

#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT

/**
* Set whether outbound messages sent via the exchange should be sent from
* the local ephemeral UDP port.
*/
void ExchangeContext::SetUseEphemeralUDPPort(bool val)
{
SetFlag(mFlags, static_cast<uint16_t>(kFlagUseEphemeralUDPPort), val);
}

#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT

/**
* Send a Weave message on this exchange.
*
Expand Down Expand Up @@ -524,10 +554,16 @@ WEAVE_ERROR ExchangeContext::SendMessage(uint32_t profileId, uint8_t msgType, Pa
msgInfo->Flags |= kWeaveMessageFlag_ReuseMessageId;
if (sendFlags & kSendFlag_ReuseSourceId)
msgInfo->Flags |= kWeaveMessageFlag_ReuseSourceId;
if (sendFlags & kSendFlag_MulticastFromLinkLocal)
msgInfo->Flags |= kWeaveMessageFlag_MulticastFromLinkLocal;
if (sendFlags & kSendFlag_DefaultMulticastSourceAddress)
msgInfo->Flags |= kWeaveMessageFlag_DefaultMulticastSourceAddress;

SetFlag(msgInfo->Flags, kWeaveMessageFlag_FromInitiator, IsInitiator());

#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
SetFlag(msgInfo->Flags, kWeaveMessageFlag_ViaEphemeralUDPPort, UseEphemeralUDPPort());
#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT

// Send the message via UDP or TCP based on the presence of a connection.
// Send the message via UDP or TCP/BLE based on the presence of a connection.
if (Con != NULL)
{
// Hook the message received callback on the connection so that the WeaveExchangeManager gets
Expand Down
Loading