* Copyright 2002-2006,2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Scott T. Mansfield, thephantom@mac.com
* Oliver Tappe, zooey@hirschkaefer.de
*/
NetAddress.cpp -- Implementation of the BNetAddress class.
Remarks:
* In all accessors, non-struct output values are converted from network to
host byte order.
* In all mutators, non-struct input values are converted from host to
network byte order.
* No trouts were harmed during the development of this class.
*/
#include <r5_compatibility.h>
#include <ByteOrder.h>
#include <NetAddress.h>
#include <Message.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <new>
#include <string.h>
BNetAddress::BNetAddress(const char* hostname, unsigned short port)
:
fInit(B_NO_INIT)
{
SetTo(hostname, port);
}
BNetAddress::BNetAddress(const struct sockaddr_in& addr)
:
fInit(B_NO_INIT)
{
SetTo(addr);
}
BNetAddress::BNetAddress(in_addr addr, int port)
:
fInit(B_NO_INIT)
{
SetTo(addr, port);
}
BNetAddress::BNetAddress(uint32 addr, int port)
:
fInit(B_NO_INIT)
{
SetTo(addr, port);
}
BNetAddress::BNetAddress(const char* hostname, const char* protocol,
const char* service)
:
fInit(B_NO_INIT)
{
SetTo(hostname, protocol, service);
}
BNetAddress::BNetAddress(const BNetAddress& other)
{
*this = other;
}
BNetAddress::BNetAddress(BMessage* archive)
{
int16 int16value;
if (archive->FindInt16("bnaddr_family", &int16value) != B_OK)
return;
fFamily = int16value;
if (archive->FindInt16("bnaddr_port", &int16value) != B_OK)
return;
fPort = int16value;
if (archive->FindInt32("bnaddr_addr", &fAddress) != B_OK)
return;
fInit = B_OK;
}
BNetAddress::~BNetAddress()
{
}
BNetAddress&
BNetAddress::operator=(const BNetAddress& other)
{
fInit = other.fInit;
fFamily = other.fFamily;
fPort = other.fPort;
fAddress = other.fAddress;
return *this;
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Class accessor.
*
* Output parameters:
* hostname: Host name associated with this instance (default: NULL).
* In this particular implementation, hostname will be an
* ASCII-fied representation of an IP address.
*
* port: Port number associated with this instance
* (default: NULL). Will be converted to host byte order
* here, so it is not necessary to call ntohs() after
* calling this method.
*
* Returns:
* B_OK for success, B_NO_INIT if instance was not properly constructed.
*
* Remarks:
* Hostname and/or port can be NULL; although having them both NULL would
* be a pointless waste of CPU cycles. ;-)
*
* The hostname output parameter can be a variety of things, but in this
* method we convert the IP address to a string. See the relevant
* documentation about inet_ntoa() for details.
*
* Make sure hostname is large enough or you will step on someone
* else's toes. (Can you say "buffer overflow exploit" boys and girls?)
* You can generally be safe using the MAXHOSTNAMELEN define, which
* defaults to 64 bytes--don't forget to leave room for the NULL!
*/
status_t
BNetAddress::GetAddr(char* hostname, unsigned short* port) const
{
if (fInit != B_OK)
return B_NO_INIT;
if (port != NULL)
*port = ntohs(fPort);
if (hostname != NULL) {
struct in_addr addr;
addr.s_addr = fAddress;
char* text = inet_ntoa(addr);
if (text != NULL)
strcpy(hostname, text);
}
return B_OK;
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Class accessor.
*
* Output parameter:
* sa: sockaddr_in struct to be filled.
*
* Returns:
* B_OK for success, B_NO_INIT if instance was not properly constructed.
*
* Remarks:
* This method fills in the sin_addr, sin_family, and sin_port fields of
* the output parameter, all other fields are untouched so we can work
* with both POSIX and non-POSIX versions of said struct. The port and
* address values added to the output parameter are in network byte order.
*/
status_t BNetAddress::GetAddr(struct sockaddr_in& sa) const
{
if (fInit != B_OK)
return B_NO_INIT;
sa.sin_port = fPort;
sa.sin_addr.s_addr = fAddress;
if (check_r5_compatibility()) {
r5_sockaddr_in* r5Addr = (r5_sockaddr_in*)&sa;
if (fFamily == AF_INET)
r5Addr->sin_family = R5_AF_INET;
else
r5Addr->sin_family = fFamily;
} else
sa.sin_family = fFamily;
return B_OK;
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Class accessor.
*
* Output parameters:
* addr: in_addr struct to fill.
* port: optional port number to fill.
*
* Returns:
* B_OK for success, B_NO_INIT if instance was not properly constructed.
*
* Remarks:
* Output port will be in host byte order, but addr will be in the usual
* network byte order (ready to be used by other network functions).
*/
status_t BNetAddress::GetAddr(in_addr& addr, unsigned short* port) const
{
if (fInit != B_OK)
return B_NO_INIT;
addr.s_addr = fAddress;
if (port != NULL)
*port = ntohs(fPort);
return B_OK;
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Determine whether or not this instance is properly initialized.
*
* Returns:
* B_OK if this instance is initialized, B_ERROR if not.
*/
status_t BNetAddress::InitCheck() const
{
return fInit == B_OK ? B_OK : B_ERROR;
}
status_t BNetAddress::InitCheck()
{
return const_cast<const BNetAddress*>(this)->InitCheck();
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Serialize this instance into the passed BMessage parameter.
*
* Input parameter:
* deep: [ignored] default==true.
*
* Output parameter:
* into: BMessage object to serialize into.
*
* Returns:
* B_OK/BERROR on success/failure. Returns B_NO_INIT if instance not
* properly initialized.
*/
status_t BNetAddress::Archive(BMessage* into, bool deep) const
{
if (fInit != B_OK)
return B_NO_INIT;
if (into->AddInt16("bnaddr_family", fFamily) != B_OK)
return B_ERROR;
if (into->AddInt16("bnaddr_port", fPort) != B_OK)
return B_ERROR;
if (into->AddInt32("bnaddr_addr", fAddress) != B_OK)
return B_ERROR;
return B_OK;
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Un-serialize and instantiate from the passed BMessage parameter.
*
* Input parameter:
* archive: Archived BMessage object for (de)serialization.
*
* Returns:
* NULL if a BNetAddress instance can not be initialized, otherwise
* a new BNetAddress object instantiated from the BMessage parameter.
*/
BArchivable*
BNetAddress::Instantiate(BMessage* archive)
{
if (!validate_instantiation(archive, "BNetAddress"))
return NULL;
BNetAddress* address = new (std::nothrow) BNetAddress(archive);
if (address == NULL)
return NULL;
if (address->InitCheck() != B_OK) {
delete address;
return NULL;
}
return address;
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Set hostname and port network address data.
*
* Input parameters:
* hostname: Can be one of three things:
* 1. An ASCII-string representation of an IP address.
* 2. A canonical hostname.
* 3. NULL. If NULL, then by default the address will be
* set to INADDR_ANY (0.0.0.0).
* port: Duh.
*
* Returns:
* B_OK/B_ERROR for success/failure.
*/
status_t
BNetAddress::SetTo(const char* hostname, unsigned short port)
{
if (hostname == NULL)
return B_ERROR;
in_addr_t addr = INADDR_ANY;
addr = inet_addr(hostname);
if (addr == INADDR_ANY || addr == (in_addr_t)-1) {
struct hostent* host = gethostbyname(hostname);
if (host != NULL)
addr = *(int*)host->h_addr_list[0];
else
return B_ERROR;
}
fFamily = AF_INET;
fPort = htons(port);
fAddress = addr;
return fInit = B_OK;
}
Set from passed in sockaddr_in address.
\param addr address
\return B_OK.
*/
status_t
BNetAddress::SetTo(const struct sockaddr_in& addr)
{
fPort = addr.sin_port;
fAddress = addr.sin_addr.s_addr;
if (check_r5_compatibility()) {
const r5_sockaddr_in* r5Addr = (const r5_sockaddr_in*)&addr;
if (r5Addr->sin_family == R5_AF_INET)
fFamily = AF_INET;
else
fFamily = r5Addr->sin_family;
} else
fFamily = addr.sin_family;
return fInit = B_OK;
}
Set from passed in address and port.
\param addr IP address in network form.
\param port Optional port number.
\return B_OK.
*/
status_t
BNetAddress::SetTo(in_addr addr, int port)
{
fFamily = AF_INET;
fPort = htons((short)port);
fAddress = addr.s_addr;
return fInit = B_OK;
}
Set from passed in address and port.
\param addr IP address in network form.
\param port Optional port number.
\return B_OK.
*/
status_t
BNetAddress::SetTo(uint32 addr, int port)
{
fFamily = AF_INET;
fPort = htons((short)port);
fAddress = addr;
return fInit = B_OK;
}
*=--------------------------------------------------------------------------=*
* Purpose:
* Set from passed in hostname and protocol/service information.
*
* Input parameters:
* hostname: Can be one of three things:
* 1. An ASCII-string representation of an IP address.
* 2. A canonical hostname.
* 3. NULL. If NULL, then by default the address will be
* set to INADDR_ANY (0.0.0.0).
* protocol: Datagram type, typically "TCP" or "UDP"
* service: The name of the service, such as http, ftp, et al. This
* must be one of the official service names listed in
* /etc/services -- but you already knew that because
* you're doing network/sockets programming, RIIIGHT???.
*
* Returns:
* B_OK/B_ERROR on success/failure.
*
* Remarks:
* The protocol and service input parameters must be one of the official
* types listed in /etc/services. We use these two parameters to
* determine the port number (see getservbyname(3)). This method will
* fail if the aforementioned precondition is not met.
*/
status_t
BNetAddress::SetTo(const char* hostname, const char* protocol,
const char* service)
{
struct servent* serviceEntry = getservbyname(service, protocol);
if (serviceEntry == NULL)
return B_ERROR;
return SetTo(hostname, serviceEntry->s_port);
}
void BNetAddress::_ReservedBNetAddressFBCCruft1() {}
void BNetAddress::_ReservedBNetAddressFBCCruft2() {}
void BNetAddress::_ReservedBNetAddressFBCCruft3() {}
void BNetAddress::_ReservedBNetAddressFBCCruft4() {}
void BNetAddress::_ReservedBNetAddressFBCCruft5() {}
void BNetAddress::_ReservedBNetAddressFBCCruft6() {}