mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-20 01:14:20 +00:00
Added support for finding the broadcast address of an interface
This commit is contained in:
parent
bea6639637
commit
e1a8bbf020
7 changed files with 281 additions and 46 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -400,4 +400,10 @@ void IPAddress::findAllAddresses (Array<IPAddress>& result, bool /*includeIPv6*/
|
|||
}
|
||||
}
|
||||
|
||||
IPAddress IPAddress::getInterfaceBroadcastAddress (const IPAddress&)
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
140
modules/juce_core/native/juce_mac_linux_IPAddress.h
Normal file
140
modules/juce_core/native/juce_mac_linux_IPAddress.h
Normal 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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
struct IPAddressTests : public UnitTest
|
||||
{
|
||||
auto addr = addr_in->sin_addr.s_addr;
|
||||
|
||||
if (addr != INADDR_NONE)
|
||||
result.addIfNotAlreadyThere (IPAddress (ntohl (addr)));
|
||||
}
|
||||
|
||||
static void addAddress (const sockaddr_in6* addr_in, Array<IPAddress>& result)
|
||||
{
|
||||
in6_addr addr = addr_in->sin6_addr;
|
||||
|
||||
union ByteUnion
|
||||
IPAddressTests()
|
||||
: UnitTest ("IPAddress", "Networking")
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
result.addIfNotAlreadyThere (IPAddress (arr));
|
||||
}
|
||||
|
||||
void IPAddress::findAllAddresses (Array<IPAddress>& result, bool includeIPv6)
|
||||
{
|
||||
struct ifaddrs* ifaddr = nullptr;
|
||||
|
||||
if (getifaddrs (&ifaddr) == -1)
|
||||
return;
|
||||
|
||||
for (auto* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
|
||||
void runTest() override
|
||||
{
|
||||
if (ifa->ifa_addr == nullptr)
|
||||
continue;
|
||||
|
||||
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);
|
||||
testConstructors();
|
||||
testFindAllAddresses();
|
||||
testFindBroadcastAddress();
|
||||
}
|
||||
|
||||
freeifaddrs (ifaddr);
|
||||
}
|
||||
void testConstructors()
|
||||
{
|
||||
beginTest ("constructors");
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
void testFindAllAddresses()
|
||||
{
|
||||
beginTest ("find all addresses");
|
||||
|
||||
Array<IPAddress> ipv4Addresses;
|
||||
Array<IPAddress> allAddresses;
|
||||
|
||||
IPAddress::findAllAddresses (ipv4Addresses, false);
|
||||
IPAddress::findAllAddresses (allAddresses, true);
|
||||
|
||||
expect (allAddresses.size() >= ipv4Addresses.size());
|
||||
|
||||
for (auto& a : ipv4Addresses)
|
||||
{
|
||||
expect (! a.isNull());
|
||||
expect (! a.isIPv6);
|
||||
}
|
||||
|
||||
for (auto& a : allAddresses)
|
||||
{
|
||||
expect (! a.isNull());
|
||||
}
|
||||
}
|
||||
|
||||
void testFindBroadcastAddress()
|
||||
{
|
||||
beginTest ("broadcast addresses");
|
||||
|
||||
Array<IPAddress> addresses;
|
||||
|
||||
// Only IPv4 interfaces have broadcast
|
||||
IPAddress::findAllAddresses (addresses, false);
|
||||
|
||||
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;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Add a link
Reference in a new issue