* Copyright 2010-2015, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include <NetworkAddress.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/sockio.h>
* Benefits include faster execution time as the builtin
* uses a bitcounting cpu instruction if it exists
*/
#if __GNUC__ > 3
# define addr_bitcount(bitfield) __builtin_popcount(bitfield)
#else
static ssize_t
addr_bitcount(uint32 bitfield)
{
ssize_t result = 0;
for (uint8 i = 32; i > 0; i--) {
if ((bitfield & (1 << (i - 1))) == 0)
break;
result++;
}
return result;
}
#endif
static uint8
from_hex(char hex)
{
if (isdigit(hex))
return hex - '0';
return tolower(hex) - 'a' + 10;
}
BNetworkAddress::BNetworkAddress()
{
Unset();
}
BNetworkAddress::BNetworkAddress(const char* host, uint16 port, uint32 flags)
{
fStatus = SetTo(host, port, flags);
}
BNetworkAddress::BNetworkAddress(const char* host, const char* service,
uint32 flags)
{
fStatus = SetTo(host, service, flags);
}
BNetworkAddress::BNetworkAddress(int family, const char* host, uint16 port,
uint32 flags)
{
fStatus = SetTo(family, host, port, flags);
}
BNetworkAddress::BNetworkAddress(int family, const char* host,
const char* service, uint32 flags)
{
fStatus = SetTo(family, host, service, flags);
}
BNetworkAddress::BNetworkAddress(const sockaddr& address)
{
SetTo(address);
}
BNetworkAddress::BNetworkAddress(const sockaddr_storage& address)
{
SetTo(address);
}
BNetworkAddress::BNetworkAddress(const sockaddr_in& address)
{
SetTo(address);
}
BNetworkAddress::BNetworkAddress(const sockaddr_in6& address)
{
SetTo(address);
}
BNetworkAddress::BNetworkAddress(const sockaddr_dl& address)
{
SetTo(address);
}
BNetworkAddress::BNetworkAddress(in_addr_t address, uint16 port)
{
SetTo(address, port);
}
BNetworkAddress::BNetworkAddress(const in6_addr& address, uint16 port)
{
SetTo(address, port);
}
BNetworkAddress::BNetworkAddress(const BNetworkAddress& other)
:
fAddress(other.fAddress),
fStatus(other.fStatus),
fHostName(other.fHostName)
{
}
BNetworkAddress::~BNetworkAddress()
{
}
status_t
BNetworkAddress::InitCheck() const
{
return fStatus;
}
void
BNetworkAddress::Unset()
{
fAddress.ss_family = AF_UNSPEC;
fAddress.ss_len = 2;
fHostName = "";
fStatus = B_OK;
}
status_t
BNetworkAddress::SetTo(const char* host, uint16 port, uint32 flags)
{
BReference<const BNetworkAddressResolver> resolver
= BNetworkAddressResolver::Resolve(host, port, flags);
if (!resolver.IsSet())
return B_NO_MEMORY;
status_t status = resolver->InitCheck();
if (status != B_OK)
return status;
uint32 cookie = 0;
status = resolver->GetNextAddress(AF_INET6, &cookie, *this);
if (status != B_OK) {
cookie = 0;
status = resolver->GetNextAddress(&cookie, *this);
if (status != B_OK)
Unset();
}
fHostName = host;
fStatus = status;
return status;
}
status_t
BNetworkAddress::SetTo(const char* host, const char* service, uint32 flags)
{
BReference<const BNetworkAddressResolver> resolver
= BNetworkAddressResolver::Resolve(host, service, flags);
if (!resolver.IsSet())
return B_NO_MEMORY;
status_t status = resolver->InitCheck();
if (status != B_OK)
return status;
uint32 cookie = 0;
status = resolver->GetNextAddress(AF_INET6, &cookie, *this);
if (status != B_OK) {
cookie = 0;
status = resolver->GetNextAddress(&cookie, *this);
if (status != B_OK)
Unset();
}
fHostName = host;
fStatus = status;
return status;
}
status_t
BNetworkAddress::SetTo(int family, const char* host, uint16 port, uint32 flags)
{
if (family == AF_LINK) {
if (port != 0)
return B_BAD_VALUE;
return _ParseLinkAddress(host);
}
BReference<const BNetworkAddressResolver> resolver
= BNetworkAddressResolver::Resolve(family, host, port, flags);
if (!resolver.IsSet())
return B_NO_MEMORY;
status_t status = resolver->InitCheck();
if (status != B_OK)
return status;
uint32 cookie = 0;
status = resolver->GetNextAddress(&cookie, *this);
if (status != B_OK)
Unset();
fHostName = host;
fStatus = status;
return status;
}
status_t
BNetworkAddress::SetTo(int family, const char* host, const char* service,
uint32 flags)
{
if (family == AF_LINK) {
if (service != NULL)
return B_BAD_VALUE;
return _ParseLinkAddress(host);
}
BReference<const BNetworkAddressResolver> resolver
= BNetworkAddressResolver::Resolve(family, host, service, flags);
if (!resolver.IsSet())
return B_NO_MEMORY;
status_t status = resolver->InitCheck();
if (status != B_OK)
return status;
uint32 cookie = 0;
status = resolver->GetNextAddress(&cookie, *this);
if (status != B_OK)
Unset();
fHostName = host;
fStatus = status;
return status;
}
void
BNetworkAddress::SetTo(const sockaddr& address)
{
if (address.sa_family == AF_UNSPEC) {
Unset();
return;
}
size_t length = min_c(sizeof(sockaddr_storage), address.sa_len);
switch (address.sa_family) {
case AF_INET:
length = sizeof(sockaddr_in);
break;
case AF_INET6:
length = sizeof(sockaddr_in6);
break;
case AF_LINK:
{
sockaddr_dl& link = (sockaddr_dl&)address;
length = sizeof(sockaddr_dl) - sizeof(link.sdl_data) + link.sdl_alen
+ link.sdl_nlen + link.sdl_slen;
break;
}
}
SetTo(address, length);
}
void
BNetworkAddress::SetTo(const sockaddr& address, size_t length)
{
if (address.sa_family == AF_UNSPEC || length == 0) {
Unset();
return;
}
memcpy(&fAddress, &address, length);
fAddress.ss_len = length;
fStatus = B_OK;
}
void
BNetworkAddress::SetTo(const sockaddr_storage& address)
{
SetTo((sockaddr&)address);
}
void
BNetworkAddress::SetTo(const sockaddr_in& address)
{
SetTo((sockaddr&)address);
}
void
BNetworkAddress::SetTo(const sockaddr_in6& address)
{
SetTo((sockaddr&)address);
}
void
BNetworkAddress::SetTo(const sockaddr_dl& address)
{
SetTo((sockaddr&)address);
}
void
BNetworkAddress::SetTo(in_addr_t inetAddress, uint16 port)
{
memset(&fAddress, 0, sizeof(sockaddr_storage));
fAddress.ss_family = AF_INET;
fAddress.ss_len = sizeof(sockaddr_in);
SetAddress(inetAddress);
SetPort(port);
fStatus = B_OK;
}
void
BNetworkAddress::SetTo(const in6_addr& inet6Address, uint16 port)
{
memset(&fAddress, 0, sizeof(sockaddr_storage));
fAddress.ss_family = AF_INET6;
fAddress.ss_len = sizeof(sockaddr_in6);
SetAddress(inet6Address);
SetPort(port);
fStatus = B_OK;
}
void
BNetworkAddress::SetTo(const BNetworkAddress& other)
{
fAddress = other.fAddress;
fStatus = other.fStatus;
fHostName = other.fHostName;
}
status_t
BNetworkAddress::SetToBroadcast(int family, uint16 port)
{
if (family != AF_INET)
return fStatus = B_NOT_SUPPORTED;
SetTo(INADDR_BROADCAST, port);
return fStatus;
}
status_t
BNetworkAddress::SetToLocal(int family, uint16 port)
{
return fStatus = B_NOT_SUPPORTED;
}
status_t
BNetworkAddress::SetToLoopback(int family, uint16 port)
{
switch (family) {
case AF_UNSPEC:
case AF_INET:
SetTo(htonl(INADDR_LOOPBACK), port);
break;
case AF_INET6:
SetTo(in6addr_loopback, port);
break;
default:
return fStatus = B_NOT_SUPPORTED;
}
return fStatus;
}
status_t
BNetworkAddress::SetToMask(int family, uint32 prefixLength)
{
switch (family) {
case AF_INET:
{
if (prefixLength > 32)
return B_BAD_VALUE;
sockaddr_in& mask = (sockaddr_in&)fAddress;
memset(&fAddress, 0, sizeof(sockaddr_storage));
mask.sin_family = AF_INET;
mask.sin_len = sizeof(sockaddr_in);
uint32 hostMask = 0;
for (uint8 i = 32; i > 32 - prefixLength; i--)
hostMask |= 1 << (i - 1);
mask.sin_addr.s_addr = htonl(hostMask);
break;
}
case AF_INET6:
{
if (prefixLength > 128)
return B_BAD_VALUE;
sockaddr_in6& mask = (sockaddr_in6&)fAddress;
memset(&fAddress, 0, sizeof(sockaddr_storage));
mask.sin6_family = AF_INET6;
mask.sin6_len = sizeof(sockaddr_in6);
for (uint8 i = 0; i < sizeof(in6_addr); i++, prefixLength -= 8) {
if (prefixLength < 8) {
mask.sin6_addr.s6_addr[i]
= (uint8)(0xff << (8 - prefixLength));
break;
}
mask.sin6_addr.s6_addr[i] = 0xff;
}
break;
}
default:
return B_NOT_SUPPORTED;
}
return fStatus = B_OK;
}
status_t
BNetworkAddress::SetToWildcard(int family, uint16 port)
{
switch (family) {
case AF_INET:
SetTo(INADDR_ANY, port);
break;
case AF_INET6:
SetTo(in6addr_any, port);
break;
default:
return B_NOT_SUPPORTED;
}
return fStatus;
}
status_t
BNetworkAddress::SetAddress(in_addr_t inetAddress)
{
if (Family() != AF_INET)
return B_BAD_VALUE;
sockaddr_in& address = (sockaddr_in&)fAddress;
address.sin_addr.s_addr = inetAddress;
return B_OK;
}
status_t
BNetworkAddress::SetAddress(const in6_addr& inet6Address)
{
if (Family() != AF_INET6)
return B_BAD_VALUE;
sockaddr_in6& address = (sockaddr_in6&)fAddress;
memcpy(address.sin6_addr.s6_addr, &inet6Address,
sizeof(address.sin6_addr.s6_addr));
return B_OK;
}
void
BNetworkAddress::SetPort(uint16 port)
{
switch (fAddress.ss_family) {
case AF_INET:
((sockaddr_in&)fAddress).sin_port = htons(port);
break;
case AF_INET6:
((sockaddr_in6&)fAddress).sin6_port = htons(port);
break;
default:
break;
}
}
void
BNetworkAddress::SetToLinkLevel(const uint8* address, size_t length)
{
sockaddr_dl& link = (sockaddr_dl&)fAddress;
memset(&link, 0, sizeof(sockaddr_dl));
link.sdl_family = AF_LINK;
link.sdl_alen = length;
memcpy(LLADDR(&link), address, length);
link.sdl_len = sizeof(sockaddr_dl);
if (length > sizeof(link.sdl_data))
link.sdl_len += length - sizeof(link.sdl_data);
fStatus = B_OK;
}
void
BNetworkAddress::SetToLinkLevel(const char* name)
{
sockaddr_dl& link = (sockaddr_dl&)fAddress;
memset(&link, 0, sizeof(sockaddr_dl));
size_t length = strlen(name);
if (length > sizeof(fAddress) - sizeof(sockaddr_dl) + sizeof(link.sdl_data))
length = sizeof(fAddress) - sizeof(sockaddr_dl) + sizeof(link.sdl_data);
link.sdl_family = AF_LINK;
link.sdl_nlen = length;
memcpy(link.sdl_data, name, link.sdl_nlen);
link.sdl_len = sizeof(sockaddr_dl);
if (link.sdl_nlen > sizeof(link.sdl_data))
link.sdl_len += link.sdl_nlen - sizeof(link.sdl_data);
fStatus = B_OK;
}
void
BNetworkAddress::SetToLinkLevel(uint32 index)
{
sockaddr_dl& link = (sockaddr_dl&)fAddress;
memset(&link, 0, sizeof(sockaddr_dl));
link.sdl_family = AF_LINK;
link.sdl_len = sizeof(sockaddr_dl);
link.sdl_index = index;
fStatus = B_OK;
}
void
BNetworkAddress::SetLinkLevelIndex(uint32 index)
{
sockaddr_dl& link = (sockaddr_dl&)fAddress;
link.sdl_index = index;
}
void
BNetworkAddress::SetLinkLevelType(uint8 type)
{
sockaddr_dl& link = (sockaddr_dl&)fAddress;
link.sdl_type = type;
}
void
BNetworkAddress::SetLinkLevelFrameType(uint16 frameType)
{
sockaddr_dl& link = (sockaddr_dl&)fAddress;
link.sdl_e_type = htons(frameType);
}
int
BNetworkAddress::Family() const
{
return fAddress.ss_family;
}
uint16
BNetworkAddress::Port() const
{
switch (fAddress.ss_family) {
case AF_INET:
return ntohs(((sockaddr_in&)fAddress).sin_port);
case AF_INET6:
return ntohs(((sockaddr_in6&)fAddress).sin6_port);
default:
return 0;
}
}
size_t
BNetworkAddress::Length() const
{
return fAddress.ss_len;
}
const sockaddr&
BNetworkAddress::SockAddr() const
{
return (const sockaddr&)fAddress;
}
sockaddr&
BNetworkAddress::SockAddr()
{
return (sockaddr&)fAddress;
}
bool
BNetworkAddress::IsEmpty() const
{
if (fAddress.ss_len == 0)
return true;
switch (fAddress.ss_family) {
case AF_UNSPEC:
return true;
case AF_INET:
{
sockaddr_in& sin = (sockaddr_in&)fAddress;
return sin.sin_addr.s_addr == INADDR_ANY && sin.sin_port == 0;
}
case AF_INET6:
{
sockaddr_in6& sin6 = (sockaddr_in6&)fAddress;
return IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)
&& sin6.sin6_port == 0;
}
default:
return false;
}
}
bool
BNetworkAddress::IsWildcard() const
{
switch (fAddress.ss_family) {
case AF_INET:
return ((sockaddr_in&)fAddress).sin_addr.s_addr == INADDR_ANY;
case AF_INET6:
return !memcmp(&((sockaddr_in6&)fAddress).sin6_addr, &in6addr_any,
sizeof(in6_addr));
default:
return false;
}
}
bool
BNetworkAddress::IsBroadcast() const
{
switch (fAddress.ss_family) {
case AF_INET:
return ((sockaddr_in&)fAddress).sin_addr.s_addr == INADDR_BROADCAST;
case AF_INET6:
return IN6_IS_ADDR_MULTICAST(&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsMulticast() const
{
switch (fAddress.ss_family) {
case AF_INET:
return IN_MULTICAST(((sockaddr_in&)fAddress).sin_addr.s_addr);
case AF_INET6:
return IN6_IS_ADDR_MULTICAST(&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsMulticastGlobal() const
{
switch (fAddress.ss_family) {
case AF_INET6:
return IN6_IS_ADDR_MC_GLOBAL(&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsMulticastNodeLocal() const
{
switch (fAddress.ss_family) {
case AF_INET6:
return IN6_IS_ADDR_MC_NODELOCAL(
&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsMulticastLinkLocal() const
{
switch (fAddress.ss_family) {
case AF_INET6:
return IN6_IS_ADDR_MC_LINKLOCAL(
&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsMulticastSiteLocal() const
{
switch (fAddress.ss_family) {
case AF_INET6:
return IN6_IS_ADDR_MC_SITELOCAL(
&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsMulticastOrgLocal() const
{
switch (fAddress.ss_family) {
case AF_INET6:
return IN6_IS_ADDR_MC_ORGLOCAL(
&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsLinkLocal() const
{
switch (fAddress.ss_family) {
case AF_INET6:
return IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsSiteLocal() const
{
switch (fAddress.ss_family) {
case AF_INET6:
return IN6_IS_ADDR_SITELOCAL(&((sockaddr_in6&)fAddress).sin6_addr);
default:
return false;
}
}
bool
BNetworkAddress::IsLocal() const
{
BNetworkRoster& roster = BNetworkRoster::Default();
BNetworkInterface interface;
uint32 cookie = 0;
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
int32 count = interface.CountAddresses();
for (int32 j = 0; j < count; j++) {
BNetworkInterfaceAddress address;
if (interface.GetAddressAt(j, address) != B_OK)
break;
if (Equals(address.Address(), false))
return true;
}
}
return false;
}
ssize_t
BNetworkAddress::PrefixLength() const
{
switch (fAddress.ss_family) {
case AF_INET:
{
sockaddr_in& mask = (sockaddr_in&)fAddress;
uint32 hostMask = ntohl(mask.sin_addr.s_addr);
return addr_bitcount(hostMask);
}
case AF_INET6:
{
sockaddr_in6& mask = (sockaddr_in6&)fAddress;
ssize_t result = 0;
for (uint8 i = 0; i < sizeof(in6_addr); i++) {
for (uint8 j = 0; j < 8; j++) {
if (!(mask.sin6_addr.s6_addr[i] & (1 << j)))
return result;
result++;
}
}
return 128;
}
default:
return B_NOT_SUPPORTED;
}
}
uint32
BNetworkAddress::LinkLevelIndex() const
{
return ((sockaddr_dl&)fAddress).sdl_index;
}
BString
BNetworkAddress::LinkLevelInterface() const
{
sockaddr_dl& address = (sockaddr_dl&)fAddress;
if (address.sdl_nlen == 0)
return "";
BString name;
name.SetTo((const char*)address.sdl_data, address.sdl_nlen);
return name;
}
uint8
BNetworkAddress::LinkLevelType() const
{
return ((sockaddr_dl&)fAddress).sdl_type;
}
uint16
BNetworkAddress::LinkLevelFrameType() const
{
return ntohs(((sockaddr_dl&)fAddress).sdl_e_type);
}
uint8*
BNetworkAddress::LinkLevelAddress() const
{
return LLADDR(&(sockaddr_dl&)fAddress);
}
size_t
BNetworkAddress::LinkLevelAddressLength() const
{
return ((sockaddr_dl&)fAddress).sdl_alen;
}
status_t
BNetworkAddress::ResolveForDestination(const BNetworkAddress& destination)
{
if (!IsWildcard())
return B_OK;
if (destination.fAddress.ss_family != fAddress.ss_family)
return B_BAD_VALUE;
char buffer[2048];
memset(buffer, 0, sizeof(buffer));
route_entry* route = (route_entry*)buffer;
route->destination = (sockaddr*)&destination.fAddress;
int socket = ::socket(fAddress.ss_family, SOCK_DGRAM, 0);
if (socket < 0)
return errno;
if (ioctl(socket, SIOCGETRT, route, sizeof(buffer)) != 0) {
close(socket);
return errno;
}
uint16 port = Port();
memcpy(&fAddress, route->source, sizeof(sockaddr_storage));
SetPort(port);
close(socket);
return B_OK;
}
status_t
BNetworkAddress::ResolveTo(const BNetworkAddress& address)
{
if (!IsWildcard())
return B_OK;
if (address.fAddress.ss_family != fAddress.ss_family)
return B_BAD_VALUE;
uint16 port = Port();
*this = address;
SetPort(port);
return B_OK;
}
BString
BNetworkAddress::ToString(bool includePort) const
{
char buffer[512];
switch (fAddress.ss_family) {
case AF_INET:
inet_ntop(AF_INET, &((sockaddr_in&)fAddress).sin_addr, buffer,
sizeof(buffer));
break;
case AF_INET6:
inet_ntop(AF_INET6, &((sockaddr_in6&)fAddress).sin6_addr,
buffer, sizeof(buffer));
break;
case AF_LINK:
{
uint8 *byte = LinkLevelAddress();
char* target = buffer;
int bytesLeft = sizeof(buffer);
target[0] = '\0';
for (size_t i = 0; i < LinkLevelAddressLength(); i++) {
if (i != 0 && bytesLeft > 1) {
target[0] = ':';
target[1] = '\0';
target++;
bytesLeft--;
}
int bytesWritten = snprintf(target, bytesLeft, "%02x", byte[i]);
if (bytesWritten >= bytesLeft)
break;
target += bytesWritten;
bytesLeft -= bytesWritten;
}
break;
}
default:
return "";
}
BString address = buffer;
if (includePort && Port() != 0) {
if (fAddress.ss_family == AF_INET6) {
address = "[";
address += buffer;
address += "]";
}
snprintf(buffer, sizeof(buffer), ":%u", Port());
address += buffer;
}
return address;
}
BString
BNetworkAddress::HostName() const
{
return fHostName;
}
BString
BNetworkAddress::ServiceName() const
{
BString portName;
portName << Port();
return portName;
}
bool
BNetworkAddress::Equals(const BNetworkAddress& other, bool includePort) const
{
if (IsEmpty() && other.IsEmpty())
return true;
if (Family() != other.Family()
|| (includePort && Port() != other.Port())) {
return false;
}
switch (fAddress.ss_family) {
case AF_INET:
{
sockaddr_in& address = (sockaddr_in&)fAddress;
sockaddr_in& otherAddress = (sockaddr_in&)other.fAddress;
return memcmp(&address.sin_addr, &otherAddress.sin_addr,
sizeof(address.sin_addr)) == 0;
}
case AF_INET6:
{
sockaddr_in6& address = (sockaddr_in6&)fAddress;
sockaddr_in6& otherAddress = (sockaddr_in6&)other.fAddress;
return memcmp(&address.sin6_addr, &otherAddress.sin6_addr,
sizeof(address.sin6_addr)) == 0;
}
default:
if (fAddress.ss_len != other.fAddress.ss_len)
return false;
return memcmp(&fAddress, &other.fAddress, fAddress.ss_len);
}
}
bool
BNetworkAddress::IsFixedSize() const
{
return false;
}
type_code
BNetworkAddress::TypeCode() const
{
return B_NETWORK_ADDRESS_TYPE;
}
ssize_t
BNetworkAddress::FlattenedSize() const
{
return Length();
}
status_t
BNetworkAddress::Flatten(void* buffer, ssize_t size) const
{
if (buffer == NULL || size < FlattenedSize())
return B_BAD_VALUE;
memcpy(buffer, &fAddress, Length());
return B_OK;
}
status_t
BNetworkAddress::Unflatten(type_code code, const void* buffer, ssize_t size)
{
if (buffer == NULL || size < 2)
return fStatus = B_BAD_VALUE;
if (!AllowsTypeCode(code))
return fStatus = B_BAD_TYPE;
memcpy(&fAddress, buffer, min_c(size, (ssize_t)sizeof(fAddress)));
if (fAddress.ss_family != AF_UNSPEC && size < (ssize_t)sizeof(sockaddr))
return fStatus = B_BAD_VALUE;
return fStatus = B_OK;
}
BNetworkAddress&
BNetworkAddress::operator=(const BNetworkAddress& other)
{
memcpy(&fAddress, &other.fAddress, other.fAddress.ss_len);
fHostName = other.fHostName;
fStatus = other.fStatus;
return *this;
}
bool
BNetworkAddress::operator==(const BNetworkAddress& other) const
{
return Equals(other);
}
bool
BNetworkAddress::operator!=(const BNetworkAddress& other) const
{
return !Equals(other);
}
bool
BNetworkAddress::operator<(const BNetworkAddress& other) const
{
if (Family() < other.Family())
return true;
if (Family() > other.Family())
return false;
int compare;
switch (fAddress.ss_family) {
default:
case AF_INET:
{
sockaddr_in& address = (sockaddr_in&)fAddress;
sockaddr_in& otherAddress = (sockaddr_in&)other.fAddress;
compare = memcmp(&address.sin_addr, &otherAddress.sin_addr,
sizeof(address.sin_addr));
break;
}
case AF_INET6:
{
sockaddr_in6& address = (sockaddr_in6&)fAddress;
sockaddr_in6& otherAddress = (sockaddr_in6&)other.fAddress;
compare = memcmp(&address.sin6_addr, &otherAddress.sin6_addr,
sizeof(address.sin6_addr));
break;
}
case AF_LINK:
if (LinkLevelAddressLength() < other.LinkLevelAddressLength())
return true;
if (LinkLevelAddressLength() > other.LinkLevelAddressLength())
return true;
compare = memcmp(LinkLevelAddress(), other.LinkLevelAddress(),
LinkLevelAddressLength());
break;
}
if (compare < 0)
return true;
if (compare > 0)
return false;
return Port() < other.Port();
}
BNetworkAddress::operator const sockaddr*() const
{
return (const sockaddr*)&fAddress;
}
BNetworkAddress::operator const sockaddr&() const
{
return (const sockaddr&)fAddress;
}
BNetworkAddress::operator sockaddr*()
{
return (sockaddr*)&fAddress;
}
BNetworkAddress::operator const sockaddr*()
{
return (sockaddr*)&fAddress;
}
BNetworkAddress::operator sockaddr&()
{
return (sockaddr&)fAddress;
}
BNetworkAddress::operator const sockaddr&()
{
return (sockaddr&)fAddress;
}
status_t
BNetworkAddress::_ParseLinkAddress(const char* address)
{
if (address == NULL)
return B_BAD_VALUE;
uint8 linkAddress[128];
uint32 length = 0;
while (length < sizeof(linkAddress)) {
if (!isxdigit(address[0]) || !isxdigit(address[1]))
return B_BAD_VALUE;
linkAddress[length++] = (from_hex(address[0]) << 4)
| from_hex(address[1]);
if (address[2] == '\0')
break;
if (address[2] != ':')
return B_BAD_VALUE;
address += 3;
}
fHostName = address;
SetToLinkLevel(linkAddress, length);
return B_OK;
}