# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

inet_address.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "stdnet.h"
00027 
00028 #include "nel/misc/common.h"
00029 
00030 #include "nel/net/inet_address.h"
00031 #include "nel/net/sock.h"
00032 
00033 #ifdef NL_OS_WINDOWS
00034 
00035 #include <winsock2.h>
00036 
00037 #elif defined NL_OS_UNIX
00038 
00039 #include <unistd.h>
00040 #include <sys/socket.h>
00041 #include <arpa/inet.h>
00042 #include <netinet/in.h>
00043 #include <netdb.h>
00044 
00045 #define WSAGetLastError() 0
00046 #define SOCKET_ERROR -1
00047 
00048 #endif
00049 
00050 
00051 using namespace std;
00052 using namespace NLMISC;
00053 
00054 
00055 namespace NLNET
00056 {
00057 
00058 bool CInetAddress::RetrieveNames = false;
00059 
00060 
00061 /*
00062  * Constructor
00063  */
00064 CInetAddress::CInetAddress()
00065 {
00066         init();
00067         _SockAddr->sin_port = 0; // same as htons(0)
00068         memset( &_SockAddr->sin_addr, 0, sizeof(in_addr) ); // same as htonl(INADDR_ANY)
00069 }
00070 
00071 
00072 /*
00073  * Constructor with ip address, port=0
00074  */
00075 CInetAddress::CInetAddress( const in_addr *ip )
00076 {
00077         init();
00078         _SockAddr->sin_port = 0;
00079         memcpy( &_SockAddr->sin_addr, ip, sizeof(in_addr) );
00080 
00081         // get the host name to be displayed
00082         hostent *phostent = gethostbyaddr( (char*)&ip->s_addr, 4,  AF_INET );
00083         if ( phostent == NULL )
00084         {
00085                 _HostName = ipAddress();
00086         }
00087         else
00088         {
00089                 _HostName = string( phostent->h_name );
00090         }
00091         _Valid = true;
00092 }
00093 
00094 
00095 /*
00096  * Alternate constructor (calls setByName())
00097  */
00098 CInetAddress::CInetAddress( const std::string& hostName, uint16 port )
00099 {
00100         init();
00101         setPort( port );
00102         setByName( hostName );
00103 }
00104 
00105 
00106 /*
00107  * Alternate constructor (calls setNameAndPort())
00108  */
00109 CInetAddress::CInetAddress( const std::string& hostNameAndPort )
00110 {
00111         init();
00112         setNameAndPort( hostNameAndPort );
00113 }
00114 
00115 
00116 /*
00117  * Copy constructor
00118  */
00119 CInetAddress::CInetAddress( const CInetAddress& other )
00120 {
00121         init();
00122         _HostName = other._HostName;
00123         memcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) );
00124         _Valid = other._Valid;
00125 }
00126 
00127 
00128 /*
00129  * Assignment operator
00130  */
00131 CInetAddress& CInetAddress::operator=( const CInetAddress& other )
00132 {
00133         _HostName = other._HostName;
00134         memcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) );
00135         _Valid = other._Valid;
00136         return *this;
00137 }
00138 
00139 
00140 /*
00141  * Comparison == operator
00142  */
00143 bool operator==( const CInetAddress& a1, const CInetAddress& a2 )
00144 {
00145         // Compares the sockaddr structure except the last 8 bytes equal to zero.
00146         return ( memcmp( a1._SockAddr, a2._SockAddr, sizeof(sockaddr_in)-8 ) == 0 );
00147 }
00148 
00149 
00150 /*
00151  * Comparison < operator
00152  */
00153 bool operator<( const CInetAddress& a1, const CInetAddress& a2 )
00154 {
00155 #ifdef NL_OS_WINDOWS
00156         if ( a1._SockAddr->sin_addr.S_un.S_addr == a2._SockAddr->sin_addr.S_un.S_addr )
00157         {
00158                 return ( a1.port() < a2.port() );
00159         }
00160         else
00161         {
00162                 return ( a1._SockAddr->sin_addr.S_un.S_addr < a2._SockAddr->sin_addr.S_un.S_addr );
00163         }
00164 #elif defined NL_OS_UNIX
00165         if ( a1._SockAddr->sin_addr.s_addr == a2._SockAddr->sin_addr.s_addr )
00166         {
00167                 return ( a1.port() < a2.port() );
00168         }
00169         else
00170         {
00171                 return ( a1._SockAddr->sin_addr.s_addr < a2._SockAddr->sin_addr.s_addr );
00172         }
00173 #endif  
00174 }
00175 
00176 
00177 /*
00178  * Constructor contents
00179  */
00180 void CInetAddress::init()
00181 {
00182         CSock::initNetwork(); 
00183         
00184         _Valid = false;
00185 
00186         _SockAddr = new sockaddr_in;
00187         _SockAddr->sin_family = AF_INET;
00188         memset( _SockAddr->sin_zero, 0, 8 );
00189 }
00190 
00191 
00192 /*
00193  * Destructor
00194  */
00195 CInetAddress::~CInetAddress()
00196 {
00197         delete _SockAddr;
00198         // _Valid = false;
00199 }
00200 
00201 /*
00202  * Sets hostname and port (ex: www.nevrax.com:80)
00203  */
00204 void CInetAddress::setNameAndPort( const std::string& hostNameAndPort )
00205 {
00206         uint32 pos = hostNameAndPort.find_first_of (':');
00207         if (pos != string::npos)
00208         {
00209                 setPort( atoi(hostNameAndPort.substr(pos + 1).c_str()) );
00210         }
00211         else
00212         {
00213                 setPort( 0 );
00214         }
00215 
00216         // if pos == -1, it will copy all the string
00217         setByName( hostNameAndPort.substr (0, pos) );
00218 }
00219 
00220 
00221 /*
00222  * Resolves a name
00223  */
00224 CInetAddress& CInetAddress::setByName( const std::string& hostName )
00225 {
00226         // Try to convert directly for addresses such as a.b.c.d
00227         in_addr iaddr;
00228 #ifdef NL_OS_WINDOWS
00229         iaddr.S_un.S_addr = inet_addr( hostName.c_str() );
00230         if ( iaddr.S_un.S_addr == INADDR_NONE )
00231 #elif defined NL_OS_UNIX
00232         iaddr.s_addr = inet_addr( hostName.c_str() );
00233         if ( iaddr.s_addr == INADDR_NONE )
00234 #endif
00235         {
00236 
00237                 // Otherwise use the traditional DNS look-up
00238                 hostent *phostent = gethostbyname( hostName.c_str() );
00239                 if ( phostent == NULL )
00240                 {
00241                         _Valid = false;
00242                         nldebug( "LNETL0: Network error: resolution of hostname '%s' failed", hostName.c_str() );
00243                         // return *this;
00244                         throw ESocket( (string("Hostname resolution failed for ")+hostName).c_str() );
00245                 }
00246                 _HostName = string( phostent->h_name );
00247                 memcpy( &_SockAddr->sin_addr, phostent->h_addr, sizeof(in_addr) );
00248         }
00249         else
00250         {
00251                 _HostName = hostName;
00252                 memcpy( &_SockAddr->sin_addr, &iaddr, sizeof(iaddr) );
00253         }
00254         _Valid = true;
00255         return *this;
00256 }
00257 
00258 
00259 /*
00260  * Sets port
00261  */
00262 void CInetAddress::setPort( uint16 port )
00263 {
00264         _SockAddr->sin_port = htons( port );
00265 
00266 }
00267 
00268 
00269 /* Sets internal socket address directly (contents is copied).
00270  * It also retrieves the host name if CInetAddress::RetrieveNames is true.
00271  */
00272 void CInetAddress::setSockAddr( const sockaddr_in* saddr )
00273 {
00274         memcpy( _SockAddr, saddr, sizeof(*saddr) );
00275 
00276         // Get host name
00277         // Warning: when it can't find it, it take more than 4 seconds
00278         if ( CInetAddress::RetrieveNames )
00279         {
00280                 hostent *phostent = gethostbyaddr( (char*)&saddr->sin_addr.s_addr, 4,  AF_INET );
00281                 if ( phostent == NULL )
00282                 {
00283                         _HostName = ipAddress();
00284                 }
00285                 else
00286                 {
00287                         _HostName = string( phostent->h_name );
00288                 }
00289         }
00290         _Valid = true;
00291 }
00292 
00293 
00294 /*
00295  * Returns if object (address and port) is valid
00296  */
00297 bool CInetAddress::isValid() const
00298 {
00299         return ( _Valid && _SockAddr->sin_port!=0 ); // same as ntohs(0)
00300 }
00301 
00302 
00303 /*
00304  * Returns internal socket address (read only)
00305  */
00306 const sockaddr_in *CInetAddress::sockAddr() const
00307 {
00308         return _SockAddr;
00309 }
00310 
00311 
00312 /*
00313  * Returns internal IP address
00314  */
00315 uint32 CInetAddress::internalIPAddress() const
00316 {
00317         return _SockAddr->sin_addr.s_addr;
00318 }
00319 
00320 uint32 CInetAddress::internalNetAddress() const
00321 {
00322         uint32 ip = internalIPAddress();
00323         if ((ip&0x00000080) == 0)
00324         {
00325                 // A class
00326                 return ip & 0x000000FF;
00327         }
00328         else if ((ip&0x00000040) == 0)
00329         {
00330                 // B class
00331                 return ip & 0x0000FFFF;
00332         }
00333         else if ((ip&0x00000020) == 0)
00334         {
00335                 // C class
00336                 return ip & 0x00FFFFFF;
00337         }
00338         else if ((ip&0x00000010) == 0)
00339         {
00340                 // D class
00341                 return ip & 0xFFFFFFFF;
00342         }
00343         else
00344         {
00345                 return ip;
00346         }
00347 }
00348 
00349 
00350 
00351 
00352 /*
00353  * Returns readable IP address. (ex: "195.68.21.195")
00354  */
00355 string CInetAddress::ipAddress() const
00356 {
00357         /*stringstream ss; // or use inet_ntoa
00358         ss << inet_ntoa ( _SockAddr->sin_addr );
00359         return ss.str();*/
00360         return string( inet_ntoa( _SockAddr->sin_addr ) );
00361 }
00362 
00363 
00364 /*
00365  * Returns host name. (ex: "www.nevrax.org")
00366  */
00367 const string& CInetAddress::hostName() const
00368 {
00369         return _HostName;
00370 }
00371 
00372 
00373 /*
00374  * Returns port
00375  */
00376 uint16 CInetAddress::port() const
00377 {
00378         return ntohs( _SockAddr->sin_port );
00379 }
00380 
00381 
00382 /*
00383  * Returns hostname and port as a string. (ex: "www.nevrax.org:80 (195.68.21.195)")
00384  */
00385 std::string CInetAddress::asString() const
00386 {
00387         stringstream ss;
00388         ss << hostName() << ":" << port() << " (" << ipAddress() << ")";
00389         return ss.str();
00390 }
00391 
00392 
00393 /*
00394  * Returns IP address and port as a string. (ex: "195.68.21.195:80")
00395  */
00396 std::string CInetAddress::asIPString() const
00397 {
00398         stringstream ss;
00399         ss << ipAddress() << ":" << port();
00400         return ss.str();
00401 }
00402 
00403 
00404 /*
00405  * Serialize
00406  */
00407 void CInetAddress::serial( NLMISC::IStream& s )
00408 {
00409         NLMISC::CMemStream *ms = dynamic_cast<NLMISC::CMemStream*>(&s);
00410         if ( ms && ms->stringMode() )
00411         {
00412                 // String stream
00413                 string addrs;
00414                 if ( ms->isReading() )
00415                 {
00416                         ms->serial( addrs );
00417                         setNameAndPort( addrs );
00418                 }
00419                 else
00420                 {
00421                         addrs = asIPString();
00422                         ms->serial( addrs );
00423                 }
00424                 s.serial( _Valid );
00425         }
00426         else
00427         {
00428                 // Binary stream
00429                 s.serialBuffer( (uint8*)_SockAddr, sizeof(*_SockAddr) ); // this is possible only because the contents of _SockAddr is platform-independant !
00430                 s.serial( _Valid );
00431 
00432                 if(_Valid)
00433                 {
00434                         // retreive the fullname
00435                         setSockAddr (_SockAddr);
00436                 }
00437         
00438         }
00439 }
00440 
00441 
00442 /*
00443  * Creates a CInetAddress object with local host address, port=0
00444  */
00445 CInetAddress CInetAddress::localHost()
00446 {
00447         const uint maxlength = 80;
00448         char localhost [maxlength];
00449         if ( gethostname( localhost, maxlength ) != 0 )
00450                 throw ESocket( "Unable to get local hostname" );
00451         CInetAddress localaddr = CInetAddress( string(localhost) );
00452 
00453         if ( localaddr.ipAddress() == "127.0.0.1" )
00454         {
00455                 nlwarning ("*** No network card detected! using localhost (127.0.0.1)");
00456         }
00457 
00458         return localaddr;
00459 }
00460 
00461 
00462 /* Returns the list of the local host addresses (with port=0)
00463  * (especially useful if the host is multihomed)
00464  */
00465 std::vector<CInetAddress> CInetAddress::localAddresses()
00466 {
00467         // 1. Get local host name
00468         const uint maxlength = 80;
00469         char localhost [maxlength];
00470         if ( gethostname( localhost, maxlength ) == SOCKET_ERROR )
00471         {
00472                 throw ESocket( "Unable to get local hostname" );
00473         }
00474 
00475         // 2. Get address list
00476     hostent *phostent = gethostbyname( localhost );
00477     if ( phostent == NULL )
00478         {
00479                 throw ESocket( (string("Hostname resolution failed for ")+string(localhost)).c_str() );
00480         }
00481         uint i;
00482         vector<CInetAddress> vect;
00483     for ( i=0; phostent->h_addr_list[i]!=0; ++i )
00484         {
00485                 vect.push_back( CInetAddress( (const in_addr*)(phostent->h_addr_list[i]) ) );
00486     } 
00487 
00488         if(vect.empty())
00489         {
00490                 throw ESocket( (string("No network card detected for ")+string(localhost)).c_str() );
00491         }
00492         
00493         return vect;
00494 }
00495 
00496 bool CInetAddress::is127001 () const 
00497 {
00498         return (internalIPAddress () == htonl(0x7F000001));
00499 }
00500 
00501 
00502 std::string vectorCInetAddressToString(const std::vector<CInetAddress> &addrs)
00503 {
00504         string str;
00505 
00506         for (uint i = 0; i < addrs.size(); i++)
00507         {
00508                 if (i != 0)
00509                         str += " ";
00510                 str += addrs[i].asString().c_str ();
00511         }
00512         return str;
00513 }
00514 
00515 uint32 stringToInternalIPAddress (const std::string &addr)
00516 {
00517         return inet_addr( addr.c_str() );
00518 }
00519 
00520 std::string internalIPAddressToString (uint32 addr)
00521 {
00522         string res;
00523         res = toString((addr)&0xFF);
00524         res += ".";
00525         res += toString((addr>>8)&0xFF);
00526         res += ".";
00527         res += toString((addr>>16)&0xFF);
00528         res += ".";
00529         res += toString((addr>>24)&0xFF);
00530         return res;
00531 }
00532 
00533 
00534 } // NLNET