Return to inet_address.cpp CVS log | Up to Nevrax / code / nel / src / net |
File: Nevrax / code / nel / src / net / inet_address.cpp (download) Revision 1.38, Fri Dec 28 10:17:21 2001 UTC (7 months ago) by lecroart Branch: MAIN CVS Tags: georges_v2, HEAD Changes since 1.37: +3 -6 lines ADDED: support of precompilated header on visual |
/** \file inet_address.cpp * Class CInetAddress (IP address + port) * * $Id: inet_address.cpp,v 1.38 2001/12/28 10:17:21 lecroart Exp $ */ /* Copyright, 2000 Nevrax Ltd. * * This file is part of NEVRAX NEL. * NEVRAX NEL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * NEVRAX NEL is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * You should have received a copy of the GNU General Public License * along with NEVRAX NEL; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ #include "stdnet.h" #include "nel/net/inet_address.h" #include "nel/net/sock.h" #ifdef NL_OS_WINDOWS #include <winsock2.h> #elif defined NL_OS_UNIX #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #define WSAGetLastError() 0 #define SOCKET_ERROR -1 #endif using namespace std; namespace NLNET { bool CInetAddress::RetrieveNames = true; /* * Constructor */ CInetAddress::CInetAddress() : _Valid( false ) { init(); _SockAddr->sin_port = 0; // same as htons(0) memset( &_SockAddr->sin_addr, 0, sizeof(in_addr) ); // same as htonl(INADDR_ANY) } /* * Constructor with ip address, port=0 */ CInetAddress::CInetAddress( const in_addr *ip ) { init(); _SockAddr->sin_port = 0; memcpy( &_SockAddr->sin_addr, ip, sizeof(in_addr) ); } /* * Alternate constructor (calls setByName()) */ CInetAddress::CInetAddress( const std::string& hostName, uint16 port ) : _Valid( false ) { init(); setPort( port ); setByName( hostName ); } /* * Alternate constructor (calls setNameAndPort()) */ CInetAddress::CInetAddress( const std::string& hostNameAndPort ) : _Valid( false ) { init(); setNameAndPort( hostNameAndPort ); } /* * Copy constructor */ CInetAddress::CInetAddress( const CInetAddress& other ) : _Valid( false ) { init(); _HostName = other._HostName; memcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) ); _Valid = other._Valid; } /* * Assignment operator */ CInetAddress& CInetAddress::operator=( const CInetAddress& other ) { _HostName = other._HostName; memcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) ); _Valid = other._Valid; return *this; } /* * Comparison == operator */ bool operator==( const CInetAddress& a1, const CInetAddress& a2 ) { // Compares the sockaddr structure except the last 8 bytes equal to zero. return ( memcmp( a1._SockAddr, a2._SockAddr, sizeof(sockaddr_in)-8 ) == 0 ); } /* * Comparison < operator */ bool operator<( const CInetAddress& a1, const CInetAddress& a2 ) { #ifdef NL_OS_WINDOWS if ( a1._SockAddr->sin_addr.S_un.S_addr == a2._SockAddr->sin_addr.S_un.S_addr ) { return ( a1.port() < a2.port() ); } else { return ( a1._SockAddr->sin_addr.S_un.S_addr < a2._SockAddr->sin_addr.S_un.S_addr ); } #elif defined NL_OS_UNIX if ( a1._SockAddr->sin_addr.s_addr == a2._SockAddr->sin_addr.s_addr ) { return ( a1.port() < a2.port() ); } else { return ( a1._SockAddr->sin_addr.s_addr < a2._SockAddr->sin_addr.s_addr ); } #endif } /* * Constructor contents */ void CInetAddress::init() { CSock::initNetwork(); /// \todo cado: handle exception (because init() is called within a constructor) _SockAddr = new sockaddr_in; _SockAddr->sin_family = AF_INET; memset( _SockAddr->sin_zero, 0, 8 ); } /* * Destructor */ CInetAddress::~CInetAddress() { delete _SockAddr; // _Valid = false; } /* * Sets hostname and port (ex: www.nevrax.com:80) */ void CInetAddress::setNameAndPort( const std::string& hostNameAndPort ) { int pos = hostNameAndPort.find_first_of (':'); if (pos != string::npos) { setPort( atoi(hostNameAndPort.substr(pos + 1).c_str()) ); } else { setPort( 0 ); } // if pos == -1, it will copy all the string setByName( hostNameAndPort.substr (0, pos) ); } /* * Resolves a name */ CInetAddress& CInetAddress::setByName( const std::string& hostName ) { // Try to convert directly for addresses such as a.b.c.d in_addr iaddr; #ifdef NL_OS_WINDOWS iaddr.S_un.S_addr = inet_addr( hostName.c_str() ); if ( iaddr.S_un.S_addr == INADDR_NONE ) #elif defined NL_OS_UNIX iaddr.s_addr = inet_addr( hostName.c_str() ); if ( iaddr.s_addr == INADDR_NONE ) #endif { // Otherwise use the traditional DNS look-up hostent *phostent = gethostbyname( hostName.c_str() ); if ( phostent == NULL ) { _Valid = false; nldebug( "LNETL0: Network error: resolution of hostname '%s' failed", hostName.c_str() ); // return *this; throw ESocket( (string("Hostname resolution failed for ")+hostName).c_str() ); } _HostName = string( phostent->h_name ); memcpy( &_SockAddr->sin_addr, phostent->h_addr, sizeof(in_addr) ); } else { _HostName = hostName; memcpy( &_SockAddr->sin_addr, &iaddr, sizeof(iaddr) ); } _Valid = true; return *this; } /* * Sets port */ void CInetAddress::setPort( uint16 port ) { _SockAddr->sin_port = htons( port ); } /* Sets internal socket address directly (contents is copied). * It also retrieves the host name if CInetAddress::RetrieveNames is true. */ void CInetAddress::setSockAddr( const sockaddr_in* saddr ) { memcpy( _SockAddr, saddr, sizeof(*saddr) ); // Get host name // Warning: when it can't find it, it take more than 4 seconds if ( CInetAddress::RetrieveNames ) { hostent *phostent = gethostbyaddr( (char*)&saddr->sin_addr.s_addr, 4, AF_INET ); if ( phostent == NULL ) { _HostName = ipAddress(); } else { _HostName = string( phostent->h_name ); } } _Valid = true; } /* * Returns if object (address and port) is valid */ bool CInetAddress::isValid() const { return ( _Valid && _SockAddr->sin_port!=0 ); // same as ntohs(0) } /* * Returns internal socket address (read only) */ const sockaddr_in *CInetAddress::sockAddr() const { return _SockAddr; } /* * Returns internal IP address */ uint32 CInetAddress::internalIPAddress() const { return _SockAddr->sin_addr.s_addr; } /* * Returns readable IP address. (ex: "195.68.21.195") */ string CInetAddress::ipAddress() const { /*stringstream ss; // or use inet_ntoa ss << inet_ntoa ( _SockAddr->sin_addr ); return ss.str();*/ return string( inet_ntoa( _SockAddr->sin_addr ) ); } /* * Returns host name. (ex: "www.nevrax.org") */ const string& CInetAddress::hostName() const { return _HostName; } /* * Returns port */ uint16 CInetAddress::port() const { return ntohs( _SockAddr->sin_port ); } /* * Returns hostname and port as a string. (ex: "www.nevrax.org:80 (195.68.21.195)") */ std::string CInetAddress::asString() const { stringstream ss; ss << hostName() << ":" << port() << " (" << ipAddress() << ")"; return ss.str(); } /* * Returns IP address and port as a string. (ex: "195.68.21.195:80") */ std::string CInetAddress::asIPString() const { stringstream ss; ss << ipAddress() << ":" << port(); return ss.str(); } /* * Serialize */ void CInetAddress::serial( NLMISC::IStream& s ) { NLMISC::CMemStream *ms = dynamic_cast<NLMISC::CMemStream*>(&s); if ( ms && ms->stringMode() ) { // String stream string addrs; if ( ms->isReading() ) { ms->serial( addrs ); setNameAndPort( addrs ); } else { addrs = asIPString(); ms->serial( addrs ); } } else { // Binary stream s.serialBuffer( (uint8*)_SockAddr, sizeof(*_SockAddr) ); // this is possible only because the contents of _SockAddr is platform-independant ! s.serial( _Valid ); } // Common s.serial( _Valid ); } /* * Creates a CInetAddress object with local host address, port=0 */ CInetAddress CInetAddress::localHost() { const uint maxlength = 80; char localhost [maxlength]; if ( gethostname( localhost, maxlength ) != 0 ) throw ESocket( "Unable to get local hostname" ); CInetAddress localaddr = CInetAddress( string(localhost) ); nlassert( localaddr.ipAddress() != "127.0.0.1" ); return localaddr; } /* Returns the list of the local host addresses (with port=0) * (especially useful if the host is multihomed) */ std::vector<CInetAddress> CInetAddress::localAddresses() { // 1. Get local host name const uint maxlength = 80; char localhost [maxlength]; if ( gethostname( localhost, maxlength ) == SOCKET_ERROR ) { throw ESocket( "Unable to get local hostname" ); } // 2. Get address list hostent *phostent = gethostbyname( localhost ); if ( phostent == NULL ) { throw ESocket( (string("Hostname resolution failed for ")+string(localhost)).c_str() ); } uint i; vector<CInetAddress> vect; for ( i=0; phostent->h_addr_list[i]!=0; ++i ) { vect.push_back( CInetAddress( (const in_addr*)(phostent->h_addr_list[i]) ) ); } return vect; } } // NLNET