Browse Source

Added support for finding the broadcast address of an interface

tags/2021-05-28
cesare jules 7 years ago
parent
commit
e1a8bbf020
7 changed files with 272 additions and 37 deletions
  1. +28
    -2
      extras/UnitTestRunner/Source/Main.cpp
  2. +2
    -0
      modules/juce_core/juce_core.cpp
  3. +6
    -0
      modules/juce_core/native/juce_android_Network.cpp
  4. +140
    -0
      modules/juce_core/native/juce_mac_linux_IPAddress.h
  5. +7
    -0
      modules/juce_core/native/juce_win32_Network.cpp
  6. +81
    -35
      modules/juce_core/network/juce_IPAddress.cpp
  7. +8
    -0
      modules/juce_core/network/juce_IPAddress.h

+ 28
- 2
extras/UnitTestRunner/Source/Main.cpp View File

@@ -48,14 +48,40 @@ class ConsoleUnitTestRunner : public UnitTestRunner
}
};
//==============================================================================
int main()
int main (int argc, char **argv)
{
ConsoleLogger logger;
Logger::setCurrentLogger (&logger);
ConsoleUnitTestRunner runner;
runner.runAllTests();
ArgumentList args (argc, argv);
if (args.size() == 0)
{
runner.runAllTests();
}
else
{
if (args.containsOption ("--help|-h"))
{
std::cout << argv[0] << " [--help|-h] [--category category] [--list-categories]" << std::endl;
return 0;
}
if (args.containsOption ("--list-categories"))
{
for (auto& category : UnitTest::getAllCategories())
std::cout << category << std::endl;
return 0;
}
if (args.containsOption ("--category"))
runner.runTestsInCategory (args.getArgumentAfterOption ("--category").text);
}
Logger::setCurrentLogger (nullptr);


+ 2
- 0
modules/juce_core/juce_core.cpp View File

@@ -190,6 +190,7 @@
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#include "native/juce_mac_Files.mm"
#include "native/juce_mac_linux_IPAddress.h"
#include "native/juce_mac_Network.mm"
#include "native/juce_mac_Strings.mm"
#include "native/juce_mac_SystemStats.mm"
@@ -207,6 +208,7 @@
#elif JUCE_LINUX
#include "native/juce_linux_CommonFile.cpp"
#include "native/juce_linux_Files.cpp"
#include "native/juce_mac_linux_IPAddress.h"
#include "native/juce_linux_Network.cpp"
#if JUCE_USE_CURL
#include "native/juce_curl_Network.cpp"


+ 6
- 0
modules/juce_core/native/juce_android_Network.cpp View File

@@ -400,4 +400,10 @@ void IPAddress::findAllAddresses (Array<IPAddress>& result, bool /*includeIPv6*/
}
}
IPAddress IPAddress::getInterfaceBroadcastAddress (const IPAddress&)
{
return {}; // TODO
}
} // namespace juce

+ 140
- 0
modules/juce_core/native/juce_mac_linux_IPAddress.h View File

@@ -0,0 +1,140 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace
{
static IPAddress makeAddress (const sockaddr_in6* addr_in)
{
if (addr_in == nullptr)
return {};
in6_addr addr = addr_in->sin6_addr;
union ByteUnion
{
uint16 combined;
uint8 split[2];
};
ByteUnion temp;
uint16 arr[8];
for (int i = 0; i < 8; ++i) // Swap bytes from network to host order
{
temp.split[0] = addr.s6_addr[i * 2 + 1];
temp.split[1] = addr.s6_addr[i * 2];
arr[i] = temp.combined;
}
return IPAddress (arr);
}
static IPAddress makeAddress (const sockaddr_in *addr_in)
{
if (addr_in->sin_addr.s_addr == INADDR_NONE)
return {};
return IPAddress (ntohl (addr_in->sin_addr.s_addr));
}
struct InterfaceInfo
{
IPAddress interfaceAddress;
IPAddress broadcastAddress;
};
bool operator== (const InterfaceInfo& lhs, const InterfaceInfo& rhs)
{
return lhs.interfaceAddress == rhs.interfaceAddress
&& lhs.broadcastAddress == rhs.broadcastAddress;
}
bool populateInterfaceInfo (struct ifaddrs* ifa, InterfaceInfo& interfaceInfo)
{
if (ifa->ifa_addr != nullptr)
{
if (ifa->ifa_addr->sa_family == AF_INET)
{
auto* interfaceAddressInfo = (sockaddr_in*) ifa->ifa_addr;
auto* broadcastAddressInfo = (sockaddr_in*) ifa->ifa_dstaddr;
if (interfaceAddressInfo->sin_addr.s_addr != INADDR_NONE)
{
interfaceInfo.interfaceAddress = makeAddress (interfaceAddressInfo);
interfaceInfo.broadcastAddress = makeAddress (broadcastAddressInfo);
return true;
}
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
interfaceInfo.interfaceAddress = makeAddress ((sockaddr_in6*) ifa->ifa_addr);
interfaceInfo.broadcastAddress = makeAddress ((sockaddr_in6*) ifa->ifa_dstaddr);
return true;
}
}
return false;
}
Array<InterfaceInfo> getAllInterfaceInfo()
{
Array<InterfaceInfo> interfaces;
struct ifaddrs* ifaddr = nullptr;
if (getifaddrs (&ifaddr) != -1)
{
for (auto* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
{
InterfaceInfo i;
if (populateInterfaceInfo (ifa, i))
interfaces.addIfNotAlreadyThere (i);
}
freeifaddrs (ifaddr);
}
return interfaces;
}
}
void IPAddress::findAllAddresses (Array<IPAddress>& result, bool includeIPv6)
{
for (auto& i : getAllInterfaceInfo())
if (includeIPv6 || ! i.interfaceAddress.isIPv6)
result.addIfNotAlreadyThere (i.interfaceAddress);
}
IPAddress IPAddress::getInterfaceBroadcastAddress (const IPAddress& interfaceAddress)
{
for (auto& i : getAllInterfaceInfo())
if (i.interfaceAddress == interfaceAddress)
return i.broadcastAddress;
return {};
}
} // namespace juce

+ 7
- 0
modules/juce_core/native/juce_win32_Network.cpp View File

@@ -618,6 +618,13 @@ void IPAddress::findAllAddresses (Array<IPAddress>& result, bool includeIPv6)
}
}
IPAddress IPAddress::getInterfaceBroadcastAddress (const IPAddress&)
{
// TODO
return IPAddress {};
}
//==============================================================================
bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
const String& emailSubject,


+ 81
- 35
modules/juce_core/network/juce_IPAddress.cpp View File

@@ -85,6 +85,15 @@ IPAddress::IPAddress (uint32 n) noexcept : isIPv6 (false)
zeroUnusedBytes();
}
bool IPAddress::isNull() const
{
for (int i = 0; i < 16; ++i)
if (address[i] != 0)
return false;
return true;
}
static String removePort (const String& adr)
{
if (adr.containsAnyOf ("[]"))
@@ -350,57 +359,94 @@ Array<IPAddress> IPAddress::getAllAddresses (bool includeIPv6)
return addresses;
}
#if (! JUCE_WINDOWS) && (! JUCE_ANDROID)
static void addAddress (const sockaddr_in* addr_in, Array<IPAddress>& result)
{
auto addr = addr_in->sin_addr.s_addr;
if (addr != INADDR_NONE)
result.addIfNotAlreadyThere (IPAddress (ntohl (addr)));
}
//==============================================================================
#if JUCE_UNIT_TESTS
static void addAddress (const sockaddr_in6* addr_in, Array<IPAddress>& result)
struct IPAddressTests : public UnitTest
{
in6_addr addr = addr_in->sin6_addr;
union ByteUnion
IPAddressTests()
: UnitTest ("IPAddress", "Networking")
{
uint16 combined;
uint8 split[2];
};
}
ByteUnion temp;
uint16 arr[8];
void runTest() override
{
testConstructors();
testFindAllAddresses();
testFindBroadcastAddress();
}
for (int i = 0; i < 8; ++i) // Swap bytes from network to host order
void testConstructors()
{
temp.split[0] = addr.s6_addr[i * 2 + 1];
temp.split[1] = addr.s6_addr[i * 2];
beginTest ("constructors");
arr[i] = temp.combined;
// Default IPAdress should be null
IPAddress defaultConstructed;
expect (defaultConstructed.isNull());
auto local = IPAddress::local();
expect (! local.isNull());
IPAddress ipv4{1, 2, 3, 4};
expect (! ipv4.isNull());
expect (! ipv4.isIPv6);
expect (ipv4.toString() == "1.2.3.4");
}
result.addIfNotAlreadyThere (IPAddress (arr));
}
void testFindAllAddresses()
{
beginTest ("find all addresses");
void IPAddress::findAllAddresses (Array<IPAddress>& result, bool includeIPv6)
{
struct ifaddrs* ifaddr = nullptr;
Array<IPAddress> ipv4Addresses;
Array<IPAddress> allAddresses;
if (getifaddrs (&ifaddr) == -1)
return;
IPAddress::findAllAddresses (ipv4Addresses, false);
IPAddress::findAllAddresses (allAddresses, true);
for (auto* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
expect (allAddresses.size() >= ipv4Addresses.size());
for (auto& a : ipv4Addresses)
{
expect (! a.isNull());
expect (! a.isIPv6);
}
for (auto& a : allAddresses)
{
expect (! a.isNull());
}
}
void testFindBroadcastAddress()
{
if (ifa->ifa_addr == nullptr)
continue;
beginTest ("broadcast addresses");
Array<IPAddress> addresses;
// Only IPv4 interfaces have broadcast
IPAddress::findAllAddresses (addresses, false);
if (ifa->ifa_addr->sa_family == AF_INET) addAddress ((const sockaddr_in*) ifa->ifa_addr, result);
else if (ifa->ifa_addr->sa_family == AF_INET6 && includeIPv6) addAddress ((const sockaddr_in6*) ifa->ifa_addr, result);
for (auto& a : addresses)
{
expect (! a.isNull());
auto broadcastAddress = IPAddress::getInterfaceBroadcastAddress (a);
// If we retrieve an address, it should be an IPv4 address
if (! broadcastAddress.isNull())
{
expect (! a.isIPv6);
}
}
// Expect to fail to find a broadcast for this address
IPAddress address{1, 2, 3, 4};
expect (IPAddress::getInterfaceBroadcastAddress (address).isNull());
}
};
static IPAddressTests iPAddressTests;
freeifaddrs (ifaddr);
}
#endif
} // namespace juce

+ 8
- 0
modules/juce_core/network/juce_IPAddress.h View File

@@ -87,6 +87,9 @@ public:
/** Parses a string IP address of the form "1.2.3.4" (IPv4) or "1:2:3:4:5:6:7:8" (IPv6). */
explicit IPAddress (const String& address);
/** Returns whether the address contains the null address (e.g. 0.0.0.0). */
bool isNull() const;
//==============================================================================
/** Returns a dot- or colon-separated string in the form "1.2.3.4" (IPv4) or "1:2:3:4:5:6:7:8" (IPv6). */
String toString() const;
@@ -130,6 +133,11 @@ public:
/** Converts an IPv4 address to an IPv4-mapped IPv6 address. */
static IPAddress convertIPv4AddressToIPv4Mapped (const IPAddress& addressToMap);
/** If the IPAdress is the address of an interface on the machine, returns the associated broadcast address.
If the address is not an interface, it will return a null address.
*/
static IPAddress getInterfaceBroadcastAddress (const IPAddress& interfaceAddress);
private:
/** Union used to split a 16-bit unsigned integer into 2 8-bit unsigned integers or vice-versa */
union ByteUnion


Loading…
Cancel
Save