Move getifaddrs to libnetwork again.

* BNetworkInterfaceAddress is moved to libnetwork. It is modified to not
use BNetworkAddress (which is in libbnetapi) and instead use sockaddr
and sockaddr_storage directly. All callers are adjusted to this.
* Some support code is shared between BNetworkInterface and
BNetworkInterfaceAddress, move it to libnetwork but in the BPrivate
namespace.
This commit is contained in:
Adrien Destugues 2015-01-20 14:30:24 +01:00
parent a66de90c49
commit 31ea76548a
17 changed files with 346 additions and 278 deletions

View File

@ -138,9 +138,7 @@ public:
operator const sockaddr*() const;
operator const sockaddr&() const;
operator const sockaddr*();
operator sockaddr*();
operator const sockaddr&();
operator sockaddr&();
private:

View File

@ -8,11 +8,12 @@
#include <net/if.h>
#include <net/if_types.h>
#include <sys/socket.h>
#include <ObjectList.h>
#include <NetworkAddress.h>
class BNetworkAddress;
class BNetworkInterface;
@ -21,24 +22,20 @@ public:
BNetworkInterfaceAddress();
~BNetworkInterfaceAddress();
status_t SetTo(const BNetworkInterface& interface,
status_t SetTo(const char* interfaceName,
int32 index);
void SetAddress(const BNetworkAddress& address);
void SetMask(const BNetworkAddress& mask);
void SetBroadcast(const BNetworkAddress& broadcast);
void SetDestination(
const BNetworkAddress& destination);
void SetAddress(const sockaddr& address);
void SetMask(const sockaddr& mask);
void SetBroadcast(const sockaddr& broadcast);
void SetDestination(const sockaddr& destination);
BNetworkAddress& Address() { return fAddress; }
BNetworkAddress& Mask() { return fMask; }
BNetworkAddress& Broadcast() { return fBroadcast; }
BNetworkAddress& Destination() { return fBroadcast; }
const BNetworkAddress& Address() const { return fAddress; }
const BNetworkAddress& Mask() const { return fMask; }
const BNetworkAddress& Broadcast() const { return fBroadcast; }
const BNetworkAddress& Destination() const { return fBroadcast; }
const sockaddr& Address() const { return (sockaddr&)fAddress; }
const sockaddr& Mask() const { return (sockaddr&)fMask; }
const sockaddr& Broadcast() const
{ return (sockaddr&)fBroadcast; }
const sockaddr& Destination() const
{ return (sockaddr&)fBroadcast; }
void SetFlags(uint32 flags);
uint32 Flags() const { return fFlags; }
@ -47,9 +44,9 @@ public:
private:
int32 fIndex;
BNetworkAddress fAddress;
BNetworkAddress fMask;
BNetworkAddress fBroadcast;
sockaddr_storage fAddress;
sockaddr_storage fMask;
sockaddr_storage fBroadcast;
uint32 fFlags;
};

View File

@ -357,9 +357,12 @@ NetworkStatusView::_ShowConfiguration(BMessage* message)
size_t boldLength = text.Length();
text << "\n" << B_TRANSLATE("Address") << ": " << address.Address().ToString();
text << "\n" << B_TRANSLATE("Broadcast") << ": " << address.Broadcast().ToString();
text << "\n" << B_TRANSLATE("Netmask") << ": " << address.Mask().ToString();
text << "\n" << B_TRANSLATE("Address") << ": "
<< BNetworkAddress(address.Address()).ToString();
text << "\n" << B_TRANSLATE("Broadcast") << ": "
<< BNetworkAddress(address.Broadcast()).ToString();
text << "\n" << B_TRANSLATE("Netmask") << ": "
<< BNetworkAddress(address.Mask()).ToString();
BAlert* alert = new BAlert(name, text.String(), B_TRANSLATE("OK"));
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);

View File

@ -474,20 +474,24 @@ list_interface_addresses(BNetworkInterface& interface, uint32 flags)
break;
const address_family* family
= address_family_for(address.Address().Family());
= address_family_for(address.Address().sa_family);
printf("\t%s addr: %s", family->name,
address.Address().ToString().String());
BNetworkAddress(address.Address()).ToString().String());
if ((flags & IFF_BROADCAST) != 0)
printf(", Bcast: %s", address.Broadcast().ToString().String());
if ((flags & IFF_BROADCAST) != 0) {
printf(", Bcast: %s",
BNetworkAddress(address.Broadcast()).ToString().String());
}
switch (family->preferred_format) {
case PREFER_OUTPUT_MASK:
printf(", Mask: %s", address.Mask().ToString().String());
printf(", Mask: %s",
BNetworkAddress(address.Mask()).ToString().String());
break;
case PREFER_OUTPUT_PREFIX_LENGTH:
printf(", Prefix Length: %zu", address.Mask().PrefixLength());
printf(", Prefix Length: %zu",
BNetworkAddress(address.Mask()).PrefixLength());
break;
}

View File

@ -11,13 +11,18 @@ for architectureObject in [ MultiArchSubDirSetup ] {
local architecture = $(TARGET_PACKAGING_ARCH) ;
UsePrivateSystemHeaders ;
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
local libnetwork = [ MultiArchDefaultGristFiles libnetwork.so ] ;
SharedLibrary $(libnetwork) :
getifaddrs.cpp
init.cpp
interfaces.cpp
socket.cpp
r5_compatibility.cpp
NetworkInterfaceAddress.cpp
:
<libbind!$(architecture)>libbind.o
[ TargetLibsupc++ ]

View File

@ -0,0 +1,135 @@
/*
* Copyright 2010, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include <NetworkInterface.h>
#include <errno.h>
#include <string.h>
#include <sys/sockio.h>
#include <AutoDeleter.h>
namespace BPrivate {
int
family_from_interface_address(const BNetworkInterfaceAddress& address)
{
if (address.Address().sa_family != AF_UNSPEC)
return address.Address().sa_family;
if (address.Mask().sa_family != AF_UNSPEC)
return address.Mask().sa_family;
if (address.Destination().sa_family != AF_UNSPEC)
return address.Destination().sa_family;
return AF_INET;
}
status_t
do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address,
bool readBack = false)
{
int family = AF_INET;
if (!readBack)
family = family_from_interface_address(address);
int socket = ::socket(family, SOCK_DGRAM, 0);
if (socket < 0)
return errno;
FileDescriptorCloser closer(socket);
ifaliasreq request;
strlcpy(request.ifra_name, name, IF_NAMESIZE);
request.ifra_index = address.Index();
request.ifra_flags = address.Flags();
memcpy(&request.ifra_addr, &address.Address(),
address.Address().sa_len);
memcpy(&request.ifra_mask, &address.Mask(),
address.Mask().sa_len);
memcpy(&request.ifra_broadaddr, &address.Broadcast(),
address.Broadcast().sa_len);
if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0)
return errno;
if (readBack) {
address.SetFlags(request.ifra_flags);
address.SetAddress((sockaddr&)request.ifra_addr);
address.SetMask((sockaddr&)request.ifra_mask);
address.SetBroadcast((sockaddr&)request.ifra_broadaddr);
}
return B_OK;
}
};
using namespace BPrivate;
// #pragma mark -
BNetworkInterfaceAddress::BNetworkInterfaceAddress()
:
fIndex(-1),
fFlags(0)
{
}
BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
{
}
status_t
BNetworkInterfaceAddress::SetTo(const char* name, int32 index)
{
fIndex = index;
return do_ifaliasreq(name, B_SOCKET_GET_ALIAS, *this, true);
}
void
BNetworkInterfaceAddress::SetAddress(const sockaddr& address)
{
memcpy(&fAddress, &address, address.sa_len);
}
void
BNetworkInterfaceAddress::SetMask(const sockaddr& mask)
{
memcpy(&fMask, &mask, mask.sa_len);
}
void
BNetworkInterfaceAddress::SetBroadcast(const sockaddr& broadcast)
{
memcpy(&fBroadcast, &broadcast, broadcast.sa_len);
}
void
BNetworkInterfaceAddress::SetDestination(const sockaddr& destination)
{
memcpy(&fBroadcast, &destination, destination.sa_len);
}
void
BNetworkInterfaceAddress::SetFlags(uint32 flags)
{
fFlags = flags;
}

View File

@ -0,0 +1,141 @@
/*
* Copyright 2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#include <ifaddrs.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sockio.h>
#include <unistd.h>
#include <AutoDeleter.h>
#include <NetworkAddress.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
// This structure has an ifaddrs and all the information it refers to. We can
// allocate this in a single call to the allocator instead of allocating each
// address, the name, and the ifaddr struct itself separately. This simplifies
// the error handling and the freeing of the structure, and reduces the stress
// on the memory allocator.
struct IfaddrContainer {
ifaddrs header;
sockaddr_storage address;
sockaddr_storage mask;
sockaddr_storage destination;
char name[0];
};
int
getifaddrs(struct ifaddrs **ifap)
{
if (ifap == NULL) {
errno = B_BAD_VALUE;
return -1;
}
// get a list of all interfaces
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0)
return -1;
FileDescriptorCloser closer(socket);
ifconf config;
config.ifc_len = sizeof(config.ifc_value);
if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
return -1;
size_t count = (size_t)config.ifc_value;
if (count == 0) {
errno = B_BAD_VALUE;
return -1;
}
char* buffer = (char*)malloc(count * sizeof(struct ifreq));
if (buffer == NULL) {
errno = B_NO_MEMORY;
return -1;
}
MemoryDeleter deleter(buffer);
config.ifc_len = count * sizeof(struct ifreq);
config.ifc_buf = buffer;
if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
return -1;
ifreq* interfaces = (ifreq*)buffer;
ifreq* end = (ifreq*)(buffer + config.ifc_len);
struct ifaddrs* previous = NULL;
struct ifaddrs* current = NULL;
for (uint32 i = 0; interfaces < end; i++) {
BNetworkInterfaceAddress address;
int32 j = 0;
while (address.SetTo(interfaces->ifr_name, j++) == B_OK) {
IfaddrContainer* container = (IfaddrContainer*)malloc(
sizeof(IfaddrContainer) + strlen(interfaces->ifr_name) + 1);
if (container == NULL) {
freeifaddrs(previous);
errno = B_NO_MEMORY;
return -1;
}
current = &container->header;
strcpy(container->name, interfaces->ifr_name);
current->ifa_name = container->name;
current->ifa_flags = address.Flags();
memcpy(&container->address, &address.Address(),
address.Address().sa_len);
current->ifa_addr = (sockaddr*)&container->address;
memcpy(&container->mask, &address.Mask(), address.Mask().sa_len);
current->ifa_netmask = (sockaddr*)&container->mask;
memcpy(&container->destination, &address.Destination(),
address.Destination().sa_len);
current->ifa_dstaddr = (sockaddr*)&container->destination;
current->ifa_data = NULL;
// Could point to extra information, if we have something to
// add.
// Chain this interface with the next one
current->ifa_next = previous;
previous = current;
}
}
*ifap = current;
return B_OK;
}
void
freeifaddrs(struct ifaddrs *ifa)
{
// Since each item was allocated as a single chunk using the IfaddrContainer,
// all we need to do is free that.
struct ifaddrs* next;
while (ifa != NULL) {
next = ifa->ifa_next;
free(ifa);
ifa = next;
}
}

View File

@ -197,7 +197,7 @@ BAbstractSocket::Connect(const BNetworkAddress& peer, int type,
return fInitStatus;
BNetworkAddress normalized = peer;
if (connect(fSocket, normalized, normalized.Length()) != 0) {
if (connect(fSocket, &normalized.SockAddr(), normalized.Length()) != 0) {
TRACE("%p: connecting to %s: %s\n", this,
normalized.ToString().c_str(), strerror(errno));
return fInitStatus = errno;

View File

@ -127,9 +127,10 @@ BDatagramSocket::Write(const void* buffer, size_t size)
{
ssize_t bytesSent;
if (!fIsConnected)
bytesSent = sendto(Socket(), buffer, size, 0, fPeer, fPeer.Length());
else
if (!fIsConnected) {
bytesSent = sendto(Socket(), buffer, size, 0, &fPeer.SockAddr(),
fPeer.Length());
} else
bytesSent = send(Socket(), buffer, size, 0);
if (bytesSent < 0) {

View File

@ -79,7 +79,6 @@ for architectureObject in [ MultiArchSubDirSetup ] {
HttpResult.cpp
HttpTime.cpp
getifaddrs.cpp
notifications.cpp
$(md5Sources)

View File

@ -1188,24 +1188,12 @@ BNetworkAddress::operator sockaddr*()
}
BNetworkAddress::operator const sockaddr*()
{
return (sockaddr*)&fAddress;
}
BNetworkAddress::operator sockaddr&()
{
return (sockaddr&)fAddress;
}
BNetworkAddress::operator const sockaddr&()
{
return (sockaddr&)fAddress;
}
// #pragma mark - private

View File

@ -8,25 +8,25 @@
#include <errno.h>
#include <net/if.h>
#include <string.h>
#include <sys/sockio.h>
#include <AutoDeleter.h>
#include <Messenger.h>
#include <NetServer.h>
#include <NetworkAddress.h>
#include <RouteSupport.h>
static int
family_from_interface_address(const BNetworkInterfaceAddress& address)
{
if (address.Address().Family() != AF_UNSPEC)
return address.Address().Family();
if (address.Mask().Family() != AF_UNSPEC)
return address.Mask().Family();
if (address.Destination().Family() != AF_UNSPEC)
return address.Destination().Family();
return AF_INET;
}
namespace BPrivate {
status_t do_ifaliasreq(const char* name, int32 option,
BNetworkInterfaceAddress& address, bool readBack = false);
int family_from_interface_address(const BNetworkInterfaceAddress& address);
};
using namespace BPrivate;
static int
@ -45,46 +45,6 @@ family_from_route(const route_entry& route)
}
static status_t
do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address,
bool readBack = false)
{
int family = AF_INET;
if (!readBack)
family = family_from_interface_address(address);
int socket = ::socket(family, SOCK_DGRAM, 0);
if (socket < 0)
return errno;
FileDescriptorCloser closer(socket);
ifaliasreq request;
strlcpy(request.ifra_name, name, IF_NAMESIZE);
request.ifra_index = address.Index();
request.ifra_flags = address.Flags();
memcpy(&request.ifra_addr, &address.Address().SockAddr(),
address.Address().Length());
memcpy(&request.ifra_mask, &address.Mask().SockAddr(),
address.Mask().Length());
memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(),
address.Broadcast().Length());
if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0)
return errno;
if (readBack) {
address.SetFlags(request.ifra_flags);
address.Address().SetTo(request.ifra_addr);
address.Mask().SetTo(request.ifra_mask);
address.Broadcast().SetTo(request.ifra_broadaddr);
}
return B_OK;
}
static status_t
do_ifaliasreq(const char* name, int32 option,
const BNetworkInterfaceAddress& address)
@ -115,65 +75,6 @@ do_request(int family, T& request, const char* name, int option)
// #pragma mark -
BNetworkInterfaceAddress::BNetworkInterfaceAddress()
:
fIndex(-1),
fFlags(0)
{
}
BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
{
}
status_t
BNetworkInterfaceAddress::SetTo(const BNetworkInterface& interface, int32 index)
{
fIndex = index;
return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true);
}
void
BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address)
{
fAddress = address;
}
void
BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask)
{
fMask = mask;
}
void
BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast)
{
fBroadcast = broadcast;
}
void
BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination)
{
fBroadcast = destination;
}
void
BNetworkInterfaceAddress::SetFlags(uint32 flags)
{
fFlags = flags;
}
// #pragma mark -
BNetworkInterface::BNetworkInterface()
{
Unset();
@ -380,7 +281,7 @@ BNetworkInterface::CountAddresses() const
status_t
BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address)
{
return address.SetTo(*this, index);
return address.SetTo(Name(), index);
}
@ -445,7 +346,7 @@ status_t
BNetworkInterface::AddAddress(const BNetworkAddress& local)
{
BNetworkInterfaceAddress address;
address.SetAddress(local);
address.SetAddress(local.SockAddr());
return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
}
@ -462,8 +363,7 @@ status_t
BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address)
{
ifreq request;
memcpy(&request.ifr_addr, &address.Address().SockAddr(),
address.Address().Length());
memcpy(&request.ifr_addr, &address.Address(), address.Address().sa_len);
return do_request(family_from_interface_address(address), request, Name(),
B_SOCKET_REMOVE_ALIAS);

View File

@ -1,103 +0,0 @@
/*
* Copyright 2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <AutoDeleter.h>
#include <NetworkAddress.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include "compatibility/bsd/ifaddrs.h"
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(std::nothrow) BNetworkInterface();
if (interface == NULL) {
errno = B_NO_MEMORY;
return -1;
}
while (roster.GetNextInterface(&cookie, *interface) == B_OK) {
BNetworkInterfaceAddress address;
int32 i = 0;
while (interface->GetAddressAt(i++, address) == B_OK) {
if (interface == NULL) {
freeifaddrs(previous);
errno = B_NO_MEMORY;
return -1;
}
current = new(std::nothrow) ifaddrs();
if (current == NULL) {
freeifaddrs(previous);
errno = B_NO_MEMORY;
return -1;
}
// 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(std::nothrow) 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;
}
}

View File

@ -297,16 +297,16 @@ NetworkSettings::SetConfiguration()
BNetworkInterfaceAddress interfaceConfig;
fNetworkInterface->GetAddressAt(zeroAddr,
interfaceConfig);
interfaceConfig.SetAddress(fAddress[inet_id]);
interfaceConfig.SetMask(fNetmask[inet_id]);
interfaceConfig.SetAddress(fAddress[inet_id].SockAddr());
interfaceConfig.SetMask(fNetmask[inet_id].SockAddr());
fNetworkInterface->SetAddress(interfaceConfig);
} else {
// TODO : test this case (no address set for this protocol)
printf("no zeroAddr found for %s(%d), found %" B_PRIu32 "\n",
fProtocols[index].name, inet_id, zeroAddr);
BNetworkInterfaceAddress interfaceConfig;
interfaceConfig.SetAddress(fAddress[inet_id]);
interfaceConfig.SetMask(fNetmask[inet_id]);
interfaceConfig.SetAddress(fAddress[inet_id].SockAddr());
interfaceConfig.SetMask(fNetmask[inet_id].SockAddr());
fNetworkInterface->AddAddress(interfaceConfig);
}

View File

@ -527,7 +527,7 @@ DHCPClient::_Negotiate(dhcp_state state)
option = 1;
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
if (bind(socket, local, local.Length()) < 0) {
if (bind(socket, &local.SockAddr(), local.Length()) < 0) {
close(socket);
return errno;
}

View File

@ -613,12 +613,12 @@ NetServer::_ConfigureInterface(BMessage& message)
if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()) {
BNetworkInterfaceAddress interfaceAddress;
interfaceAddress.SetAddress(address);
interfaceAddress.SetMask(mask);
interfaceAddress.SetAddress(address.SockAddr());
interfaceAddress.SetMask(mask.SockAddr());
if (!broadcast.IsEmpty())
interfaceAddress.SetBroadcast(broadcast);
interfaceAddress.SetBroadcast(broadcast.SockAddr());
else if (!peer.IsEmpty())
interfaceAddress.SetDestination(peer);
interfaceAddress.SetDestination(peer.SockAddr());
status_t status = interface.SetAddress(interfaceAddress);
if (status != B_OK) {
@ -949,9 +949,9 @@ NetServer::_ConfigureIPv6LinkLocal(const char* name)
}
BNetworkInterfaceAddress interfaceAddress;
interfaceAddress.SetAddress(localLinkAddress);
interfaceAddress.SetMask(localLinkMask);
interfaceAddress.SetBroadcast(localLinkMask);
interfaceAddress.SetAddress(localLinkAddress.SockAddr());
interfaceAddress.SetMask(localLinkMask.SockAddr());
interfaceAddress.SetBroadcast(localLinkMask.SockAddr());
/* TODO: Duplicate Address Detection. (DAD)
Need to blast an icmp packet over the IPv6 network from :: to ensure

View File

@ -274,8 +274,8 @@ Services::_StartService(struct service& service)
address.socket = socket(address.family, address.type, address.protocol);
if (address.socket < 0
|| bind(address.socket, address.address, address.address.Length())
< 0
|| bind(address.socket, &address.address.SockAddr(),
address.address.Length()) < 0
|| fcntl(address.socket, F_SETFD, FD_CLOEXEC) < 0) {
failed = true;
break;