/* * 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 #include #include #include #include #include #include #include #include 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; } /* GetAddr *=--------------------------------------------------------------------------=* * 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; } /* GetAddr *=--------------------------------------------------------------------------=* * 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; } /* GetAddr *=--------------------------------------------------------------------------=* * 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; } /* InitCheck *=--------------------------------------------------------------------------=* * 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(this)->InitCheck(); } /* Archive *=--------------------------------------------------------------------------=* * 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; } /* Instantiate *=--------------------------------------------------------------------------=* * 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; } /* SetTo *=--------------------------------------------------------------------------=* * 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; // Try like all git-out to set the address from the given hostname. // See if the string is an ASCII-fied IP address. addr = inet_addr(hostname); if (addr == INADDR_ANY || addr == (in_addr_t)-1) { // See if we can resolve the hostname to an IP address. 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; } /* SetTo *=--------------------------------------------------------------------------=* * 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); } // #pragma mark - FBC void BNetAddress::_ReservedBNetAddressFBCCruft1() {} void BNetAddress::_ReservedBNetAddressFBCCruft2() {} void BNetAddress::_ReservedBNetAddressFBCCruft3() {} void BNetAddress::_ReservedBNetAddressFBCCruft4() {} void BNetAddress::_ReservedBNetAddressFBCCruft5() {} void BNetAddress::_ReservedBNetAddressFBCCruft6() {}