From c2808ea7b2da2e03373962bc413c3c1c73a70e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 9 Aug 2010 16:31:40 +0000 Subject: [PATCH] * Adapted API as needed, and implemented most of the C++ API - it's completely untested at this point, though. * Will port ifconfig, NetworkStatus, and the Network preferences application later in order to test the API. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37988 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/net/NetworkAddress.h | 32 +- headers/os/net/NetworkInterface.h | 21 +- headers/os/net/NetworkRoster.h | 11 +- src/kits/network/libnetapi/Jamfile | 2 +- src/kits/network/libnetapi/NetworkAddress.cpp | 969 ++++++++++++++++++ .../network/libnetapi/NetworkInterface.cpp | 336 ++++++ src/kits/network/libnetapi/NetworkRoster.cpp | 128 +++ 7 files changed, 1477 insertions(+), 22 deletions(-) diff --git a/headers/os/net/NetworkAddress.h b/headers/os/net/NetworkAddress.h index 68c8fcc9cc..3646aa4211 100644 --- a/headers/os/net/NetworkAddress.h +++ b/headers/os/net/NetworkAddress.h @@ -12,6 +12,7 @@ #include #include +#include class BNetworkAddress : public BArchivable { @@ -21,10 +22,12 @@ public: const char* address, uint16 port = 0); BNetworkAddress(const char* address, uint16 port = 0); - BNetworkAddress(const sockaddr* address); - BNetworkAddress(const sockaddr_in* address); - BNetworkAddress(const sockaddr_in6* address); - BNetworkAddress(const sockaddr_dl* address); + BNetworkAddress(const sockaddr& address); + BNetworkAddress( + const sockaddr_storage& address); + BNetworkAddress(const sockaddr_in& address); + BNetworkAddress(const sockaddr_in6& address); + BNetworkAddress(const sockaddr_dl& address); BNetworkAddress(const in_addr_t address); BNetworkAddress(const in6_addr* address); BNetworkAddress(const BNetworkAddress& other); @@ -38,10 +41,11 @@ public: status_t SetTo(int family, const char* address, uint16 port = 0); status_t SetTo(const char* address, uint16 port = 0); - void SetTo(const sockaddr* address); - void SetTo(const sockaddr_in* address); - void SetTo(const sockaddr_in6* address); - void SetTo(const sockaddr_dl* address); + void SetTo(const sockaddr& address); + void SetTo(const sockaddr_storage& address); + void SetTo(const sockaddr_in& address); + void SetTo(const sockaddr_in6& address); + void SetTo(const sockaddr_dl& address); void SetTo(const in_addr_t address); void SetTo(const in6_addr* address); void SetTo(const BNetworkAddress& other); @@ -63,6 +67,7 @@ public: int Family() const; uint16 Port() const; size_t Length() const; + const sockaddr& SockAddr() const; bool IsEmpty() const; bool IsWildcard() const; @@ -84,17 +89,20 @@ public: uint8* LinkLevelAddress() const; size_t LinkLevelAddressLength() const; - BNetworkAddress ResolvedForDestination( - const BNetworkAddress& destination) const; - void ResolveTo(const BNetworkAddress& address); + status_t ResolveForDestination( + const BNetworkAddress& destination); + status_t ResolveTo(const BNetworkAddress& address); - BString ToString() const; + BString ToString(bool includePort = true) const; BString HostName() const; BString PortName() const; virtual status_t Archive(BMessage* into, bool deep = true) const; static BArchivable* Instantiate(BMessage* archive); + bool Equals(const BNetworkAddress& other, + bool includePort = true) const; + BNetworkAddress& operator=(const BNetworkAddress& other); bool operator==(const BNetworkAddress& other) const; diff --git a/headers/os/net/NetworkInterface.h b/headers/os/net/NetworkInterface.h index 8820c6dc3e..38fb4419e4 100644 --- a/headers/os/net/NetworkInterface.h +++ b/headers/os/net/NetworkInterface.h @@ -21,9 +21,12 @@ public: BNetworkInterfaceAddress(); ~BNetworkInterfaceAddress(); + status_t SetTo(BNetworkInterface& interface, + int32 index); + void SetAddress(BNetworkAddress& address); void SetMask(BNetworkAddress& mask); - void SetBroadcast(BNetworkAddress& mask); + void SetBroadcast(BNetworkAddress& broadcast); BNetworkAddress& Address() { return fAddress; } BNetworkAddress& Mask() { return fMask; } @@ -36,9 +39,10 @@ public: void SetFlags(uint32 flags); uint32 Flags() const { return fFlags; } + int32 Index() const { return fIndex; } + private: - BNetworkInterface* fInterface; - uint32 fIndex; + int32 fIndex; BNetworkAddress fAddress; BNetworkAddress fMask; BNetworkAddress fBroadcast; @@ -53,9 +57,14 @@ public: BNetworkInterface(uint32 index); ~BNetworkInterface(); + void Unset(); + void SetTo(const char* name); + status_t SetTo(uint32 index); + bool Exists() const; const char* Name() const; + uint32 Index() const; uint32 Flags() const; uint32 MTU() const; uint32 Type() const; @@ -66,10 +75,13 @@ public: status_t SetMTU(uint32 mtu); int32 CountAddresses() const; - BNetworkInterfaceAddress* AddressAt(int32 index); + status_t GetAddressAt(int32 index, + BNetworkInterfaceAddress& address); status_t AddAddress( const BNetworkInterfaceAddress& address); + status_t SetAddress( + const BNetworkInterfaceAddress& address); status_t RemoveAddress( const BNetworkInterfaceAddress& address); status_t RemoveAddressAt(int32 index); @@ -78,7 +90,6 @@ public: private: char fName[IF_NAMESIZE]; - uint32 fIndex; BList fAddresses; }; diff --git a/headers/os/net/NetworkRoster.h b/headers/os/net/NetworkRoster.h index 02fc48ee3a..4de5c1a681 100644 --- a/headers/os/net/NetworkRoster.h +++ b/headers/os/net/NetworkRoster.h @@ -6,7 +6,7 @@ #define _NETWORK_ROSTER_H -#include +#include class BMessenger; @@ -17,14 +17,14 @@ class BNetworkRoster { public: static BNetworkRoster& Default(); - int32 CountInterfaces(); - BNetworkInterface* InterfaceAt(int32 index); + size_t CountInterfaces() const; + status_t GetNextInterface(uint32* cookie, + BNetworkInterface& interface) const; status_t AddInterface( const BNetworkInterface& interface); status_t RemoveInterface( const BNetworkInterface& interface); - status_t RemoveInterfaceAt(int32 index); status_t StartWatching(const BMessenger& target, uint32 eventMask); @@ -33,6 +33,9 @@ public: private: BNetworkRoster(); ~BNetworkRoster(); + +private: + static BNetworkRoster sDefault; }; diff --git a/src/kits/network/libnetapi/Jamfile b/src/kits/network/libnetapi/Jamfile index e397d8882e..9f113f0f0e 100644 --- a/src/kits/network/libnetapi/Jamfile +++ b/src/kits/network/libnetapi/Jamfile @@ -1,6 +1,6 @@ SubDir HAIKU_TOP src kits network libnetapi ; -UsePrivateHeaders net ; +UsePrivateHeaders net shared ; SharedLibrary libbnetapi.so : init.cpp diff --git a/src/kits/network/libnetapi/NetworkAddress.cpp b/src/kits/network/libnetapi/NetworkAddress.cpp index c2536a0872..7c3dc0e722 100644 --- a/src/kits/network/libnetapi/NetworkAddress.cpp +++ b/src/kits/network/libnetapi/NetworkAddress.cpp @@ -6,3 +6,972 @@ #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static bool +strip_port(BString& host, BString& port) +{ + int32 separator = host.FindFirst(':'); + if (separator != -1) { + // looks like there is a port + host.CopyInto(port, separator + 1, -1); + host.Truncate(separator); + + return true; + } + + return false; +} + + +static status_t +resolve_address(int family, const char* host, const char* port, + int type, sockaddr_storage& address) +{ + addrinfo hint = {0}; + hint.ai_family = family; + hint.ai_socktype = type; + hint.ai_protocol = 0; + + if (host == NULL && port == NULL) { + port = "0"; + hint.ai_flags = AI_PASSIVE; + } + + addrinfo* info; + int status = getaddrinfo(host, port, &hint, &info); + if (status != 0) { + // TODO: improve error reporting + return B_ERROR; + } + + bool foundAddress = false; + + if (family == AF_UNSPEC) { + // Prefer IPv6 addresses over IPv4 addresses + + for (const addrinfo* next = info; next != NULL; next = next->ai_next) { + if (next->ai_family == AF_INET6) { + memcpy(&address, next->ai_addr, next->ai_addrlen); + foundAddress = true; + break; + } + } + } + + if (!foundAddress) { + // No preferred, or no IPv6 address found, just take the first one + // that works + memcpy(&address, info->ai_addr, info->ai_addrlen); + } + + freeaddrinfo(info); + return B_OK; +} + + +// #pragma mark - + + +BNetworkAddress::BNetworkAddress(int family, const char* host, uint16 port) +{ + SetTo(family, host, port); +} + + +BNetworkAddress::BNetworkAddress(const char* host, uint16 port) +{ + SetTo(host, port); +} + + +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(const in_addr_t address) +{ + SetTo(address); +} + + +BNetworkAddress::BNetworkAddress(const in6_addr* address) +{ + SetTo(address); +} + + +BNetworkAddress::BNetworkAddress(const BNetworkAddress& other) + : + fAddress(other.fAddress), + fStatus(other.fStatus) +{ +} + + +BNetworkAddress::BNetworkAddress(BMessage* archive) +{ + // TODO: implement me + fStatus = B_NO_INIT; +} + + +BNetworkAddress::BNetworkAddress() +{ + Unset(); +} + + +BNetworkAddress::~BNetworkAddress() +{ +} + + +status_t +BNetworkAddress::InitCheck() const +{ + return fStatus; +} + + +void +BNetworkAddress::Unset() +{ + fAddress.ss_family = AF_UNSPEC; + fAddress.ss_len = 2; + fStatus = B_OK; +} + + +status_t +BNetworkAddress::SetTo(int family, const char* host, uint16 port) +{ + // Check if the address contains a port + + BString hostAddress(host); + + BString portString; + if (strip_port(hostAddress, portString) && port == 0) + port = strtoul(portString.String(), NULL, 0); + + // Resolve address + + memset(&fAddress, 0, sizeof(sockaddr_storage)); + fAddress.ss_family = family; + + if (host != NULL) { + switch (family) { + case AF_INET: + { + hostent* server = gethostbyname(hostAddress.String()); + if (server == NULL) + return errno; + + struct sockaddr_in& address = (sockaddr_in&)fAddress; + address.sin_port = htons(port); + address.sin_addr.s_addr = *(in_addr_t*)server->h_addr_list[0]; + break; + } + + default: + { + fStatus = resolve_address(family, host, "0", 0, fAddress); + if (fStatus != B_OK) + return fStatus; + + if (family == AF_INET6) { + struct sockaddr_in6& address = (sockaddr_in6&)fAddress; + address.sin6_port = htons(port); + } + break; + } + } + } else { + switch (fAddress.ss_family) { + case AF_INET: + { + struct sockaddr_in& address = (sockaddr_in&)fAddress; + address.sin_port = htons(port); + address.sin_addr.s_addr = INADDR_ANY; + break; + } + + case AF_INET6: + { + struct sockaddr_in6& address = (sockaddr_in6&)fAddress; + address.sin6_port = htons(port); + address.sin6_addr = in6addr_any; + break; + } + + default: + return B_NOT_SUPPORTED; + } + } + + return fStatus = B_OK; +} + + +status_t +BNetworkAddress::SetTo(const char* host, uint16 port) +{ + // Check if the address contains a port + + BString hostAddress(host); + + BString portString; + strip_port(hostAddress, portString); + + // Resolve address + + memset(&fAddress, 0, sizeof(sockaddr_storage)); + + fStatus = resolve_address(AF_UNSPEC, + host != NULL ? hostAddress.String() : NULL, + portString.Length() == 0 ? NULL : portString.String(), 0, fAddress); + if (fStatus != B_OK) + return fStatus; + + // Set port if specified separately + + switch (fAddress.ss_family) { + case AF_INET: + { + struct sockaddr_in& address = (sockaddr_in&)fAddress; + if (address.sin_port == 0) + address.sin_port = htons(port); + break; + } + + case AF_INET6: + { + struct sockaddr_in6& address = (sockaddr_in6&)fAddress; + if (address.sin6_port == 0) + address.sin6_port = htons(port); + break; + } + + default: + break; + } + + return B_OK; +} + + +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: + length = sizeof(sockaddr_dl); + break; + } + + 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(const in_addr_t inetAddress) +{ + sockaddr_in& address = (sockaddr_in&)fAddress; + memset(&fAddress, 0, sizeof(sockaddr_storage)); + + address.sin_family = AF_INET; + address.sin_len = sizeof(sockaddr_in); + address.sin_addr.s_addr = inetAddress; + fStatus = B_OK; +} + + +void +BNetworkAddress::SetTo(const in6_addr* inet6Address) +{ + sockaddr_in6& address = (sockaddr_in6&)fAddress; + memset(&fAddress, 0, sizeof(sockaddr_storage)); + + address.sin6_family = AF_INET6; + address.sin6_len = sizeof(sockaddr_in6); + memcpy(address.sin6_addr.s6_addr, inet6Address, + sizeof(address.sin6_addr.s6_addr)); + fStatus = B_OK; +} + + +void +BNetworkAddress::SetTo(const BNetworkAddress& other) +{ + fAddress = other.fAddress; + fStatus = other.fStatus; +} + + +status_t +BNetworkAddress::SetToBroadcast(int family, uint16 port) +{ + if (family != AF_INET) + return fStatus = B_NOT_SUPPORTED; + + memset(&fAddress, 0, sizeof(sockaddr_storage)); + fAddress.ss_family = family; + ((sockaddr_in&)fAddress).sin_addr.s_addr = INADDR_BROADCAST; + + SetPort(port); + return fStatus = B_OK; +} + + +status_t +BNetworkAddress::SetToLocal() +{ + // TODO: choose a local address from the network interfaces + return B_NOT_SUPPORTED; +} + + +status_t +BNetworkAddress::SetToLoopback() +{ + return SetTo("localhost"); +} + + +status_t +BNetworkAddress::SetToMask(int family, uint32 prefixLength) +{ + // TODO: implement SetToMask() + return B_NOT_SUPPORTED; +} + + +status_t +BNetworkAddress::SetToWildcard(int family) +{ + return SetTo(family, NULL); +} + + +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(uint8* address, size_t length) +{ + // TODO: implement me! +} + + +void +BNetworkAddress::SetToLinkLevel(const char* name) +{ + // TODO: implement me! +} + + +void +BNetworkAddress::SetToLinkLevel(uint32 index) +{ + // TODO: implement me! +} + + +void +BNetworkAddress::SetLinkLevelIndex(uint32 index) +{ + // TODO: implement me! +} + + +void +BNetworkAddress::SetLinkLevelType(uint32 type) +{ + // TODO: implement me! +} + + +void +BNetworkAddress::SetLinkLevelFrameType(uint32 frameType) +{ + // TODO: implement me! +} + + +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; +} + + +bool +BNetworkAddress::IsEmpty() const +{ + return fAddress.ss_len == 0 || fAddress.ss_family == AF_UNSPEC; +} + + +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: + // There is no broadcast in IPv6, only multicast/anycast + 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 +{ + // TODO: ipv4 + 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; +} + + +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; +} + + +uint32 +BNetworkAddress::LinkLevelType() const +{ + return ((sockaddr_dl&)fAddress).sdl_type; +} + + +uint32 +BNetworkAddress::LinkLevelFrameType() const +{ + return ((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); + + 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[128]; + + 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; + + 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 +{ + // TODO: implement host name lookup + return ToString(false); +} + + +BString +BNetworkAddress::PortName() const +{ + // TODO: implement service lookup + BString portName; + portName << Port(); + return portName; +} + + +status_t +BNetworkAddress::Archive(BMessage* into, bool deep = true) const +{ + // TODO: implement me! + return B_ERROR; +} + + +/*static*/ BArchivable* +BNetworkAddress::Instantiate(BMessage* archive) +{ + if (archive != NULL) + return new BNetworkAddress(archive); + + return NULL; +} + + +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); + } +} + + +BNetworkAddress& +BNetworkAddress::operator=(const BNetworkAddress& other) +{ + memcpy(&fAddress, &other.fAddress, other.fAddress.ss_len); + 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; + } + } + + if (compare < 0) + return true; + if (compare > 0) + return false; + + return Port() < other.Port(); +} diff --git a/src/kits/network/libnetapi/NetworkInterface.cpp b/src/kits/network/libnetapi/NetworkInterface.cpp index 7222f5cb82..95cc26db3f 100644 --- a/src/kits/network/libnetapi/NetworkInterface.cpp +++ b/src/kits/network/libnetapi/NetworkInterface.cpp @@ -6,3 +6,339 @@ #include +#include +#include +#include + +#include + + +static status_t +do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address, + bool readBack = false) +{ + int socket = ::socket(AF_INET, SOCK_DGRAM, 0); + if (socket < 0) + return errno; + + DescriptorCloser 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) +{ + return do_ifaliasreq(name, option, + const_cast(address)); +} + + +static status_t +do_request(ifreq& request, const char* name, int option) +{ + int socket = ::socket(AF_INET, SOCK_DGRAM, 0); + if (socket < 0) + return errno; + + DescriptorCloser closer(socket); + + strlcpy(request.ifr_name, name, IF_NAMESIZE); + + if (ioctl(socket, option, &request, sizeof(struct ifreq)) < 0) + return errno; + + return B_OK; +} + + +// #pragma mark - + + +BNetworkInterfaceAddress::BNetworkInterfaceAddress() + : + fIndex(0), + fFlags(0) +{ +} + + +BNetworkInterfaceAddress::~BNetworkInterfaceAddress() +{ +} + + +status_t +BNetworkInterfaceAddress::SetTo(BNetworkInterface& interface, int32 index) +{ + fIndex = index; + return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true); +} + + +void +BNetworkInterfaceAddress::SetAddress(BNetworkAddress& address) +{ + fAddress = address; +} + + +void +BNetworkInterfaceAddress::SetMask(BNetworkAddress& mask) +{ + fMask = mask; +} + + +void +BNetworkInterfaceAddress::SetBroadcast(BNetworkAddress& broadcast) +{ + fBroadcast = broadcast; +} + + +void +BNetworkInterfaceAddress::SetFlags(uint32 flags) +{ + fFlags = flags; +} + + +// #pragma mark - + + +BNetworkInterface::BNetworkInterface() +{ + Unset(); +} + + +BNetworkInterface::BNetworkInterface(const char* name) +{ + SetTo(name); +} + + +BNetworkInterface::BNetworkInterface(uint32 index) +{ + SetTo(index); +} + + +BNetworkInterface::~BNetworkInterface() +{ +} + + +void +BNetworkInterface::Unset() +{ + fName[0] = '\0'; +} + + +void +BNetworkInterface::SetTo(const char* name) +{ + strlcpy(fName, name, IF_NAMESIZE); +} + + +status_t +BNetworkInterface::SetTo(uint32 index) +{ + ifreq request; + request.ifr_index = index; + + status_t status = do_request(request, "", SIOCGIFNAME); + if (status != B_OK) + return status; + + strlcpy(fName, request.ifr_name, IF_NAMESIZE); + return B_OK; +} + + +bool +BNetworkInterface::Exists() const +{ + ifreq request; + return do_request(request, Name(), SIOCGIFINDEX) == B_OK; +} + + +const char* +BNetworkInterface::Name() const +{ + return fName; +} + + +uint32 +BNetworkInterface::Flags() const +{ + ifreq request; + if (do_request(request, Name(), SIOCGIFFLAGS) != B_OK) + return 0; + + return request.ifr_flags; +} + + +uint32 +BNetworkInterface::MTU() const +{ + ifreq request; + if (do_request(request, Name(), SIOCGIFMTU) != B_OK) + return 0; + + return request.ifr_mtu; +} + + +uint32 +BNetworkInterface::Type() const +{ + ifreq request; + if (do_request(request, Name(), SIOCGIFTYPE) != B_OK) + return 0; + + return request.ifr_type; +} + + +status_t +BNetworkInterface::GetStats(ifreq_stats& stats) +{ + ifreq request; + status_t status = do_request(request, Name(), SIOCGIFSTATS); + if (status != B_OK) + return status; + + memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats)); + return B_OK; +} + + +bool +BNetworkInterface::HasLink() const +{ + return (Flags() & IFF_LINK) != 0; +} + + +status_t +BNetworkInterface::SetFlags(uint32 flags) +{ + ifreq request; + request.ifr_flags = flags; + return do_request(request, Name(), SIOCSIFFLAGS); +} + + +status_t +BNetworkInterface::SetMTU(uint32 mtu) +{ + ifreq request; + request.ifr_mtu = mtu; + return do_request(request, Name(), SIOCSIFMTU); +} + + +int32 +BNetworkInterface::CountAddresses() const +{ + ifreq request; + if (do_request(request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK) + return 0; + + return request.ifr_count; +} + + +status_t +BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address) +{ + return address.SetTo(*this, index); +} + + +status_t +BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address) +{ + return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); +} + + +status_t +BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address) +{ + return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address); +} + + +status_t +BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address) +{ + ifreq request; + memcpy(&request.ifr_addr, &address.Address().SockAddr(), + address.Address().Length()); + + return do_request(request, Name(), B_SOCKET_REMOVE_ALIAS); +} + + +status_t +BNetworkInterface::RemoveAddressAt(int32 index) +{ + BNetworkInterfaceAddress address; + status_t status = GetAddressAt(index, address); + if (status != B_OK) + return status; + + return RemoveAddress(address); +} + + +status_t +BNetworkInterface::GetHardwareAddress(BNetworkAddress& address) +{ + int socket = ::socket(AF_LINK, SOCK_DGRAM, 0); + if (socket < 0) + return errno; + + DescriptorCloser closer(socket); + + ifreq request; + strlcpy(request.ifr_name, Name(), IF_NAMESIZE); + + if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) + return errno; + + address.SetTo(request.ifr_addr); + return B_OK; +} diff --git a/src/kits/network/libnetapi/NetworkRoster.cpp b/src/kits/network/libnetapi/NetworkRoster.cpp index af90b2fef5..49dfd2cdf3 100644 --- a/src/kits/network/libnetapi/NetworkRoster.cpp +++ b/src/kits/network/libnetapi/NetworkRoster.cpp @@ -6,3 +6,131 @@ #include +#include +#include + +#include + +#include +#include + + +BNetworkRoster BNetworkRoster::sDefault; + + +/*static*/ BNetworkRoster& +BNetworkRoster::Default() +{ + return sDefault; +} + + +size_t +BNetworkRoster::CountInterfaces() const +{ + int socket = ::socket(AF_INET, SOCK_DGRAM, 0); + if (socket < 0) + return 0; + + DescriptorCloser closer(socket); + + ifconf config; + config.ifc_len = sizeof(config.ifc_value); + if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) != 0) + return 0; + + return (size_t)config.ifc_value; +} + + +status_t +BNetworkRoster::GetNextInterface(uint32* cookie, + BNetworkInterface& interface) const +{ + // TODO: think about caching the interfaces! + + // get a list of all interfaces + + int socket = ::socket(AF_INET, SOCK_DGRAM, 0); + if (socket < 0) + return errno; + + DescriptorCloser closer(socket); + + ifconf config; + config.ifc_len = sizeof(config.ifc_value); + if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0) + return errno; + + size_t count = (size_t)config.ifc_value; + if (count == 0) + return B_BAD_VALUE; + + char* buffer = (char*)malloc(count * sizeof(struct ifreq)); + if (buffer == NULL) + return B_NO_MEMORY; + + MemoryDeleter deleter(buffer); + + config.ifc_len = count * sizeof(struct ifreq); + config.ifc_buf = buffer; + if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0) + return errno; + + ifreq* interfaces = (ifreq*)buffer; + ifreq* end = (ifreq*)(buffer + config.ifc_len); + + for (uint32 i = 0; interfaces < end; i++) { + interface.SetTo(interfaces[0].ifr_name); + if (i == *cookie) + return B_OK; + + interfaces = (ifreq*)((uint8*)interfaces + + _SIZEOF_ADDR_IFREQ(interfaces[0])); + } + + return B_BAD_VALUE; +} + + +status_t +BNetworkRoster::AddInterface(const BNetworkInterface& interface) +{ + // TODO: implement me + return B_NOT_SUPPORTED; +} + + +status_t +BNetworkRoster::RemoveInterface(const BNetworkInterface& interface) +{ + // TODO: implement me + return B_NOT_SUPPORTED; +} + + +status_t +BNetworkRoster::StartWatching(const BMessenger& target, uint32 eventMask) +{ + return start_watching_network(eventMask, target); +} + + +void +BNetworkRoster::StopWatching(const BMessenger& target) +{ + stop_watching_network(target); +} + + +// #pragma mark - private + + +BNetworkRoster::BNetworkRoster() +{ +} + + +BNetworkRoster::~BNetworkRoster() +{ +}