Skip to content
Open
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
6 changes: 5 additions & 1 deletion libcluon/include/cluon/OD4Session.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,12 @@ class LIBCLUON_API OD4Session {
* if a nullptr is passed, the method dataTrigger can be used to set
* message specific delegates. Please note that it is NOT possible
* to have both: a delegate for "catch-all" and the data-triggered ones.
* @param interfaceAssociatedAddress Optional numerical IPv4 address associated with an interface. If given, will be used to
* specify which interface to use when setting up the OD4 session.
*/
OD4Session(uint16_t CID, std::function<void(cluon::data::Envelope &&envelope)> delegate = nullptr) noexcept;
OD4Session(uint16_t CID,
std::function<void(cluon::data::Envelope &&envelope)> delegate = nullptr,
const std::string &interfaceAssociatedAddress = "") noexcept;

/**
* This method will send a given Envelope to this OpenDaVINCI v4 session.
Expand Down
5 changes: 4 additions & 1 deletion libcluon/include/cluon/UDPReceiver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,14 @@ class LIBCLUON_API UDPReceiver {
* @param receiveFromPort Port to receive UDP packets from.
* @param delegate Functional (noexcept) to handle received bytes; parameters are received data, sender, timestamp.
* @param localSendFromPort Port that an application is using to send data. This port (> 0) is ignored when data is received.
* @param interfaceAssociatedAddress Optional numerical IPv4 address associated with a interface. If given, will be used to
* specify which interface to use when joining a multicast group.
*/
UDPReceiver(const std::string &receiveFromAddress,
uint16_t receiveFromPort,
std::function<void(std::string &&, std::string &&, std::chrono::system_clock::time_point &&)> delegate,
uint16_t localSendFromPort = 0) noexcept;
uint16_t localSendFromPort = 0,
const std::string &interfaceAssociatedAddress = "") noexcept;
~UDPReceiver() noexcept;

/**
Expand Down
4 changes: 3 additions & 1 deletion libcluon/include/cluon/UDPSender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ class LIBCLUON_API UDPSender {
*
* @param sendToAddress Numerical IPv4 address to send a UDP packet to.
* @param sendToPort Port to send a UDP packet to.
* @param interfaceAssociatedAddress Optional numerical IPv4 address associated with a interface. If given, will be used to
* specify which interface to use when sending to a multicast group.
*/
UDPSender(const std::string &sendToAddress, uint16_t sendToPort) noexcept;
UDPSender(const std::string &sendToAddress, uint16_t sendToPort, const std::string &interfaceAssociatedAddress = "") noexcept;
~UDPSender() noexcept;

/**
Expand Down
7 changes: 4 additions & 3 deletions libcluon/src/OD4Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

namespace cluon {

OD4Session::OD4Session(uint16_t CID, std::function<void(cluon::data::Envelope &&envelope)> delegate) noexcept
OD4Session::OD4Session(uint16_t CID, std::function<void(cluon::data::Envelope &&envelope)> delegate, const std::string &interfaceAssociatedAddress) noexcept
: m_receiver{nullptr}
, m_sender{"225.0.0." + std::to_string(CID), 12175}
, m_sender{"225.0.0." + std::to_string(CID), 12175, interfaceAssociatedAddress}
, m_delegate(std::move(delegate))
, m_mapOfDataTriggeredDelegatesMutex{}
, m_mapOfDataTriggeredDelegates{} {
Expand All @@ -30,7 +30,8 @@ OD4Session::OD4Session(uint16_t CID, std::function<void(cluon::data::Envelope &&
[this](std::string &&data, std::string &&from, std::chrono::system_clock::time_point &&timepoint) {
this->callback(std::move(data), std::move(from), std::move(timepoint));
},
m_sender.getSendFromPort() /* passing our local send from port to the UDPReceiver to filter out our own bytes */);
m_sender.getSendFromPort() /* passing our local send from port to the UDPReceiver to filter out our own bytes */,
interfaceAssociatedAddress);
}

void OD4Session::timeTrigger(float freq, std::function<bool()> delegate) noexcept {
Expand Down
34 changes: 18 additions & 16 deletions libcluon/src/UDPReceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ namespace cluon {
UDPReceiver::UDPReceiver(const std::string &receiveFromAddress,
uint16_t receiveFromPort,
std::function<void(std::string &&, std::string &&, std::chrono::system_clock::time_point &&)> delegate,
uint16_t localSendFromPort) noexcept
uint16_t localSendFromPort,
const std::string &interfaceAssociatedAddress) noexcept
: m_localSendFromPort(localSendFromPort)
, m_receiveFromAddress()
, m_mreq()
Expand All @@ -72,7 +73,10 @@ UDPReceiver::UDPReceiver(const std::string &receiveFromAddress,
&& (0 < receiveFromPort)) {
// Check for valid IP address.
struct sockaddr_in tmpSocketAddress {};
const bool isValid = (0 < ::inet_pton(AF_INET, receiveFromAddress.c_str(), &(tmpSocketAddress.sin_addr))) && (224 > receiveFromAddressTokens[0] || 255 == receiveFromAddressTokens[0]); // Accept regular IP addresses (ie., non-multicast addesses and the network-wide broadcast address 255.255.255.255.
const bool isValid
= (0 < ::inet_pton(AF_INET, receiveFromAddress.c_str(), &(tmpSocketAddress.sin_addr)))
&& (224 > receiveFromAddressTokens[0] || 255 == receiveFromAddressTokens[0]); // Accept regular IP addresses (ie., non-multicast addesses and the
// network-wide broadcast address 255.255.255.255.

// Check for UDP multicast, i.e., IP address range [225.0.0.1 - 239.255.255.255].
m_isMulticast = (((224 < receiveFromAddressTokens[0]) && (receiveFromAddressTokens[0] <= 239))
Expand All @@ -89,26 +93,24 @@ UDPReceiver::UDPReceiver(const std::string &receiveFromAddress,
struct ifaddrs *ifaddr{nullptr};
if (0 == getifaddrs(&ifaddr)) {
for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (NULL == ifa->ifa_addr) continue; // LCOV_EXCL_LINE
if (NULL == ifa->ifa_addr)
continue; // LCOV_EXCL_LINE

if (ifa->ifa_addr->sa_family == AF_INET) {
char broadcastAddress[NI_MAXHOST];
#ifdef __APPLE__
if (NULL == ifa->ifa_dstaddr) continue; // LCOV_EXCL_LINE
if (0 == ::getnameinfo(ifa->ifa_dstaddr,
sizeof(struct sockaddr_in),
broadcastAddress, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST))
if (NULL == ifa->ifa_dstaddr)
continue; // LCOV_EXCL_LINE
if (0 == ::getnameinfo(ifa->ifa_dstaddr, sizeof(struct sockaddr_in), broadcastAddress, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
#else
if (NULL == ifa->ifa_ifu.ifu_broadaddr) continue; // LCOV_EXCL_LINE
if (0 == ::getnameinfo(ifa->ifa_ifu.ifu_broadaddr,
sizeof(struct sockaddr_in),
broadcastAddress, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST))
if (NULL == ifa->ifa_ifu.ifu_broadaddr)
continue; // LCOV_EXCL_LINE
if (0
== ::getnameinfo(ifa->ifa_ifu.ifu_broadaddr, sizeof(struct sockaddr_in), broadcastAddress, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
#endif
{
std::string _tmp{broadcastAddress};
isBroadcast |= (_tmp.compare(receiveFromAddress) == 0);
std::string _tmp{broadcastAddress};
isBroadcast |= (_tmp.compare(receiveFromAddress) == 0);
}
}
}
Expand Down Expand Up @@ -236,8 +238,8 @@ UDPReceiver::UDPReceiver(const std::string &receiveFromAddress,
if (m_isMulticast) {
// Join the multicast group.
m_mreq.imr_multiaddr.s_addr = ::inet_addr(receiveFromAddress.c_str());
m_mreq.imr_interface.s_addr = htonl(INADDR_ANY);
// clang-format off
m_mreq.imr_interface.s_addr = interfaceAssociatedAddress.empty() ? htonl(INADDR_ANY) : ::inet_addr(interfaceAssociatedAddress.c_str());
auto retval = ::setsockopt(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, reinterpret_cast<char *>(&m_mreq), sizeof(m_mreq)); // NOLINT
// clang-format on
if (0 > retval) { // LCOV_EXCL_LINE
Expand Down
59 changes: 42 additions & 17 deletions libcluon/src/UDPSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

namespace cluon {

UDPSender::UDPSender(const std::string &sendToAddress, uint16_t sendToPort) noexcept
UDPSender::UDPSender(const std::string &sendToAddress, uint16_t sendToPort, const std::string &interfaceAssociatedAddress) noexcept
: m_socketMutex()
, m_sendToAddress() {
// Decompose given address into tokens to check validity with numerical IPv4 address.
Expand All @@ -58,6 +58,11 @@ UDPSender::UDPSender(const std::string &sendToAddress, uint16_t sendToPort) noex

m_socket = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

// Check for UDP multicast, i.e., IP address range [225.0.0.1 - 239.255.255.255].
bool isMulticast
= (((224 < sendToAddressTokens[0]) && (sendToAddressTokens[0] <= 239)) && ((0 <= sendToAddressTokens[1]) && (sendToAddressTokens[1] <= 255))
&& ((0 <= sendToAddressTokens[2]) && (sendToAddressTokens[2] <= 255)) && ((1 <= sendToAddressTokens[3]) && (sendToAddressTokens[3] <= 255)));

#ifndef WIN32
// Check whether given address is a broadcast address.
bool isBroadcast{false};
Expand All @@ -67,24 +72,21 @@ UDPSender::UDPSender(const std::string &sendToAddress, uint16_t sendToPort) noex
struct ifaddrs *ifaddr{nullptr};
if (0 == getifaddrs(&ifaddr)) {
for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (NULL == ifa->ifa_addr) continue; // LCOV_EXCL_LINE
if (NULL == ifa->ifa_addr)
continue; // LCOV_EXCL_LINE
char broadcastAddress[NI_MAXHOST];
#ifdef __APPLE__
if (NULL == ifa->ifa_dstaddr) continue; // LCOV_EXCL_LINE
if (0 == ::getnameinfo(ifa->ifa_dstaddr,
sizeof(struct sockaddr_in),
broadcastAddress, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST))
if (NULL == ifa->ifa_dstaddr)
continue; // LCOV_EXCL_LINE
if (0 == ::getnameinfo(ifa->ifa_dstaddr, sizeof(struct sockaddr_in), broadcastAddress, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
#else
if (NULL == ifa->ifa_ifu.ifu_broadaddr) continue; // LCOV_EXCL_LINE
if (0 == ::getnameinfo(ifa->ifa_ifu.ifu_broadaddr,
sizeof(struct sockaddr_in),
broadcastAddress, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST))
if (NULL == ifa->ifa_ifu.ifu_broadaddr)
continue; // LCOV_EXCL_LINE
if (0 == ::getnameinfo(ifa->ifa_ifu.ifu_broadaddr, sizeof(struct sockaddr_in), broadcastAddress, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
#endif
{
std::string _tmp{broadcastAddress};
isBroadcast |= (_tmp.compare(sendToAddress) == 0);
std::string _tmp{broadcastAddress};
isBroadcast |= (_tmp.compare(sendToAddress) == 0);
}
}
freeifaddrs(ifaddr);
Expand All @@ -104,11 +106,34 @@ UDPSender::UDPSender(const std::string &sendToAddress, uint16_t sendToPort) noex
#ifdef WIN32 // LCOV_EXCL_LINE
auto errorCode = WSAGetLastError();
#else
auto errorCode = errno; // LCOV_EXCL_LINE
#endif // LCOV_EXCL_LINE
auto errorCode = errno; // LCOV_EXCL_LINE
#endif // LCOV_EXCL_LINE
std::cerr << "[cluon::UDPSender] Failed to perform socket operation: "; // LCOV_EXCL_LINE
#ifdef WIN32 // LCOV_EXCL_LINE
std::cerr << errorCode << std::endl;
#else
std::cerr << ::strerror(errorCode) << " (" << errorCode << ")" << std::endl; // LCOV_EXCL_LINE
#endif // LCOV_EXCL_LINE
}
}
#endif

#ifndef WIN32
if (!(m_socket < 0) && isMulticast) {
struct in_addr interface_addr;
interface_addr.s_addr = interfaceAssociatedAddress.empty() ? htonl(INADDR_ANY) : ::inet_addr(interfaceAssociatedAddress.c_str());
// clang-format off
auto retVal = ::setsockopt(m_socket, IPPROTO_IP, IP_MULTICAST_IF, reinterpret_cast<char *>(&interface_addr), sizeof(interface_addr)); // NOLINT
// clang-format on
if (0 > retVal) {
#ifdef WIN32 // LCOV_EXCL_LINE
std::cerr << errorCode << std::endl;
auto errorCode = WSAGetLastError();
#else
auto errorCode = errno; // LCOV_EXCL_LINE
#endif // LCOV_EXCL_LINE
std::cerr << "[cluon::UDPSender] Failed to perform socket operation: "; // LCOV_EXCL_LINE
#ifdef WIN32 // LCOV_EXCL_LINE
std::cerr << errorCode << std::endl;
#else
std::cerr << ::strerror(errorCode) << " (" << errorCode << ")" << std::endl; // LCOV_EXCL_LINE
#endif // LCOV_EXCL_LINE
Expand Down