If you search on datagram sockets you’ll find some extensions/fixes for the sockets classes I posted. I added a helper class that let’s you create an array of all the IP addresses currently in use by a given machine, it works on iOS, Android, Mac, Windows, and Linux. It’s probably a bit out of date. I think I fixed a few more streaming socket bugs since, and I think that the header files got refactored in the Juce master branch, but the helper class should be pretty self contained.
FWIW, I merged with the tip just the other day. Here is my mucked up juce_socket.cpp and juce_socket.h. I think all my changes are backwards compatible, but I never really checked. You could just yank IpAddress. You’d use it something like this:
Array<IpAddress> ips;
IpAddress::findAllIpAddresses (ips);
for (int n=0; n < ips.size(); ++n)
Logger::outputDebugString (ips[n].toString());
Thanks jfitzpat, I’ve imported your class and it works after a few adjustments in header includes, I only have run it on a mac, i’ll try win later.
//
// J_IPAddress.h
// AGP
//
// Created by Someone on 7/13/12.
// Copyright (c) 2012 yourcompanyname. All rights reserved.
//
#ifndef AGP_J_IPAddress_h
#define AGP_J_IPAddress_h
#include "../JuceLibraryCode/JuceHeader.h"
class JUCE_API IpAddress
{
public:
//==============================================================================
/** Populates a list of the IPv4 addresses of all the available network cards. */
static void findAllIpAddresses (Array<IpAddress>& results);
//==============================================================================
/** Creates a null address (0.0.0.0). */
IpAddress();
/** Creates from a host order uint32. */
IpAddress (uint32 addr);
/** Creates from another address. */
IpAddress (const IpAddress& other);
/** Creates a copy of another address. */
IpAddress& operator= (const IpAddress& other);
/** Creates an address from a string ("1.2.3.4"). */
explicit IpAddress (const String& addr);
/** Returns a dot-separated string in the form "1.2.3.4". */
String toString() const;
/** Return as host order uint32. */
uint32 toUint32() const noexcept;
/** Return as network order uint32. */
uint32 toNetworkUint32() const noexcept;
/** Returns true if this address is ANY (0.0.0.0). */
bool isAny() const noexcept;
/** Returns true if this address is BROADCAST (255.255.255.255). */
bool isBroadcast() const noexcept;
/** Returns true if this address is LOOPBACK (127.0.0.1). */
bool isLocal() const noexcept;
bool operator== (const IpAddress& other) const noexcept;
bool operator!= (const IpAddress& other) const noexcept;
//==============================================================================
/** IPv4 Any Address. */
static const IpAddress any;
static const IpAddress broadcast;
static const IpAddress localhost;
//==============================================================================
private:
uint32 ipAddress;
};
#endif
//
// J_IPAdress.cpp
// AGP
//
// Created by someone on 7/13/12.
// Copyright (c) 2012 yourcompanyname. All rights reserved.
//
#if JUCE_MSVC
#pragma warning (push)
#pragma warning (disable : 4127 4389 4018)
#endif
#ifndef AI_NUMERICSERV // (missing in older Mac SDKs)
#define AI_NUMERICSERV 0x1000
#endif
#if JUCE_WINDOWS
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <sys/errno.h>
//#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#endif
#include "J_IPAddress.h"
//==============================================================================
//==============================================================================
IpAddress::IpAddress()
: ipAddress (0)
{
}
IpAddress::IpAddress (uint32 addr)
: ipAddress (addr)
{
}
IpAddress::IpAddress (const IpAddress& other)
: ipAddress (other.ipAddress)
{
}
IpAddress& IpAddress::operator= (const IpAddress& other)
{
ipAddress = other.ipAddress;
return *this;
}
IpAddress::IpAddress (const String& addr)
{
uint32 temp = inet_addr (addr.toUTF8());
ipAddress = ntohl (temp);
}
String IpAddress::toString() const
{
String s;
s = String ((ipAddress >> 24) & 0xFF);
s << '.';
s << String ((ipAddress >> 16) & 0xFF);
s << '.';
s << String ((ipAddress >> 8) & 0xFF);
s << '.';
s << String (ipAddress & 0xFF);
return s;
}
uint32 IpAddress::toUint32() const noexcept
{
return ipAddress;
}
uint32 IpAddress::toNetworkUint32() const noexcept
{
return htonl (ipAddress);
}
bool IpAddress::isAny() const noexcept { return ipAddress == 0; }
bool IpAddress::isBroadcast() const noexcept { return ipAddress == 0xFFFFFFFF; }
bool IpAddress::isLocal() const noexcept { return ipAddress == 0x7F000001; }
bool IpAddress::operator== (const IpAddress& other) const noexcept
{
return ipAddress == other.ipAddress;
}
bool IpAddress::operator!= (const IpAddress& other) const noexcept
{
return ipAddress != other.ipAddress;
}
#if JUCE_WINDOWS
void IpAddress::findAllIpAddresses (Array<IpAddress>& result)
{
// For consistancy
result.addIfNotAlreadyThere (IpAddress ("127.0.0.1"));
DynamicLibrary dll ("iphlpapi.dll");
JUCE_DLL_FUNCTION (GetAdaptersInfo, getAdaptersInfo, DWORD, dll, (PIP_ADAPTER_INFO, PULONG))
if (getAdaptersInfo != nullptr)
{
ULONG len = sizeof (IP_ADAPTER_INFO);
HeapBlock<IP_ADAPTER_INFO> adapterInfo (1);
if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
adapterInfo.malloc (len, 1);
if (getAdaptersInfo (adapterInfo, &len) == NO_ERROR)
{
for (PIP_ADAPTER_INFO adapter = adapterInfo; adapter != nullptr; adapter = adapter->Next)
{
IpAddress ip (adapter->IpAddressList.IpAddress.String);
if (! ip.isAny())
result.addIfNotAlreadyThere (ip);
}
}
}
}
#endif
#if JUCE_MAC || JUCE_IOS
// Oh joy, two incompatible SIOCGIFCONF interfaces...
void IpAddress::findAllIpAddresses (Array<IpAddress>& result)
{
struct ifconf cfg;
size_t buffer_capacity;
HeapBlock<char> buffer;
int sock = -1;
// Compute the sizes of ifreq structures
const size_t ifreq_size_in = IFNAMSIZ + sizeof (struct sockaddr_in);
const size_t ifreq_size_in6 = IFNAMSIZ + sizeof (struct sockaddr_in6);
// Poor man's try since we can be in an existing noexcept
do
{
// Create a dummy socket to execute the IO control on
sock = socket (AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
break;
// Repeatedly call the IO control with increasing buffer sizes until success
// Ugly, old school...
bool success = true;
buffer_capacity = ifreq_size_in6;
do
{
buffer_capacity *= 2;
buffer.realloc (buffer_capacity);
cfg.ifc_len = buffer_capacity;
cfg.ifc_buf = buffer;
if ((ioctl (sock, SIOCGIFCONF, &cfg) < 0) && (errno != EINVAL))
{
success = false;
break;
}
} while ((buffer_capacity - cfg.ifc_len) < 2 * ifreq_size_in6);
// How did we do?
if (success == false)
break;
// Copy the interface addresses into the result array
while (cfg.ifc_len >= ifreq_size_in)
{
// Skip entries for non-internet addresses
if (cfg.ifc_req->ifr_addr.sa_family == AF_INET)
{
const struct sockaddr_in* addr_in = (const struct sockaddr_in*) &cfg.ifc_req->ifr_addr;
in_addr_t addr = addr_in->sin_addr.s_addr;
// Skip entries without an address
if (addr != INADDR_NONE)
result.addIfNotAlreadyThere (IpAddress (ntohl(addr)));
}
// Move to the next structure in the buffer
// CANNOT just use sizeof (ifreq) because entries vary in size
cfg.ifc_len -= IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
cfg.ifc_buf += IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
}
} while (0);
// Free the buffer and close the socket if necessary
buffer.free();
if (sock >= 0)
close(sock);
}
#endif
#if JUCE_LINUX || JUCE_ANDROID
void IpAddress::findAllIpAddresses (Array<IpAddress>& result)
{
const int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
char buf [1024];
struct ifconf ifc;
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
ioctl (s, SIOCGIFCONF, &ifc);
struct ifreq *ifr = ifc.ifc_req;
int nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
for(int i = 0; i < nInterfaces; i++)
{
struct ifreq *item = &ifr[i];
if (item->ifr_addr.sa_family == AF_INET)
{
const struct sockaddr_in* addr_in = (const struct sockaddr_in*) &item->ifr_addr;
in_addr_t addr = addr_in->sin_addr.s_addr;
// Skip entries without an address
if (addr != INADDR_NONE)
result.addIfNotAlreadyThere (IpAddress (ntohl(addr)));
}
}
close (s);
}
}
#endif
const IpAddress IpAddress::any (0);
const IpAddress IpAddress::broadcast (0xFFFFFFFF);
const IpAddress IpAddress::localhost (0x7F000001);
I only bothered with IPv4 for the IpAddress class. Same with all the datagram and streaming fixes, really just enough for my needs of the moment. After hacking URL to do Amazon’s weird REST stuff, I’ve been wishing I had time to do a while new set of juce modules for network stuff. Alas, unlike you, I have to sleep 5-6 hours each day…
But at least some of the stuff, like enumerating all the adapters on the different platforms, might at least be a useful reference.
I actually am just coming up for air from another project and need to do a little network/config tool. I’ll try the tip sometime over the next few days. Thanks!