OW_SocketUtils.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
00029 *******************************************************************************/
00030 
00036 #include "OW_config.h"
00037 #include "OW_SocketException.hpp"
00038 #include "OW_SocketUtils.hpp"
00039 #include "OW_PosixUnnamedPipe.hpp"
00040 #include "OW_Assertion.hpp"
00041 #include "OW_Socket.hpp"
00042 #include "OW_Format.hpp"
00043 #include "OW_Thread.hpp"
00044 #include "OW_System.hpp"
00045 #include "OW_Select.hpp"
00046 
00047 #ifndef OW_HAVE_GETHOSTBYNAME_R
00048 #include "OW_Mutex.hpp"
00049 #include "OW_MutexLock.hpp"
00050 #endif
00051 
00052 extern "C"
00053 {
00054 #if !defined(OW_WIN32)
00055 #include <ctype.h>
00056 #include <sys/types.h>
00057 #include <sys/wait.h>
00058 #include <sys/time.h>
00059 #include <sys/socket.h>
00060 #ifdef OW_HAVE_SYS_RESOURCE_H
00061 #include <sys/resource.h>
00062 #endif
00063 #include <netdb.h>
00064 #include <arpa/inet.h>
00065 #include <unistd.h>
00066 #endif
00067 }
00068 
00069 #include <cstring>
00070 #include <cstdio>
00071 #include <cerrno>
00072 
00073 namespace OW_NAMESPACE
00074 {
00075 
00076 namespace SocketUtils 
00077 {
00078 
00080 String
00081 inetAddrToString(UInt64 addr)
00082 {
00083    struct in_addr iaddr;
00084    iaddr.s_addr = addr;
00085    String s(inet_ntoa(iaddr));
00086    return s;
00087 }
00088 #ifndef MAX
00089    #define MAX(A,B) (((A) > (B))? (A): (B))
00090 #endif
00091 
00092 #if defined(OW_WIN32)
00093 int
00094 waitForIO(SocketHandle_t fd, HANDLE eventArg, int timeOutSecs,
00095    long networkEvents)
00096 {
00097    DWORD timeout = (timeOutSecs != -1)
00098       ? static_cast<DWORD>(timeOutSecs * 1000)
00099       : INFINITE;
00100 
00101    if (networkEvents != -1L)
00102    {
00103       if(::WSAEventSelect(fd, eventArg, networkEvents) != 0)
00104       {
00105          OW_THROW(SocketException, 
00106             Format("WSAEventSelect failed in waitForIO: %1",
00107             System::lastErrorMsg(true)).c_str());
00108       }
00109    }
00110 
00111    int cc;
00112    if(Socket::getShutDownMechanism() != NULL)
00113    {
00114       HANDLE events[2];
00115       events[0] = Socket::getShutDownMechanism();
00116       events[1] = eventArg;
00117 
00118       DWORD index = ::WaitForMultipleObjects(
00119          2,
00120          events,
00121          FALSE,
00122          timeout);
00123 
00124       switch (index)
00125       {
00126          case WAIT_FAILED:
00127             cc = -1;
00128             break;
00129          case WAIT_TIMEOUT:
00130             cc = ETIMEDOUT;
00131             break;
00132          default:
00133             index -= WAIT_OBJECT_0;
00134             // If not shutdown event, then reset
00135             if (index != 0)
00136             {
00137                ::ResetEvent(eventArg);
00138                cc = 0;
00139             }
00140             else
00141             {
00142                // Shutdown handle was signaled
00143                cc = -2;
00144             }
00145             break;
00146       }
00147    }
00148    else
00149    {
00150       switch(::WaitForSingleObject(eventArg, timeout))
00151       {
00152          case WAIT_OBJECT_0:
00153             ::ResetEvent(eventArg);
00154             cc = 0;
00155             break;
00156          case WAIT_TIMEOUT:
00157             cc = ETIMEDOUT;
00158             break;
00159          default:
00160             cc = -1;
00161             break;
00162       }
00163    }
00164 
00165    // Set socket back to blocking
00166    if(::WSAEventSelect(fd, eventArg, 0) != 0)
00167    {
00168       OW_THROW(SocketException, 
00169          Format("Resetting socket with WSAEventSelect failed: %1",
00170          System::lastErrorMsg(true)).c_str());
00171    }
00172    u_long ioctlarg = 0;
00173    ::ioctlsocket(fd, FIONBIO, &ioctlarg);
00174    return cc;
00175 }
00176 
00177 #else
00178 
00179 int
00180 waitForIO(SocketHandle_t fd, int timeOutSecs, SocketFlags::EWaitDirectionFlag waitFlag)
00181 {
00182    if (fd == -1)
00183    {
00184       errno = EBADF;
00185       return -1;
00186    }
00187 
00188    Select::SelectObject so(fd); 
00189    if (waitFlag == SocketFlags::E_WAIT_FOR_INPUT)
00190    {
00191       so.waitForRead = true; 
00192    }
00193    else if (waitFlag == SocketFlags::E_WAIT_FOR_OUTPUT)
00194    {
00195       so.waitForWrite = true; 
00196    }
00197    else
00198    {
00199       so.waitForRead = true; 
00200       so.waitForWrite = true; 
00201    }
00202    Select::SelectObjectArray selarray; 
00203    selarray.push_back(so); 
00204 
00205    PosixUnnamedPipeRef lUPipe;
00206    int pipefd = -1;
00207    if (Socket::getShutDownMechanism())
00208    {
00209       UnnamedPipeRef foo = Socket::getShutDownMechanism();
00210       lUPipe = foo.cast_to<PosixUnnamedPipe>();
00211       OW_ASSERT(lUPipe);
00212       pipefd = lUPipe->getInputHandle();
00213    }
00214    if (pipefd != -1)
00215    {
00216       so = Select::SelectObject(pipefd); 
00217       so.waitForRead = true; 
00218       selarray.push_back(so); 
00219    }
00220 
00221    int rc = Select::selectRW(selarray, timeOutSecs*1000); 
00222    switch (rc)
00223    {
00224    case Select::SELECT_TIMEOUT:
00225       rc = ETIMEDOUT; 
00226       break; 
00227    case 2:
00228       rc = -1; // pipe was signalled
00229       break; 
00230    case 1: 
00231       if (pipefd != -1)
00232       {
00233          if (selarray[1].readAvailable)
00234          {
00235             rc = -1; 
00236          }
00237       }
00238       if (selarray[0].writeAvailable || selarray[0].readAvailable)
00239       {
00240          rc = 0; 
00241       }
00242       break; 
00243    default: 
00244       rc = -1; 
00245    }
00246    return rc; 
00247 
00248 }
00249 #endif   // 
00250 
00251 #ifndef OW_HAVE_GETHOSTBYNAME_R
00252 } // end namespace SocketUtils
00253 extern Mutex gethostbynameMutex;  // defined in SocketAddress.cpp
00254 namespace SocketUtils {
00255 #endif
00256 
00257 #ifndef OW_WIN32
00258 String getFullyQualifiedHostName()
00259 {
00260    char hostName [2048];
00261    if (gethostname (hostName, sizeof(hostName)) == 0)
00262    {
00263 #ifndef OW_HAVE_GETHOSTBYNAME_R
00264       MutexLock lock(gethostbynameMutex);
00265       struct hostent *he;
00266       if ((he = gethostbyname (hostName)) != 0)
00267       {
00268          return he->h_name;
00269       }
00270       else
00271       {
00272          OW_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostbyname failed: %1", h_errno).c_str());
00273       }
00274 #else
00275       hostent hostbuf;
00276       hostent* host = &hostbuf;
00277 #if (OW_GETHOSTBYNAME_R_ARGUMENTS == 6 || OW_GETHOSTBYNAME_R_ARGUMENTS == 5)
00278       char buf[2048];
00279       int h_err = 0;
00280 #elif (OW_GETHOSTBYNAME_R_ARGUMENTS == 3)
00281       hostent_data hostdata;
00282       int h_err = 0;    
00283 #else
00284 #error Not yet supported: gethostbyname_r() with other argument counts.
00285 #endif /* OW_GETHOSTBYNAME_R_ARGUMENTS */
00286       // gethostbyname_r will randomly fail on some platforms/networks
00287       // maybe the DNS server is overloaded or something.  So we'll
00288       // give it a few tries to see if it can get it right.
00289       bool worked = false;
00290       for (int i = 0; i < 10 && (!worked || host == 0); ++i)
00291       {
00292 #if (OW_GETHOSTBYNAME_R_ARGUMENTS == 6)        
00293          if (gethostbyname_r(hostName, &hostbuf, buf, sizeof(buf),
00294                   &host, &h_err) != -1)
00295          {
00296             worked = true;
00297             break;
00298          }
00299 #elif (OW_GETHOSTBYNAME_R_ARGUMENTS == 5)
00300          // returns NULL if not successful
00301          if ((host = gethostbyname_r(hostName, &hostbuf, buf, sizeof(buf), &h_err))) {
00302             worked = true;
00303             break;
00304          }
00305 #elif (OW_GETHOSTBYNAME_R_ARGUMENTS == 3)
00306          if (gethostbyname_r(hostName, &hostbuf, &hostdata) == 0)
00307          {
00308             worked = true;
00309             break;
00310          }
00311          else
00312          {
00313            h_err = h_errno;
00314          }
00315 #else
00316 #error Not yet supported: gethostbyname_r() with other argument counts.
00317 #endif /* OW_GETHOSTBYNAME_R_ARGUMENTS */
00318       }
00319       if (worked && host != 0)
00320       {
00321          return host->h_name;
00322       }
00323       else
00324       {
00325          OW_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostbyname_r(%1) failed: %2", hostName, h_err).c_str());
00326       }
00327 #endif
00328    }
00329    else
00330    {
00331       OW_THROW(SocketException, Format("SocketUtils::getFullyQualifiedHostName: gethostname failed: %1(%2)", errno, strerror(errno)).c_str());
00332    }
00333    return "";
00334 }
00335 #else
00336 // WIN32 defined
00337 String getFullyQualifiedHostName()
00338 {
00339    String rv;
00340    struct hostent *hostentp;
00341    char bfr[1024], ipaddrstr[128];
00342    struct in_addr iaHost;
00343 
00344    if(gethostname(bfr, sizeof(bfr)-1) == SOCKET_ERROR)
00345    {
00346       OW_THROW(SocketException, 
00347          Format("SocketUtils::getFullyQualifiedHostName: gethostname failed: %1(%2)", 
00348             WSAGetLastError(), System::lastErrorMsg(true)).c_str());
00349    }
00350 
00351    if(strchr(bfr, '.'))
00352    {
00353       // Guess we already have the DNS name
00354       return String(bfr);
00355    }
00356 
00357    if((hostentp = gethostbyname(bfr)) == NULL)
00358    {
00359       OW_THROW(SocketException, 
00360          Format("SocketUtils::getFullyQualifiedHostName: gethostbyname"
00361             " failed: %1(%2)", WSAGetLastError(),
00362             System::lastErrorMsg(true)).c_str());
00363    }
00364 
00365    if(strchr(hostentp->h_name, '.'))
00366    {
00367       rv = hostentp->h_name;
00368    }
00369    else
00370    {
00371       rv = inet_ntoa(*(struct in_addr*) (hostentp->h_addr_list[0]));
00372       iaHost.s_addr = inet_addr(rv.c_str());
00373       if(iaHost.s_addr != INADDR_NONE)
00374       {
00375          hostentp = gethostbyaddr((const char*)&iaHost,
00376             sizeof(struct in_addr), AF_INET);
00377          if(hostentp)
00378          {
00379             if(strchr(hostentp->h_name, '.'))
00380             {
00381                // GOT IT
00382                rv = hostentp->h_name;
00383             }
00384          }
00385       }
00386    }
00387 
00388    return rv;
00389 }
00390 #endif
00391 
00392 
00393 } // end namespace SocketUtils
00394 
00395 } // end namespace OW_NAMESPACE
00396 

Generated on Thu Feb 9 08:48:11 2006 for openwbem by  doxygen 1.4.6