blocxx

SocketAddress.cpp

Go to the documentation of this file.
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