00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanNetwork.h"
00028
00029 #include "CeylanOperators.h"
00030 #include "CeylanLogPlug.h"
00031 #include "CeylanSystem.h"
00032 #include "CeylanStringUtils.h"
00033 #include "CeylanRegularExpression.h"
00034 #include "CeylanIPAddressvFour.h"
00035
00036
00037 #ifdef CEYLAN_USES_CONFIG_H
00038 #include "CeylanConfig.h"
00039 #endif // CEYLAN_USES_CONFIG_H
00040
00041
00042
00043
00044 extern "C"
00045 {
00046
00047
00048 #ifdef CEYLAN_USES_UNISTD_H
00049 #include <unistd.h>
00050 #endif // CEYLAN_USES_UNISTD_H
00051
00052 #ifdef CEYLAN_USES_SYS_UTSNAME_H
00053 #include <sys/utsname.h>
00054 #endif // CEYLAN_USES_SYS_UTSNAME_H
00055
00056 #ifdef CEYLAN_USES_STRING_H
00057 #include <string.h>
00058 #endif // CEYLAN_USES_STRING_H
00059
00060 #ifdef CEYLAN_USES_SYS_SOCKET_H
00061 #include <sys/socket.h>
00062 #endif // CEYLAN_USES_SYS_SOCKET_H
00063
00064 #ifdef CEYLAN_USES_NETINET_IN_H
00065 #include <netinet/in.h>
00066 #endif // CEYLAN_USES_NETINET_IN_H
00067
00068 #ifdef CEYLAN_USES_ARPA_INET_H
00069 #include <arpa/inet.h>
00070 #endif // CEYLAN_USES_ARPA_INET_H
00071
00072 #ifdef CEYLAN_USES_WINSOCK2_H
00073 #include <winsock2.h>
00074 #endif // CEYLAN_USES_WINSOCK2_H
00075
00076 #ifdef CEYLAN_USES_SYS_SYSTEMINFO_H
00077 #include <sys/systeminfo.h>
00078 #endif // CEYLAN_USES_SYS_SYSTEMINFO_H
00079
00080 }
00081
00082
00083
00084
00085 #ifdef CEYLAN_USES_WS2TCPIP_H
00086 #include <ws2tcpip.h>
00087 #endif // CEYLAN_USES_WS2TCPIP_H
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 using namespace Ceylan::Network ;
00105 using namespace Ceylan::System ;
00106 using namespace Ceylan::Log ;
00107
00108 using namespace std ;
00109
00110
00111
00112
00113 NetworkException::NetworkException( const string & message ) :
00114 Ceylan::Exception( message )
00115 {
00116
00117 }
00118
00119
00120
00121 NetworkException::~NetworkException() throw()
00122 {
00123
00124 }
00125
00126
00127
00128
00129 const Ceylan::Uint16 Ceylan::Network::HostDNSEntry::HostNameMaxLength = 256 ;
00130
00131
00132
00133 #ifdef CEYLAN_USES_WS2TCPIP_H
00134
00135
00140 struct HostDNSEntry::SystemSpecificHostEntry
00141 {
00142
00143
00144
00145
00146
00147
00148 struct addrinfo* _entryList ;
00149
00150 SystemSpecificHostEntry() :
00151 _entryList( 0 )
00152 {
00153
00154 }
00155
00156 } ;
00157
00158
00159 #else // CEYLAN_USES_WS2TCPIP_H
00160
00161 #ifdef CEYLAN_USES_NETDB_H
00162
00163 #include <netdb.h>
00164
00165
00172 struct HostDNSEntry::SystemSpecificHostEntry
00173 {
00174
00175 hostent * _entry ;
00176
00177 SystemSpecificHostEntry() :
00178 _entry( 0 )
00179 {
00180
00181 }
00182
00183 } ;
00184
00185
00186 #endif // CEYLAN_USES_NETDB_H
00187
00188 #endif // CEYLAN_USES_WS2TCPIP_H
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 HostDNSEntry::HostDNSEntry( const std::string & hostName ) :
00207 _internalEntry( 0 )
00208 {
00209
00210 #ifdef CEYLAN_USES_WS2TCPIP_H
00211
00212 _internalEntry = new SystemSpecificHostEntry ;
00213
00214
00215 struct addrinfo callerHints ;
00216 ::memset( &callerHints, 0, sizeof(callerHints) ) ;
00217 callerHints.ai_family = PF_UNSPEC ;
00218 callerHints.ai_socktype = 0 ;
00219 callerHints.ai_protocol = 0 ;
00220 callerHints.ai_flags = AI_CANONNAME ;
00221
00222 #if CEYLAN_DEBUG_NETWORK
00223 LogPlug::debug( "HostDNSEntry constructor: "
00224 "running getaddrinfo for '" + hostName + "'." ) ;
00225 #endif // CEYLAN_DEBUG_NETWORK
00226
00227 if ( ::getaddrinfo( hostName.c_str(), 0,
00228 &callerHints, &_internalEntry->_entryList ) != 0 )
00229 {
00230 LogPlug::error( "HostDNSEntry constructor failed: "
00231 + Network::explainSocketError() ) ;
00232
00233 throw NetworkException( "HostDNSEntry constructor failed: "
00234 + Network::explainSocketError() ) ;
00235
00236 }
00237
00238
00239
00240 manageHostEntry() ;
00241
00242
00243
00244 #else // CEYLAN_USES_WS2TCPIP_H
00245
00246 #ifdef CEYLAN_USES_NETDB_H
00247
00248 _internalEntry = new SystemSpecificHostEntry ;
00249
00250 _internalEntry->_entry =::gethostbyname( hostName.c_str() ) ;
00251
00252
00253 if ( _internalEntry->_entry == 0 )
00254 LogPlug::error(
00255 "HostDNSEntry constructor failed for argument '"
00256 + hostName + "'." ) ;
00257
00258 manageHostEntry() ;
00259
00260
00261
00262
00263 #else // CEYLAN_USES_NETDB_H
00264
00265 throw NetworkException( "HostDNSEntry constructor from hostname failed: "
00266 "not supported on this platform." ) ;
00267
00268 #endif // CEYLAN_USES_NETDB_H
00269
00270 #endif // CEYLAN_USES_WS2TCPIP_H
00271
00272 }
00273
00274
00275
00276 HostDNSEntry::HostDNSEntry( const IPAddress & ip )
00277 {
00278
00279 #ifdef CEYLAN_USES_WS2TCPIP_H
00280
00281 _internalEntry = new SystemSpecificHostEntry ;
00282
00283
00284 struct addrinfo callerHints ;
00285 ::memset( &callerHints, 0, sizeof(callerHints) ) ;
00286 callerHints.ai_family = AF_INET ;
00287 callerHints.ai_socktype = 0 ;
00288 callerHints.ai_protocol = 0 ;
00289 callerHints.ai_flags = AI_NUMERICHOST ;
00290
00291 if ( ::getaddrinfo( ip.toString().c_str(), 0,
00292 &callerHints, &_internalEntry->_entryList ) != 0 )
00293 throw NetworkException( "HostDNSEntry constructor failed: "
00294 + Network::explainSocketError() ) ;
00295
00296
00297
00298 manageHostEntry() ;
00299
00300 #else // CEYLAN_USES_WS2TCPIP_H
00301
00302 #ifdef CEYLAN_USES_NETDB_H
00303
00304 _internalEntry = new SystemSpecificHostEntry ;
00305
00306
00307 struct in_addr binaryIp ;
00308
00309 if ( ::inet_aton( ip.toString().c_str(), &binaryIp ) == 0 )
00310 throw NetworkException( "HostDNSEntry constructor from IP failed: "
00311 "the conversion of " + ip.toString() + " to binary IP failed." ) ;
00312
00313 if ( ip.getType() == Network::IPv4 )
00314 _internalEntry->_entry =::gethostbyaddr(
00315 reinterpret_cast<const char *>( &binaryIp ),
00316 sizeof(in_addr), AF_INET ) ;
00317 else
00318 throw NetworkException( "HostDNSEntry constructor from IP failed: "
00319 "address type not supported on this platform." ) ;
00320
00321
00322 if ( _internalEntry->_entry == 0 )
00323 LogPlug::error(
00324 "HostDNSEntry constructor failed for argument '"
00325 + ip.toString() + "'." ) ;
00326
00327 manageHostEntry() ;
00328
00329
00330 #else // CEYLAN_USES_NETDB_H
00331
00332 throw NetworkException( "HostDNSEntry constructor from IP failed: "
00333 "not supported on this platform." ) ;
00334
00335 #endif // CEYLAN_USES_NETDB_H
00336
00337 #endif // CEYLAN_USES_WS2TCPIP_H
00338
00339 }
00340
00341
00342
00343 HostDNSEntry::~HostDNSEntry() throw()
00344 {
00345
00346 #ifdef CEYLAN_USES_WS2TCPIP_H
00347
00348 if ( _internalEntry != 0 )
00349 {
00350 ::freeaddrinfo( _internalEntry->_entryList ) ;
00351 delete _internalEntry ;
00352 }
00353
00354 #else // CEYLAN_USES_WS2TCPIP_H
00355
00356 #ifdef CEYLAN_USES_NETDB_H
00357
00358
00359 if ( _internalEntry != 0 )
00360 delete _internalEntry ;
00361
00362 #endif // CEYLAN_USES_NETDB_H
00363
00364 #endif // CEYLAN_USES_WS2TCPIP_H
00365
00366 }
00367
00368
00369
00370 string HostDNSEntry::getOfficialHostName() const
00371 {
00372
00373 #ifdef CEYLAN_USES_WS2TCPIP_H
00374
00375 if ( _internalEntry->_entryList->ai_canonname == 0 )
00376 throw NetworkException( "HostDNSEntry::getOfficialHostName: "
00377 "no available canonical name." ) ;
00378
00379 return string( _internalEntry->_entryList->ai_canonname ) ;
00380
00381 #else // CEYLAN_USES_WS2TCPIP_H
00382
00383 #ifdef CEYLAN_USES_NETDB_H
00384
00385 return string( _internalEntry->_entry->h_name ) ;
00386
00387 #else // CEYLAN_USES_NETDB_H
00388
00389 throw NetworkException( "HostDNSEntry::getOfficialHostName: "
00390 "not implemented yet." ) ;
00391
00392 #endif // CEYLAN_USES_NETDB_H
00393
00394 #endif // CEYLAN_USES_WS2TCPIP_H
00395
00396 }
00397
00398
00399
00400 list<string> & HostDNSEntry::getAliasList() const
00401 {
00402
00403 #ifdef CEYLAN_USES_WS2TCPIP_H
00404
00405 list<string> & res = * new list<string> ;
00406
00407 addrinfo * currentAlias = _internalEntry->_entryList->ai_next ;
00408
00409 while ( currentAlias != 0 )
00410 {
00411 if ( currentAlias->ai_canonname == 0 )
00412 {
00413
00414
00415 LogPlug::warning( "HostDNSEntry::getAliasList: "
00416 "an alias had not canonical name, "
00417 "it has been skipped." ) ;
00418 }
00419 else
00420 res.push_back( string( currentAlias->ai_canonname ) ) ;
00421
00422 currentAlias = currentAlias->ai_next ;
00423 }
00424
00425 return res ;
00426
00427 #else // CEYLAN_USES_WS2TCPIP_H
00428
00429 #ifdef CEYLAN_USES_NETDB_H
00430
00431 list<string> & res = * new list<string> ;
00432
00433 char** alias = _internalEntry->_entry->h_aliases ;
00434
00435 while ( (*alias) != 0 )
00436 {
00437 res.push_back( string( *alias ) ) ;
00438 alias++ ;
00439 }
00440
00441 return res ;
00442
00443 #else // CEYLAN_USES_NETDB_H
00444
00445 return * new list<string> ;
00446
00447 #endif // CEYLAN_USES_NETDB_H
00448
00449 #endif // CEYLAN_USES_WS2TCPIP_H
00450
00451 }
00452
00453
00454
00455 NetworkAddressType HostDNSEntry::getAddressType() const
00456 {
00457
00458 #ifdef CEYLAN_USES_WS2TCPIP_H
00459
00460 switch( _internalEntry->_entryList->ai_family )
00461 {
00462
00463 case AF_INET:
00464 return IPv4 ;
00465 break ;
00466
00467 case AF_INET6:
00468 return IPv6 ;
00469 break ;
00470
00471 default:
00472 LogPlug::error( "HostDNSEntry::getAddressType: "
00473 "unknown address type, returning IPv4 instead." ) ;
00474 return IPv4 ;
00475 break ;
00476
00477 }
00478
00479 return IPv4 ;
00480
00481 #else // CEYLAN_USES_WS2TCPIP_H
00482
00483 #ifdef CEYLAN_USES_NETDB_H
00484
00485 switch( _internalEntry->_entry->h_addrtype )
00486 {
00487
00488 case AF_INET:
00489 return IPv4 ;
00490 break ;
00491
00492 case AF_INET6:
00493 return IPv6 ;
00494 break ;
00495
00496 default:
00497 LogPlug::error( "HostDNSEntry::getAddressType: "
00498 "unknown address type, returning IPv4 instead." ) ;
00499 return IPv4 ;
00500 break ;
00501
00502 }
00503
00504 #else // CEYLAN_USES_NETDB_H
00505
00506 return IPv4 ;
00507
00508 #endif // CEYLAN_USES_NETDB_H
00509
00510 #endif // CEYLAN_USES_WS2TCPIP_H
00511
00512 }
00513
00514
00515
00516 list<IPAddress *> & HostDNSEntry::getAddresses() const
00517 {
00518
00519 #ifdef CEYLAN_USES_WS2TCPIP_H
00520
00521 list<IPAddress *> & res = * new list<IPAddress *> ;
00522
00523
00524
00525 addrinfo * currentAddressInfo = _internalEntry->_entryList ;
00526
00527 struct sockaddr_in * currentAddressStruct ;
00528 struct in_addr * currentEffectiveAddress ;
00529
00530 do
00531 {
00532
00533
00534
00535
00536
00537
00538
00539
00540 currentAddressStruct = reinterpret_cast<struct sockaddr_in*>(
00541 currentAddressInfo->ai_addr ) ;
00542
00543 char * decodedAddress ;
00544
00545 switch( currentAddressInfo->ai_family )
00546 {
00547
00548 case PF_INET:
00549 currentEffectiveAddress = & currentAddressStruct->sin_addr ;
00550 decodedAddress =::inet_ntoa( *currentEffectiveAddress ) ;
00551 if ( decodedAddress != 0 )
00552 res.push_back(
00553 new IPAddressvFour( string( decodedAddress ) ) ) ;
00554 else
00555 LogPlug::error( "HostDNSEntry::getAddresses: "
00556 "unable to decode address, skipping it." ) ;
00557 break ;
00558
00559 case PF_INET6:
00560 LogPlug::error( "HostDNSEntry::getAddresses: "
00561 "IPv6 not supported yet, skipping address entry." ) ;
00562 break ;
00563
00564 default:
00565 LogPlug::error( "HostDNSEntry::getAddresses: "
00566 "unsupported address type ("
00567 + Ceylan::toString( currentAddressInfo->ai_family )
00568 + "), skipping address entry." ) ;
00569 break ;
00570
00571 }
00572
00573 currentAddressInfo = currentAddressInfo->ai_next ;
00574
00575 }
00576 while ( currentAddressInfo != 0 ) ;
00577
00578 return res ;
00579
00580
00581 #else // CEYLAN_USES_WS2TCPIP_H
00582
00583 #ifdef CEYLAN_USES_NETDB_H
00584
00585 list<IPAddress *> & res = * new list<IPAddress *> ;
00586
00587
00588
00589 Ceylan::Uint16 addrLen = _internalEntry->_entry->h_length ;
00590
00591 struct in_addr currentAddressBuffer ;
00592
00593 char ** currentAddress = _internalEntry->_entry->h_addr_list ;
00594
00595 switch( getAddressType() )
00596 {
00597
00598 case IPv4:
00599
00600 while ( *currentAddress != 0 )
00601 {
00602
00603 ::memcpy( & currentAddressBuffer, *currentAddress, addrLen ) ;
00604
00605 string decodedAddress(
00606 ::inet_ntoa( currentAddressBuffer ) ) ;
00607
00608 res.push_back( new IPAddressvFour( decodedAddress ) ) ;
00609 currentAddress++ ;
00610
00611 }
00612 break ;
00613
00614
00615 case IPv6:
00616 LogPlug::error( "HostDNSEntry::getAddresses: "
00617 "IPv6 not supported yet, returning empty list." ) ;
00618 break ;
00619
00620 default:
00621 LogPlug::error( "HostDNSEntry::getAddresses: "
00622 "unexpected address type, returning empty list." ) ;
00623 break ;
00624
00625 }
00626
00627 return res ;
00628
00629
00630 #else // CEYLAN_USES_NETDB_H
00631
00632 return * new list<IPAddress *> ;
00633
00634 #endif // CEYLAN_USES_NETDB_H
00635
00636 #endif // CEYLAN_USES_WS2TCPIP_H
00637
00638 }
00639
00640
00641
00642 const string HostDNSEntry::toString( Ceylan::VerbosityLevels level ) const
00643 {
00644
00645 string res ;
00646
00647 try
00648 {
00649 res = "The host '" + getOfficialHostName() + "' has " ;
00650 }
00651 catch( const NetworkException & e )
00652 {
00653 res = "HostDNSEntry::toString: "
00654 "no official name could be found for this host (abnormal)" ;
00655 LogPlug::error( res ) ;
00656 return res ;
00657 }
00658
00659 list<string> * alias = & getAliasList() ;
00660
00661 if ( alias->empty() )
00662 {
00663 res += "no alias. " ;
00664 }
00665 else
00666 {
00667 res += "following name alias: " + formatStringList( *alias ) ;
00668
00669 }
00670 delete alias ;
00671
00672 res += "Its address type is " ;
00673
00674 switch( getAddressType() )
00675 {
00676
00677 case IPv4:
00678 res += "IPv4" ;
00679 break ;
00680
00681 case IPv6:
00682 res += "IPv6" ;
00683 break ;
00684
00685 default:
00686 res += "unknown (abnormal)" ;
00687 break ;
00688
00689 }
00690
00691 res += ". Its known network addresses are: " ;
00692
00693 list<IPAddress *> * addresses = & getAddresses() ;
00694
00695 list<string> addressDescriptions ;
00696
00697 for ( list<IPAddress *>::const_iterator it = addresses->begin();
00698 it != addresses->end(); it++ )
00699 addressDescriptions.push_back( (*it)->toString( level ) ) ;
00700
00701 delete addresses ;
00702
00703 return res + formatStringList( addressDescriptions ) ;
00704
00705 }
00706
00707
00708
00709 void HostDNSEntry::manageHostEntry()
00710 {
00711
00712 #ifdef CEYLAN_USES_WS2TCPIP_H
00713
00714 if ( _internalEntry->_entryList == 0 )
00715 throw NetworkException( "HostDNSEntry constructor failed "
00716 "(in HostDNSEntry::manageHostEntry), no entry found" ) ;
00717
00718 #else // CEYLAN_USES_WS2TCPIP_H
00719
00720 #ifdef CEYLAN_USES_NETDB_H
00721
00722 if ( _internalEntry->_entry == 0 )
00723 {
00724
00725 switch( h_errno )
00726 {
00727
00728 case HOST_NOT_FOUND:
00729 throw NetworkException( "HostDNSEntry constructor failed: "
00730 "the specified host is unknown." ) ;
00731 break ;
00732
00733 case NO_ADDRESS :
00734 throw NetworkException( "HostDNSEntry constructor failed: "
00735 "the requested name is valid but "
00736 "does not have an IP address." ) ;
00737 break ;
00738
00739 case NO_RECOVERY:
00740 throw NetworkException( "HostDNSEntry constructor failed: "
00741 "a non-recoverable name server error occurred." ) ;
00742 break ;
00743
00744 case TRY_AGAIN:
00745 throw NetworkException( "HostDNSEntry constructor failed: "
00746 "a temporary error occurred on "
00747 "an authoritative name server. Try again later" ) ;
00748 break ;
00749
00750 default:
00751 throw NetworkException( "HostDNSEntry constructor failed: "
00752 "unexpected error code" ) ;
00753 break ;
00754
00755 }
00756 }
00757
00758 #else // CEYLAN_USES_NETDB_H
00759
00760
00761
00762 #endif // CEYLAN_USES_NETDB_H
00763
00764 #endif // CEYLAN_USES_WS2TCPIP_H
00765
00766 }
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776 const string Ceylan::Network::getLocalHostName()
00777 {
00778
00779 #ifdef CEYLAN_USES_WINSOCK2_H
00780
00781
00782 char hostBuffer[ HostDNSEntry::HostNameMaxLength + 1 ] ;
00783
00784 if ( ::gethostname( hostBuffer, HostDNSEntry::HostNameMaxLength ) != 0 )
00785 throw NetworkException( "Ceylan::Network::getLocalHostName: "
00786 "unable to determine local host name (error code: "
00787 + Ceylan::toString( WSAGetLastError() ) + ")." ) ;
00788
00789 return string( hostBuffer ) ;
00790
00791 #else // CEYLAN_USES_WINSOCK2_H
00792
00793 #ifdef CEYLAN_USES_GETHOSTNAME
00794
00795
00796
00797
00798 char hostBuffer[ HostDNSEntry::HostNameMaxLength + 1 ] ;
00799
00800 if ( ::gethostname( hostBuffer, HostDNSEntry::HostNameMaxLength ) != 0 )
00801 throw NetworkException( "Ceylan::Network::getLocalHostName: "
00802 "unable to determine local host name: " + explainError() ) ;
00803
00804 return string( hostBuffer ) ;
00805
00806 #else // CEYLAN_USES_GETHOSTNAME
00807
00808 throw NetworkException( "Ceylan::Network::getLocalHostName: "
00809 "not available on this platform." ) ;
00810
00811 #endif // CEYLAN_USES_GETHOSTNAME
00812
00813 #endif // CEYLAN_USES_WINSOCK2_H
00814
00815 }
00816
00817
00818
00819 void Ceylan::Network::setLocalHostName( const string & newHostName )
00820 {
00821
00822 #ifdef CEYLAN_USES_SETHOSTNAME
00823
00824 #if CEYLAN_ARCH_SOLARIS
00825
00826
00827
00828
00829
00830
00831 const char * buf = newHostName.c_str() ;
00832 if ( ::sysinfo( SI_SET_HOSTNAME, const_cast<char *>( buf ),
00833 newHostName.size() ) == -1 )
00834 throw NetworkException( "Ceylan::Network::setLocalHostName: "
00835 "unable to set local host name on Solaris to "
00836 + newHostName + ": " + explainError() ) ;
00837
00838 #else // CEYLAN_ARCH_SOLARIS
00839
00840 if ( ::sethostname( newHostName.c_str(), newHostName.size() ) )
00841 throw NetworkException( "Ceylan::Network::setLocalHostName: "
00842 "unable to set local host name to "
00843 + newHostName + ": " + explainError() ) ;
00844
00845 #endif // CEYLAN_ARCH_SOLARIS
00846
00847
00848 #else // CEYLAN_USES_SETHOSTNAME
00849
00850 throw NetworkException( "Ceylan::Network::setLocalHostName: "
00851 "not available on this platform." ) ;
00852
00853 #endif // CEYLAN_USES_SETHOSTNAME
00854
00855 }
00856
00857
00858
00859 const string Ceylan::Network::getLocalHostDomainName()
00860 {
00861
00862 #ifdef CEYLAN_USES_GETDOMAINNAME
00863
00864 char domainBuffer[ 256 ] ;
00865
00866 if ( ::getdomainname( domainBuffer, 255 ) != 0 )
00867 throw NetworkException( "Unable to determine local host domain name: "
00868 + explainError() ) ;
00869
00870 string res( domainBuffer ) ;
00871
00872 if ( res == "(none)" )
00873 return "" ;
00874
00875 return res ;
00876
00877 #else // CEYLAN_USES_GETDOMAINNAME
00878
00879 throw NetworkException( "Ceylan::Network::getLocalHostDomainName: "
00880 "not available on this platform." ) ;
00881
00882 #endif // CEYLAN_USES_GETDOMAINNAME
00883
00884 }
00885
00886
00887
00888 void Ceylan::Network::setLocalHostDomainName( const string & newDomainName )
00889 {
00890
00891 #ifdef CEYLAN_USES_SETDOMAINNAME
00892
00893 if ( ::setdomainname( newDomainName.c_str(), newDomainName.size() ) )
00894 throw NetworkException( "Unable to set local host domain name to "
00895 + newDomainName + ": "
00896 + explainError() ) ;
00897
00898 #else // CEYLAN_USES_SETDOMAINNAME
00899
00900 throw NetworkException( "Ceylan::Network::setLocalHostDomainName: "
00901 "not available on this platform." ) ;
00902
00903 #endif // CEYLAN_USES_SETDOMAINNAME
00904
00905 }
00906
00907
00908
00909 const string Ceylan::Network::getMostPreciseLocalHostName()
00910 {
00911
00912 #if CEYLAN_ARCH_NINTENDO_DS
00913
00914
00915 return "nds" ;
00916
00917 #else // CEYLAN_ARCH_NINTENDO_DS
00918
00919
00920 string guessedFullHostname ;
00921
00922 #ifdef CEYLAN_USES_UNAME
00923
00924 struct utsname buf ;
00925
00926 if ( ::uname( & buf ) != 0 )
00927 {
00928 LogPlug::error( "Ceylan::Network::getMostPreciseLocalHostName: "
00929 "unable to determine name of local host: " + explainError() ) ;
00930 }
00931 else
00932 {
00933
00934 guessedFullHostname = buf.nodename ;
00935
00936
00937 if ( Ceylan::countChars( guessedFullHostname, '.' ) != 0
00938 && guessedFullHostname != "localhost.localdomain" )
00939 return guessedFullHostname ;
00940
00941 }
00942
00943 #endif // CEYLAN_USES_UNAME
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956 string thisHostname = getLocalHostName() ;
00957
00958 bool found = false ;
00959
00960 try
00961 {
00962
00963 guessedFullHostname = getFQDNFromHostname( thisHostname ) ;
00964 found = true ;
00965
00966 }
00967 catch( const NetworkException & e )
00968 {
00969 LogPlug::debug( "Ceylan::Network::getMostPreciseLocalHostName: "
00970 "FQDN not available: " + e.toString() ) ;
00971 }
00972
00973 if ( found && guessedFullHostname != "localhost.localdomain" )
00974 return guessedFullHostname ;
00975
00976
00977
00978
00979
00980
00981
00982 string domain ;
00983
00984 try
00985 {
00986
00987
00988 domain = getLocalHostDomainName() ;
00989
00990 }
00991 catch( const NetworkException & e )
00992 {
00993 LogPlug::debug( "Ceylan::Network::getMostPreciseLocalHostName: "
00994 "domain name not available: " + e.toString() ) ;
00995 domain = "" ;
00996
00997 }
00998
00999 if ( ! domain.empty() )
01000 {
01001
01002 return thisHostname + "." + domain ;
01003 }
01004
01005
01006 return thisHostname ;
01007
01008 #endif // CEYLAN_ARCH_NINTENDO_DS
01009
01010 }
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020 const string Ceylan::Network::getFQDNFromIP( const IPAddress & ip )
01021 {
01022
01023 HostDNSEntry searched( ip ) ;
01024
01025 return getFQDNFromDNSEntry( searched ) ;
01026
01027 }
01028
01029
01030
01031 const string Ceylan::Network::getFQDNFromIPv4( const std::string & ipString )
01032 {
01033
01034 IPAddressvFour ip( ipString ) ;
01035
01036 return getFQDNFromIP( ip ) ;
01037
01038 }
01039
01040
01041
01042 const string Ceylan::Network::getFQDNFromHostname(
01043 const std::string & hostname )
01044 {
01045
01046 HostDNSEntry searched( hostname ) ;
01047
01048 return getFQDNFromDNSEntry( searched ) ;
01049
01050 }
01051
01052
01053
01054 const string Ceylan::Network::getFQDNFromDNSEntry( const HostDNSEntry & entry )
01055 {
01056
01057 string current ;
01058
01059 try
01060 {
01061 current = entry.getOfficialHostName() ;
01062 }
01063 catch( const NetworkException & e )
01064 {
01065 LogPlug::debug( "Ceylan::Network::getFQDNFromDNSEntry: "
01066 "no official name found." ) ;
01067 }
01068
01069
01070 if ( Ceylan::countChars( current, '.' ) != 0 )
01071 return current ;
01072
01073
01074 list<string> * alias = & entry.getAliasList() ;
01075
01076 for ( list<string>::const_iterator it = alias->begin() ;
01077 it != alias->end(); it++ )
01078 {
01079 if ( Ceylan::countChars( (*it), '.' ) != 0 )
01080 {
01081 current = *it ;
01082 break ;
01083 }
01084 }
01085
01086 delete alias ;
01087
01088 if ( current.empty() )
01089 throw NetworkException( "Ceylan::Network::getFQDNFromDNSEntry "
01090 "failed to find any FQDN from following entry: "
01091 + entry.toString() ) ;
01092
01093 return current ;
01094
01095 }
01096
01097
01098
01099 bool Ceylan::Network::isAValidHostName( const string & hostnameString )
01100 {
01101
01102 #if CEYLAN_USES_REGEX
01103
01104 Ceylan::RegExp target( hostnameString ) ;
01105
01106 return target.matches(
01107 "^(([a-z]|[A-Z]{1,1})([a-z]|[A-Z]|[.]|[0-9]|[-]){0,})$" ) ;
01108
01109 #else // CEYLAN_USES_REGEX
01110
01111
01112 return true ;
01113
01114 #endif // CEYLAN_USES_REGEX
01115
01116 }
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129 string Ceylan::Network::interpretSocketError( SocketError errorCode )
01130 {
01131
01132 #if CEYLAN_ARCH_WINDOWS
01133
01134 switch( errorCode )
01135 {
01136
01137 case WSAEINTR:
01138 return "interrupted function call (WSAEINTR): "
01139 "a blocking operation was interrupted "
01140 "by a call to WSACancelBlockingCall" ;
01141 break ;
01142
01143 case WSAEACCES:
01144 return "permission denied (WSAEACCES): "
01145 "an attempt was made to access a socket in a way forbidden "
01146 "by its access permissions" ;
01147 break ;
01148
01149 case WSAEFAULT:
01150 return "bad address (WSAEFAULT): "
01151 "the system detected an invalid pointer address in attempting "
01152 "to use a pointer argument of a call" ;
01153 break ;
01154
01155 case WSAEINVAL:
01156 return "invalid argument (WSAEINVAL): "
01157 "some invalid argument was supplied" ;
01158 break ;
01159
01160 case WSAEMFILE:
01161 return "too many open sockets (WSAEMFILE)" ;
01162 break ;
01163
01164 case WSAEWOULDBLOCK:
01165 return "resource temporarily unavailable (WSAEWOULDBLOCK): "
01166 "this error is returned from operations on nonblocking sockets "
01167 "that cannot be completed immediately" ;
01168 break ;
01169
01170 case WSAEINPROGRESS:
01171 return "operation now in progress (WSAEINPROGRESS): "
01172 "a blocking operation is currently executing" ;
01173 break ;
01174
01175 case WSAEALREADY:
01176 return "operation already in progress (WSAEALREADY): "
01177 "an operation was attempted on a nonblocking socket "
01178 "with an operation already in progress" ;
01179 break ;
01180
01181 case WSAENOTSOCK:
01182 return "socket operation on nonsocket (WSAENOTSOCK): "
01183 "an operation was attempted on something that is not a socket" ;
01184 break ;
01185
01186 case WSAEDESTADDRREQ:
01187 return "destination address required (WSAEDESTADDRREQ): "
01188 "a required address was omitted from an operation on a socket" ;
01189 break ;
01190
01191 case WSAEMSGSIZE:
01192 return "message too long (WSAEMSGSIZE): "
01193 "a message sent on a datagram socket was larger than supported" ;
01194 break ;
01195
01196 case WSAEPROTOTYPE:
01197 return "wrong protocol type for socket (WSAEPROTOTYPE)" ;
01198 break ;
01199
01200 case WSAENOPROTOOPT:
01201 return "bad protocol option (WSAENOPROTOOPT): "
01202 "unknown, invalid or unsupported option or level" ;
01203 break ;
01204
01205 case WSAEPROTONOSUPPORT:
01206 return "requested protocol not supported on this system "
01207 "(WSAEPROTONOSUPPORT)" ;
01208 break ;
01209
01210 case WSAESOCKTNOSUPPORT:
01211 return "socket type not supported (WSAESOCKTNOSUPPORT): "
01212 "the support for the specified socket type does not exist "
01213 "in this address family" ;
01214 break ;
01215
01216 case WSAEOPNOTSUPP:
01217 return "operation not supported (WSAEOPNOTSUPP): "
01218 "the attempted operation is not supported "
01219 "for the type of object referenced" ;
01220 break ;
01221
01222 case WSAEPFNOSUPPORT:
01223 return "protocol family not supported on this system "
01224 "(WSAEPFNOSUPPORT)" ;
01225 break ;
01226
01227 case WSAEAFNOSUPPORT:
01228 return "address family not supported by protocol family "
01229 "(WSAEAFNOSUPPORT)" ;
01230 break ;
01231
01232 case WSAEADDRINUSE:
01233 return "address already in use (WSAEADDRINUSE): "
01234 "typically, only one usage of each socket address "
01235 "(protocol/IP address/port) is permitted" ;
01236 break ;
01237
01238 case WSAEADDRNOTAVAIL:
01239 return "cannot assign requested address (WSAEADDRNOTAVAIL): "
01240 "the requested address is not valid in its context" ;
01241 break ;
01242
01243 case WSAENETDOWN:
01244 return "network is down (WSAENETDOWN): "
01245 "a socket operation encountered a dead network" ;
01246 break ;
01247
01248 case WSAENETUNREACH:
01249 return "network is unreachable (WSAENETUNREACH): "
01250 "a socket operation was attempted to an unreachable network" ;
01251 break ;
01252
01253 case WSAENETRESET:
01254 return "network dropped connection on reset (WSAENETRESET)" ;
01255 break ;
01256
01257 case WSAECONNABORTED:
01258 return "software caused connection abort (WSAECONNABORTED): "
01259 "an established connection was aborted by the software "
01260 "in your host computer" ;
01261 break ;
01262
01263 case WSAECONNRESET:
01264 return "connection reset by peer (WSAECONNRESET): "
01265 "an existing connection was forcibly closed by the remote host" ;
01266 break ;
01267
01268 case WSAENOBUFS:
01269 return "no buffer space available (WSAENOBUFS)" ;
01270 break ;
01271
01272 case WSAEISCONN:
01273 return "socket is already connected (WSAEISCONN): "
01274 "a connect request was made on an already-connected socket" ;
01275 break ;
01276
01277 case WSAENOTCONN:
01278 return "socket is not connected (WSAENOTCONN): "
01279 "a request to send or receive data was disallowed because "
01280 "the socket is not connected and/or no address was supplied" ;
01281 break ;
01282
01283 case WSAESHUTDOWN:
01284 return "cannot send after socket shutdown (WSAESHUTDOWN): "
01285 "a request to send or receive data was disallowed because "
01286 "the socket had already been shut down in that direction" ;
01287 break ;
01288
01289 case WSAETIMEDOUT:
01290 return "a connection attempt failed because of a time-out "
01291 "(WSAETIMEDOUT)" ;
01292 break ;
01293
01294 case WSAECONNREFUSED:
01295 return "connection refused (WSAECONNREFUSED): "
01296 "no connection could be made because "
01297 "the target computer actively refused it" ;
01298 break ;
01299
01300 case WSAEHOSTDOWN:
01301 return "host is down (WSAEHOSTDOWN): "
01302 "a socket operation failed because the destination host is down" ;
01303 break ;
01304
01305 case WSAEHOSTUNREACH:
01306 return "no route to host (WSAEHOSTUNREACH): "
01307 "a socket operation was attempted to an unreachable host" ;
01308 break ;
01309
01310 case WSAEPROCLIM:
01311 return "too many processes (WSAEPROCLIM): "
01312 "a Windows Sockets implementation may have a limit on "
01313 "the number of applications that can use it simultaneously" ;
01314 break ;
01315
01316 case WSASYSNOTREADY:
01317 return "network subsystem is unavailable (WSASYSNOTREADY)" ;
01318 break ;
01319
01320 case WSAVERNOTSUPPORTED:
01321 return "Winsock.dll version out of range (WSAVERNOTSUPPORTED): "
01322 "the current Windows Sockets implementation "
01323 "does not support the Windows Sockets specification version "
01324 "requested by the application" ;
01325 break ;
01326
01327 case WSANOTINITIALISED:
01328 return "successful WSAStartup not yet performed (WSANOTINITIALISED)" ;
01329 break ;
01330
01331 case WSAEDISCON:
01332 return "graceful shutdown in progress (WSAEDISCON)" ;
01333 break ;
01334
01335 case WSATYPE_NOT_FOUND:
01336 return "class type not found (WSATYPE_NOT_FOUND)" ;
01337 break ;
01338
01339 case WSAHOST_NOT_FOUND:
01340 return "host not found (WSAHOST_NOT_FOUND): "
01341 "no such host is known" ;
01342 break ;
01343
01344 case WSATRY_AGAIN:
01345 return "nonauthoritative host not found (WSATRY_AGAIN): "
01346 "this is usually a temporary error during host name resolution" ;
01347 break ;
01348
01349 case WSANO_RECOVERY:
01350 return "nonrecoverable error (WSANO_RECOVERY) occurred "
01351 "during a database lookup" ;
01352 break ;
01353
01354 case WSANO_DATA:
01355 return "valid name, no data record of requested type (WSANO_DATA)" ;
01356 break ;
01357
01358 case WSA_INVALID_HANDLE:
01359 return "specified event object handle is invalid "
01360 "(WSA_INVALID_HANDLE)" ;
01361 break ;
01362
01363 case WSA_INVALID_PARAMETER:
01364 return "one or more parameters are invalid (WSA_INVALID_PARAMETER)" ;
01365 break ;
01366
01367 case WSA_IO_INCOMPLETE:
01368 return "overlapped I/O event object not in signaled state "
01369 "(WSA_IO_INCOMPLETE): the application has tried to determine the"
01370 " status of an overlapped operation which is not yet completed" ;
01371 break ;
01372
01373 case WSA_IO_PENDING:
01374 return "overlapped operations will complete later (WSA_IO_PENDING): "
01375 "the application has initiated an overlapped operation that "
01376 "cannot be completed immediately" ;
01377 break ;
01378
01379 case WSA_NOT_ENOUGH_MEMORY:
01380 return "insufficient memory available (WSA_NOT_ENOUGH_MEMORY)" ;
01381 break ;
01382
01383 case WSA_OPERATION_ABORTED:
01384 return "overlapped operation aborted (WSA_OPERATION_ABORTED)" ;
01385 break ;
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406 case WSASYSCALLFAILURE:
01407 return "system call failure (WSASYSCALLFAILURE): "
01408 "generic error code" ;
01409 break ;
01410
01411 default:
01412 return "unknown socket error code #"
01413 + Ceylan::toString( errorCode ) + " (abnormal)" ;
01414
01415 }
01416
01417 #else // CEYLAN_ARCH_WINDOWS
01418
01419 return "nothing appropriate for the current platform "
01420 "(abnormal)" ;
01421
01422 #endif // CEYLAN_ARCH_WINDOWS
01423
01424 }
01425
01426
01427
01428 SocketError Ceylan::Network::getSocketError()
01429 {
01430
01431 #if CEYLAN_ARCH_WINDOWS
01432
01433 return WSAGetLastError() ;
01434
01435 #else // CEYLAN_ARCH_WINDOWS
01436
01437 LogPlug::error( "Ceylan::Network::getSocketError called "
01438 "whereas not on Windows." ) ;
01439
01440 return 0 ;
01441
01442 #endif // CEYLAN_ARCH_WINDOWS
01443
01444 }
01445
01446
01447
01448 std::string Ceylan::Network::explainSocketError()
01449 {
01450
01451 #if CEYLAN_ARCH_WINDOWS
01452
01453 return interpretSocketError( getSocketError() ) ;
01454
01455 #else // CEYLAN_ARCH_WINDOWS
01456
01457 return "Ceylan::Network::explainSocketError should not be "
01458 "used on this platform" ;
01459
01460 #endif // CEYLAN_ARCH_WINDOWS
01461
01462 }
01463
01464
01465
01466
01467
01468
01469
01470
01471 #if CEYLAN_ARCH_WINDOWS
01472
01473 NetworkManager NetworkManager::_Manager ;
01474
01475
01476 NetworkManager::NetworkManager()
01477 {
01478
01479 #if CEYLAN_DEBUG_SYSTEM
01480
01481 Ceylan::display( "NetworkManager constructor: "
01482 "initializing network subsystem." ) ;
01483
01484 #endif // CEYLAN_DEBUG_SYSTEM
01485
01486 WORD requestedVersion = MAKEWORD( 2, 2 ) ;
01487 WSADATA wsaData ;
01488
01489 int result = WSAStartup( requestedVersion, & wsaData ) ;
01490
01491 if ( result != 0 )
01492 throw NetworkException( "NetworkManager constructor failed: "
01493 "no usable WinSock DLL found (error code: "
01494 + Ceylan::toString( result ) + ")." ) ;
01495
01496
01497
01498
01499
01500
01501
01502
01503 if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
01504 {
01505 WSACleanup() ;
01506 throw NetworkException( "NetworkManager constructor failed: "
01507 "this version of Winsock DLL is not supported." ) ;
01508 }
01509
01510 }
01511
01512
01513
01514 NetworkManager::~NetworkManager() throw()
01515 {
01516
01517 #if CEYLAN_DEBUG_SYSTEM
01518
01519 Ceylan::display( "NetworkManager destructor: "
01520 "shutting down network subsystem." ) ;
01521
01522 #endif // CEYLAN_DEBUG_SYSTEM
01523
01524 WSACleanup() ;
01525
01526 }
01527
01528
01529 #endif // CEYLAN_ARCH_WINDOWS
01530