Index: src/OFSystemInfo.h ================================================================== --- src/OFSystemInfo.h +++ src/OFSystemInfo.h @@ -40,13 +40,20 @@ typedef OFConstantString *OFNetworkInterfaceKey; /** * @brief The index of a network interface. * - * This maps to a @ref OFNumber. + * This maps to an @ref OFNumber. */ extern OFNetworkInterfaceKey OFNetworkInterfaceIndex; + +/** + * @brief The IPv4 addresses of a network interface. + * + * This maps to an @ref OFData of @ref OFSocketAddress. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceIPv4Addresses; #endif /** * @class OFSystemInfo OFSystemInfo.h ObjFW/OFSystemInfo.h * Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -40,10 +40,13 @@ # include #endif #ifdef HAVE_NETPACKET_PACKET_H # include #endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif #ifdef OF_AMIGAOS # define Class IntuitionClass # include # include @@ -75,10 +78,11 @@ #import "OFLocale.h" #import "OFNumber.h" #import "OFOnce.h" #ifdef OF_HAVE_SOCKETS # import "OFSocket.h" +# import "OFSocket+Private.h" #endif #import "OFString.h" #if defined(OF_MACOS) || defined(OF_IOS) # ifdef HAVE_SYSDIR_H @@ -125,10 +129,12 @@ NSSearchPathEnumerationState, char *); #endif #ifdef OF_HAVE_SOCKETS OFNetworkInterfaceKey OFNetworkInterfaceIndex = @"OFNetworkInterfaceIndex"; +OFNetworkInterfaceKey OFNetworkInterfaceIPv4Addresses = + @"OFNetworkInterfaceIPv4Addresses"; #endif #if defined(OF_AMD64) || defined(OF_X86) struct X86Regs { uint32_t eax, ebx, ecx, edx; @@ -841,51 +847,154 @@ return !(GetVersion() & 0x80000000); } #endif #ifdef OF_HAVE_SOCKETS -+ (OFDictionary OF_GENERIC(OFString *, OFNetworkInterface) *)networkInterfaces +static bool +queryNetworkInterfaceIndices(OFMutableDictionary *ret) { # ifdef HAVE_IF_NAMEINDEX - OFMutableDictionary *ret = [OFMutableDictionary dictionary]; - void *pool = objc_autoreleasePoolPush(); OFStringEncoding encoding = [OFLocale encoding]; struct if_nameindex *nameindex = if_nameindex(); - if (nameindex == NULL) { - objc_autoreleasePoolPop(pool); - return nil; - } + if (nameindex == NULL) + return false; @try { for (size_t i = 0; nameindex[i].if_index != 0; i++) { OFString *name = [OFString stringWithCString: nameindex[i].if_name encoding: encoding]; OFNumber *index = [OFNumber numberWithUnsignedInt: nameindex[i].if_index]; - OFDictionary *interface = [OFDictionary - dictionaryWithObject: index - forKey: OFNetworkInterfaceIndex]; + OFMutableDictionary *interface = + [ret objectForKey: name]; + + if (interface == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } - [ret setObject: interface forKey: name]; + [interface setObject: index + forKey: OFNetworkInterfaceIndex]; } } @finally { if_freenameindex(nameindex); } + return true; +# else + return false; +# endif +} + +static bool +queryNetworkInterfaceIPv4Addresses(OFMutableDictionary *ret) +{ +# if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) + OFStringEncoding encoding = [OFLocale encoding]; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + struct ifconf ifc; + struct ifreq *ifrs; + OFMutableDictionary *interface; + OFEnumerator *enumerator; + + if (sock < 0) + return false; + + ifrs = malloc(128 * sizeof(struct ifreq)); + if (ifrs == NULL) { + closesocket(sock); + return false; + } + + @try { + memset(&ifc, 0, sizeof(ifc)); + ifc.ifc_buf = (void *)ifrs; + ifc.ifc_len = 128 * sizeof(struct ifreq); + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) + return false; + + for (size_t i = 0; i < ifc.ifc_len / sizeof(struct ifreq); + i++) { + OFString *name; + OFMutableData *addresses; + OFSocketAddress address; + + if (ifrs[i].ifr_addr.sa_family != AF_INET) + continue; + + name = [OFString stringWithCString: ifrs[i].ifr_name + encoding: encoding]; + interface = [ret objectForKey: name]; + if (interface == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + addresses = [interface + objectForKey: OFNetworkInterfaceIPv4Addresses]; + if (addresses == nil) { + addresses = [OFMutableData + dataWithItemSize: sizeof(OFSocketAddress)]; + [interface + setObject: addresses + forKey: OFNetworkInterfaceIPv4Addresses]; + } + + memset(&address, 0, sizeof(address)); + address.family = OFSocketAddressFamilyIPv4; + memcpy(&address.sockaddr.in, &ifrs[i].ifr_addr, + sizeof(struct sockaddr_in)); + + [addresses addItem: &address]; + } + } @finally { + free(ifrs); + closesocket(sock); + } + + enumerator = [ret objectEnumerator]; + while ((interface = [enumerator nextObject]) != nil) + [[interface objectForKey: OFNetworkInterfaceIPv4Addresses] + makeImmutable]; + + return true; +# else + return false; +# endif +} + ++ (OFDictionary OF_GENERIC(OFString *, OFNetworkInterface) *)networkInterfaces +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *ret = [OFMutableDictionary dictionary]; + bool success = false; + OFEnumerator *enumerator; + OFMutableDictionary *interface; + + success |= queryNetworkInterfaceIndices(ret); + success |= queryNetworkInterfaceIPv4Addresses(ret); + + if (!success) { + objc_autoreleasePoolPop(pool); + return nil; + } + + enumerator = [ret objectEnumerator]; + while ((interface = [enumerator nextObject]) != nil) + [interface makeImmutable]; + [ret makeImmutable]; + [ret retain]; objc_autoreleasePoolPop(pool); - return ret; -# else - return nil; -# endif + return [ret autorelease]; } #endif - (instancetype)init { OF_INVALID_INIT_METHOD } @end Index: tests/OFSystemInfoTests.m ================================================================== --- tests/OFSystemInfoTests.m +++ tests/OFSystemInfoTests.m @@ -113,18 +113,37 @@ #ifdef OF_HAVE_SOCKETS networkInterfaces = [OFSystemInfo networkInterfaces]; [OFStdOut writeString: @"[OFSystemInfo] Network interfaces: "]; for (OFString *name in networkInterfaces) { + OFNetworkInterface interface; + OFData *IPv4Addresses; + if (!firstInterface) [OFStdOut writeString: @"; "]; firstInterface = false; - [OFStdOut writeString: name]; + [OFStdOut writeFormat: @"%@(", name]; + + interface = [networkInterfaces objectForKey: name]; + IPv4Addresses = [interface + objectForKey: OFNetworkInterfaceIPv4Addresses]; + + for (size_t i = 0; i < IPv4Addresses.count; i++) { + const OFSocketAddress *address = + [IPv4Addresses itemAtIndex: i]; + + if (i > 0) + [OFStdOut writeString: @", "]; + + [OFStdOut writeString: OFSocketAddressString(address)]; + } + + [OFStdOut writeString: @")"]; } [OFStdOut writeString: @"\n"]; #endif objc_autoreleasePoolPop(pool); } @end