Implement getifaddrs.

This is a BSD extension also available in glibc, but is not POSIX.
Fixes #6279.
This commit is contained in:
Adrien Destugues 2015-01-16 13:06:48 +01:00
parent 23f1ce0756
commit e2fc7cd3c7
2 changed files with 98 additions and 1 deletions

View File

@ -0,0 +1,25 @@
/*
* Copyright 2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _IFADDRS_H
#define _IFADDRS_H
struct ifaddrs {
struct ifaddrs *ifa_next; /* Next item in list */
const char *ifa_name; /* Name of interface */
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr; /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
struct sockaddr *ifa_dstaddr;
#define ifa_broadaddr ifa_dstaddr
void *ifa_data; /* Address-specific data */
};
int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifa);
#endif

View File

@ -1,12 +1,14 @@
/*
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#include <errno.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@ -15,6 +17,11 @@
#include <unistd.h>
#include <AutoDeleter.h>
#include <NetworkAddress.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include "compatibility/bsd/ifaddrs.h"
namespace BPrivate {
@ -141,3 +148,68 @@ if_freenameindex(struct if_nameindex *interfaceArray)
free(interfaceArray);
}
int getifaddrs(struct ifaddrs **ifap)
{
if (ifap == NULL) {
errno = B_BAD_VALUE;
return -1;
}
BNetworkRoster& roster = BNetworkRoster::Default();
uint32 cookie;
struct ifaddrs* previous = NULL;
struct ifaddrs* current = NULL;
BNetworkInterface* interface = new BNetworkInterface();
while (roster.GetNextInterface(&cookie, *interface) == B_OK) {
BNetworkInterfaceAddress address;
int32 i = 0;
while (interface->GetAddressAt(i++, address) == B_OK) {
current = new ifaddrs();
// Chain this interface with the next one
current->ifa_next = previous;
previous = current;
current->ifa_data = interface;
current->ifa_name = interface->Name();
// Points to the name in the BNetworkInterface instance, which
// is added as ifa_data so freeifaddrs can release it.
current->ifa_flags = address.Flags();
current->ifa_addr = new sockaddr(address.Address().SockAddr());
current->ifa_netmask = new sockaddr(address.Mask().SockAddr());
current->ifa_dstaddr = new sockaddr(address.Destination().SockAddr());
}
interface = new BNetworkInterface();
}
delete interface;
*ifap = current;
return 0;
}
void freeifaddrs(struct ifaddrs *ifa)
{
struct ifaddrs* next;
BNetworkInterface* interface = NULL;
while (ifa != NULL) {
if (ifa->ifa_data != interface) {
interface = (BNetworkInterface*)ifa->ifa_data;
delete interface;
}
delete ifa->ifa_addr;
delete ifa->ifa_netmask;
delete ifa->ifa_dstaddr;
next = ifa->ifa_next;
delete ifa;
ifa = next;
}
}