blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00039 #include "blocxx/BLOCXX_config.h" 00040 #include "blocxx/SocketAddress.hpp" 00041 #include "blocxx/ByteSwap.hpp" 00042 #include "blocxx/Assertion.hpp" 00043 #include "blocxx/Mutex.hpp" 00044 #include "blocxx/MutexLock.hpp" 00045 #include "blocxx/ExceptionIds.hpp" 00046 #include "blocxx/Format.hpp" 00047 00048 extern "C" 00049 { 00050 #if !defined(BLOCXX_WIN32) 00051 #include <netdb.h> 00052 #include <netinet/in.h> 00053 #include <arpa/inet.h> 00054 #include <sys/param.h> 00055 #include <sys/utsname.h> 00056 #include <unistd.h> 00057 #endif 00058 00059 #include <errno.h> 00060 } 00061 00062 namespace BLOCXX_NAMESPACE 00063 { 00064 00065 #ifdef BLOCXX_WIN32 00066 00067 #include <WS2tcpip.h> 00068 00069 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) 00070 { 00071 if (af == AF_INET) 00072 { 00073 struct sockaddr_in in; 00074 memset(&in, 0, sizeof(in)); 00075 in.sin_family = AF_INET; 00076 memcpy(&in.sin_addr, src, sizeof(struct in_addr)); 00077 getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); 00078 return dst; 00079 } 00080 else if (af == AF_INET6) 00081 { 00082 struct sockaddr_in6 in; 00083 memset(&in, 0, sizeof(in)); 00084 in.sin6_family = AF_INET6; 00085 memcpy(&in.sin6_addr, src, sizeof(struct in_addr6)); 00086 getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST); 00087 return dst; 00088 } 00089 return NULL; 00090 } 00091 #endif 00092 00093 BLOCXX_DEFINE_EXCEPTION_WITH_ID(UnknownHost); 00094 BLOCXX_DEFINE_EXCEPTION_WITH_ID(SocketAddress); 00095 00096 const char* const SocketAddress::ALL_LOCAL_ADDRESSES = "0.0.0.0"; 00097 00098 #if !defined(BLOCXX_WIN32) 00099 00100 //static 00101 SocketAddress 00102 SocketAddress::getUDS(const String& filename) 00103 { 00104 SocketAddress rval; 00105 rval.m_type = UDS; 00106 rval.m_name = filename; 00107 rval.m_address = "localhost"; 00108 memset(&rval.m_UDSNativeAddress, 0, sizeof(rval.m_UDSNativeAddress)); 00109 rval.m_UDSNativeAddress.sun_family = AF_UNIX; 00110 strncpy(rval.m_UDSNativeAddress.sun_path, filename.c_str(), 00111 sizeof(rval.m_UDSNativeAddress.sun_path) - 1); 00112 if (::strlen(rval.m_UDSNativeAddress.sun_path) != filename.length()) 00113 { 00114 BLOCXX_THROW(SocketAddressException, Format("UDS filename (%1) is too long", filename).c_str()); 00115 } 00116 #ifdef BLOCXX_SOLARIS 00117 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path) + 00118 offsetof(struct sockaddr_un, sun_path); 00119 #elif defined BLOCXX_OPENUNIX 00120 rval.m_UDSNativeAddress.sun_len = sizeof(rval.m_UDSNativeAddress); 00121 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path) + 00122 offsetof(struct sockaddr_un, sun_path); 00123 #elif defined BLOCXX_AIX || defined BLOCXX_DARWIN 00124 // AIX requires the NULL terminator to be included in the sizes. 00125 rval.m_UDSNativeAddress.sun_len = filename.length() + 1; 00126 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path) + 00127 offsetof(struct sockaddr_un, sun_path) + 1; 00128 #elif defined BLOCXX_FREEBSD 00129 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path) 00130 + sizeof(rval.m_UDSNativeAddress.sun_len) 00131 + sizeof(rval.m_UDSNativeAddress.sun_family); 00132 #else 00133 rval.m_nativeSize = sizeof(rval.m_UDSNativeAddress.sun_family) + 00134 ::strlen(rval.m_UDSNativeAddress.sun_path); 00135 #endif 00136 return rval; 00137 } 00138 00139 #endif // #if !defined(BLOCXX_WIN32) 00140 00142 SocketAddress::SocketAddress() 00143 : m_nativeSize(0) , m_type(UNSET) 00144 { 00145 } 00146 00147 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R 00148 Mutex gethostbynameMutex; 00149 #endif 00150 00152 //static 00153 SocketAddress 00154 SocketAddress::getByName(const String& hostName, UInt16 port) 00155 { 00156 #ifdef BLOCXX_HAVE_IPV6 00157 // create SocketAddress structure for IPV6 protocol 00158 InetSocketAddress_t sa; 00159 memset(&sa, 0, sizeof(sa)); 00160 if( inet_pton(AF_INET6, hostName.c_str(), (void*)&(reinterpret_cast<sockaddr_in6*>(&sa)->sin6_addr))) 00161 { 00162 reinterpret_cast<sockaddr_in6*>(&sa)->sin6_family = AF_INET6; 00163 reinterpret_cast<sockaddr_in6*>(&sa)->sin6_port = htons(port); 00164 SocketAddress p = SocketAddress(sa); 00165 p.m_type = INET; 00166 p.m_name = hostName; 00167 return p; 00168 } 00169 #endif 00170 #if defined(BLOCXX_HAVE_GETHOSTBYNAME_R) && defined(BLOCXX_GETHOSTBYNAME_R_ARGUMENTS) 00171 hostent hostbuf; 00172 hostent* host = &hostbuf; 00173 #if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6) 00174 char buf[2048]; 00175 int h_err = 0; 00176 if (gethostbyname_r(hostName.c_str(), &hostbuf, buf, sizeof(buf), 00177 &host, &h_err) == -1) 00178 { 00179 host = NULL; 00180 } 00181 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5) 00182 00183 char buf[2048]; 00184 int h_err(0); 00185 // returns NULL if not successful 00186 host = gethostbyname_r(hostName.c_str(), &hostbuf, buf, sizeof(buf), &h_err); 00187 00188 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3) 00189 hostent_data hostdata; 00190 if (gethostbyname_r(hostName.c_str(), &hostbuf, &hostdata) != 0) 00191 { 00192 host = NULL; 00193 } 00194 00195 #else 00196 #error Not yet supported: gethostbyname_r() with other argument counts. 00197 #endif /* BLOCXX_GETHOSTBYNAME_R_ARGUMENTS */ 00198 #else 00199 MutexLock mlock(gethostbynameMutex); 00200 #if defined(BLOCXX_NCR) 00201 hostent* host = gethostbyname(const_cast<char *>(hostName.c_str())); 00202 #else 00203 hostent* host = gethostbyname(hostName.c_str()); 00204 #endif 00205 #endif /* defined(BLOCXX_HAVE_GETHOSTBYNAME_R) && defined(BLOCXX_GETHOSTBYNAME_R_ARGUMENTS) */ 00206 00207 if (!host) 00208 { 00209 BLOCXX_THROW(UnknownHostException, String("Unknown host: ").concat(hostName).c_str()); 00210 } 00211 in_addr addr; 00212 memcpy(&addr, host->h_addr_list[0], sizeof(addr)); 00213 return getFromNativeForm(addr, port, host->h_name); 00214 } 00215 00217 //static 00218 SocketAddress 00219 SocketAddress::getFromNativeForm( const InetSocketAddress_t& nativeForm) 00220 { 00221 return SocketAddress(nativeForm); 00222 } 00223 00224 #if !defined(BLOCXX_WIN32) 00225 00226 //static 00227 SocketAddress 00228 SocketAddress::getFromNativeForm( const UnixSocketAddress_t& nativeForm) 00229 { 00230 return SocketAddress(nativeForm); 00231 } 00232 #endif // !defined(BLOCXX_WIN32) 00233 00235 //static 00236 SocketAddress 00237 SocketAddress::getFromNativeForm( const InetAddress_t& nativeForm, 00238 UInt16 nativePort, const String& hostName) 00239 { 00240 InetSocketAddress_t addr; 00241 memset(&addr, 0, sizeof(addr)); 00242 reinterpret_cast<sockaddr_in*>(&addr)->sin_family = AF_INET; 00243 reinterpret_cast<sockaddr_in*>(&addr)->sin_port = hton16(nativePort); 00244 reinterpret_cast<sockaddr_in*>(&addr)->sin_addr = nativeForm; 00245 SocketAddress p = SocketAddress(addr); 00246 p.m_type = INET; 00247 p.m_name = hostName; 00248 return p; 00249 } 00251 const SocketAddress_t* SocketAddress::getNativeForm() const 00252 { 00253 if (m_type == INET) 00254 { 00255 return reinterpret_cast<const sockaddr*>(&m_inetNativeAddress); 00256 } 00257 00258 #if !defined(BLOCXX_WIN32) 00259 else if (m_type == UDS) 00260 { 00261 return reinterpret_cast<const sockaddr*>(&m_UDSNativeAddress); 00262 } 00263 #endif 00264 00265 return 0; 00266 } 00267 00269 const InetSocketAddress_t* SocketAddress::getInetAddress() const 00270 { 00271 return &m_inetNativeAddress; 00272 } 00273 00274 #if !defined(BLOCXX_WIN32) 00275 00276 // Get a pointer to the UnixSocketAddress_t 00277 // precondition: getType() == UDS 00278 const UnixSocketAddress_t* SocketAddress::getUnixAddress() const 00279 { 00280 return &m_UDSNativeAddress; 00281 } 00282 #endif 00283 00285 SocketAddress 00286 SocketAddress::getAnyLocalHost(UInt16 port) 00287 { 00288 struct in_addr addr; 00289 addr.s_addr = hton32(INADDR_ANY); 00290 SocketAddress rval = getFromNativeForm(addr, port, "localhost"); 00291 char buf[256]; 00292 gethostname(buf, sizeof(buf)); 00293 String hname(buf); 00294 if (hname.indexOf('.') == String::npos) 00295 { 00296 #if defined(BLOCXX_HAVE_GETHOSTBYNAME_R) && defined(BLOCXX_GETHOSTBYNAME_R_ARGUMENTS) 00297 hostent hostbuf; 00298 hostent* hent = &hostbuf; 00299 #if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6) 00300 char local_buf[2048]; 00301 int h_err = 0; 00302 if (gethostbyname_r(buf, &hostbuf, local_buf, sizeof(local_buf), 00303 &hent, &h_err) == -1) 00304 { 00305 hent = NULL; 00306 } 00307 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5) 00308 00309 char local_buf[2048]; 00310 int h_err(0); 00311 // returns NULL if not successful 00312 hent = gethostbyname_r(buf, &hostbuf, local_buf, sizeof(local_buf), &h_err); 00313 00314 #elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3) 00315 hostent_data hostdata; 00316 if (gethostbyname_r(buf, &hostbuf, &hostdata) != 0) 00317 { 00318 hent = NULL; 00319 } 00320 00321 #else 00322 #error Not yet supported: gethostbyname_r() with other argument counts. 00323 #endif /* BLOCXX_GETHOSTBYNAME_R_ARGUMENTS */ 00324 #else 00325 MutexLock mlock(gethostbynameMutex); 00326 hostent* hent = gethostbyname(buf); 00327 #endif 00328 if (hent && hent->h_name && (strlen(hent->h_name) > 0)) 00329 { 00330 hname = String(hent->h_name); 00331 } 00332 } 00333 rval.m_name = hname; 00334 return rval; 00335 } 00336 00338 void SocketAddress::assignFromNativeForm( 00339 const InetSocketAddress_t* address, size_t /*size*/) 00340 { 00341 m_type = INET; 00342 memcpy(&m_inetNativeAddress, address, sizeof(m_inetNativeAddress)); 00343 #ifdef BLOCXX_HAVE_IPV6 00344 char buf[INET6_ADDRSTRLEN]; 00345 if ( reinterpret_cast<sockaddr*>(&m_inetNativeAddress)->sa_family==AF_INET6) 00346 { 00347 m_address = inet_ntop(AF_INET6, &(reinterpret_cast<sockaddr_in6*>(&m_inetNativeAddress)->sin6_addr), buf, sizeof(buf)); 00348 } 00349 else 00350 { 00351 m_address = inet_ntop(AF_INET, &(reinterpret_cast<sockaddr_in*>(&m_inetNativeAddress)->sin_addr), buf, sizeof(buf)); 00352 } 00353 #else 00354 m_address = inet_ntoa( reinterpret_cast<sockaddr_in*>(&m_inetNativeAddress)->sin_addr); 00355 #endif 00356 m_nativeSize = sizeof(m_inetNativeAddress); 00357 } 00358 00359 #if !defined(BLOCXX_WIN32) 00360 00361 void SocketAddress::assignFromNativeForm( 00362 const UnixSocketAddress_t* address, size_t /*size*/) 00363 { 00364 m_type = UDS; 00365 memcpy(&m_UDSNativeAddress, address, sizeof(m_UDSNativeAddress)); 00366 m_address = "localhost"; 00367 m_name = m_UDSNativeAddress.sun_path; 00368 m_nativeSize = sizeof(m_UDSNativeAddress); 00369 } 00370 #endif // !defined(BLOCXX_WIN32) 00371 00373 UInt16 SocketAddress::getPort() const 00374 { 00375 BLOCXX_ASSERT(m_type == INET); 00376 00377 #ifdef BLOCXX_HAVE_IPV6 00378 if ( reinterpret_cast<const sockaddr*>(&m_inetNativeAddress)->sa_family==AF_INET6) 00379 { 00380 return ntoh16(reinterpret_cast<const sockaddr_in6*>(&m_inetNativeAddress)->sin6_port); 00381 } 00382 else 00383 { 00384 return ntoh16(reinterpret_cast<const sockaddr_in*>(&m_inetNativeAddress)->sin_port); 00385 } 00386 #else 00387 return ntoh16(reinterpret_cast<const sockaddr_in*>(&m_inetNativeAddress)->sin_port); 00388 #endif 00389 } 00390 00391 #if !defined(BLOCXX_WIN32) 00392 00393 SocketAddress::SocketAddress(const UnixSocketAddress_t& nativeForm) 00394 : m_nativeSize(0), m_type(UDS) 00395 { 00396 assignFromNativeForm(&nativeForm, sizeof(nativeForm)); 00397 } 00398 #endif // !defined(BLOCXX_WIN32) 00399 00401 SocketAddress::SocketAddress(const InetSocketAddress_t& nativeForm) 00402 : m_nativeSize(0), m_type(INET) 00403 { 00404 assignFromNativeForm(&nativeForm, sizeof(nativeForm)); 00405 } 00406 00408 const String SocketAddress::getName() const 00409 { 00410 return m_name; 00411 } 00413 const String SocketAddress::getAddress() const 00414 { 00415 return m_address; 00416 } 00418 size_t SocketAddress::getNativeFormSize() const 00419 { 00420 return m_nativeSize; 00421 } 00423 SocketAddress SocketAddress::allocEmptyAddress(AddressType type) 00424 { 00425 if (type == INET) 00426 { 00427 InetSocketAddress_t addr; 00428 memset(&addr, 0, sizeof(addr)); 00429 reinterpret_cast<sockaddr_in*>(&addr)->sin_family = AF_INET; 00430 return SocketAddress(SocketAddress::getFromNativeForm(addr)); 00431 } 00432 #if !defined(BLOCXX_WIN32) 00433 else if (type == UDS) 00434 { 00435 sockaddr_un addr; 00436 memset(&addr, 0, sizeof(addr)); 00437 addr.sun_family = AF_UNIX; 00438 return SocketAddress(SocketAddress::getFromNativeForm(addr)); 00439 } 00440 #endif 00441 00442 BLOCXX_THROW(SocketAddressException, "Bad Address Type"); 00443 } 00445 const String 00446 SocketAddress::toString() const 00447 { 00448 BLOCXX_ASSERT(m_type != UNSET); 00449 String rval; 00450 if (m_type == INET) 00451 { 00452 rval = getAddress() + ":" + String(UInt32(getPort())); 00453 } 00454 else 00455 { 00456 rval = this->m_name; 00457 } 00458 return rval; 00459 } 00460 00461 } // end namespace BLOCXX_NAMESPACE 00462