OW_Win32SocketBaseImpl.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 
00037 #include "OW_config.h"
00038 
00039 #if defined(OW_WIN32)
00040 
00041 #include "OW_SocketBaseImpl.hpp"
00042 #include "OW_SocketUtils.hpp"
00043 #include "OW_Format.hpp"
00044 #include "OW_Assertion.hpp"
00045 #include "OW_IOException.hpp"
00046 #include "OW_Mutex.hpp"
00047 #include "OW_MutexLock.hpp"
00048 #include "OW_PosixUnnamedPipe.hpp"
00049 #include "OW_Socket.hpp"
00050 #include "OW_Thread.hpp"
00051 #include "OW_System.hpp"
00052 
00053 #include <cstdio>
00054 #include <cerrno>
00055 #include <fstream>
00056 #include <ws2tcpip.h>
00057 
00058 namespace
00059 {
00060 
00061 class SockInitializer
00062 {
00063 public:
00064    SockInitializer()
00065    {
00066       WSADATA wsaData;
00067       ::WSAStartup(MAKEWORD(2,2), &wsaData);
00068    }
00069 
00070    ~SockInitializer()
00071    {
00072       ::WSACleanup();
00073    }
00074 };
00075 
00076 // Force Winsock initialization on load
00077 SockInitializer _sockInitializer;
00078 
00080 void
00081 _closeSocket(SOCKET& sockfd)
00082 {
00083    if (sockfd != INVALID_SOCKET)
00084    {
00085       ::closesocket(sockfd);
00086       sockfd = INVALID_SOCKET;
00087    }
00088 }
00089 
00091 int
00092 getAddrFromIface(OW_NAMESPACE::InetSocketAddress_t& addr)
00093 {
00094    SOCKET sd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00095     if (sd == SOCKET_ERROR)
00096    {
00097       return -1;
00098     }
00099 
00100    int cc = -1;
00101     INTERFACE_INFO interfaceList[20];
00102     unsigned long nBytesReturned;
00103    if (::WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &interfaceList,
00104          sizeof(interfaceList), &nBytesReturned, 0, 0) != SOCKET_ERROR)
00105    {
00106       int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
00107       for (int i = 0; i < nNumInterfaces; ++i)
00108       {
00109          u_long nFlags = interfaceList[i].iiFlags;
00110          if (nFlags & IFF_UP)
00111          {
00112             cc = 0;
00113             ::memcpy(&addr, &(interfaceList[i].iiAddress), sizeof(addr));
00114             if (!(nFlags & IFF_LOOPBACK))
00115             {
00116                break;
00117             }
00118          }
00119       }
00120    }
00121 
00122    ::closesocket(sd);
00123     return 0;
00124 }
00125 
00126 }  // end of unnamed namespace
00127 
00128 namespace OW_NAMESPACE
00129 {
00130 
00131 using std::istream;
00132 using std::ostream;
00133 using std::iostream;
00134 using std::ifstream;
00135 using std::ofstream;
00136 using std::fstream;
00137 using std::ios;
00138 String SocketBaseImpl::m_traceFileOut;
00139 String SocketBaseImpl::m_traceFileIn;
00140 
00142 // static
00143 int
00144 SocketBaseImpl::waitForEvent(HANDLE eventArg, int secsToTimeout)
00145 {
00146    DWORD timeout = (secsToTimeout != -1)
00147       ? static_cast<DWORD>(secsToTimeout * 1000)
00148       : INFINITE;
00149    
00150    int cc;
00151    if(Socket::getShutDownMechanism() != NULL)
00152    {
00153       HANDLE events[2];
00154       events[0] = Socket::getShutDownMechanism();
00155       events[1] = eventArg;
00156 
00157       DWORD index = ::WaitForMultipleObjects(
00158          2,
00159          events,
00160          FALSE,
00161          timeout);
00162 
00163       switch (index)
00164       {
00165          case WAIT_FAILED:
00166             cc = -2;
00167             break;
00168          case WAIT_TIMEOUT:
00169             cc = -1;
00170             break;
00171          default:
00172             index -= WAIT_OBJECT_0;
00173             // If not shutdown event, then reset
00174             if (index != 0)
00175             {
00176                ::ResetEvent(eventArg);
00177             }
00178             cc = static_cast<int>(index);
00179             break;
00180       }
00181    }
00182    else
00183    {
00184       switch(::WaitForSingleObject(eventArg, timeout))
00185       {
00186          case WAIT_OBJECT_0:
00187             ::ResetEvent(eventArg);
00188             cc = 1;
00189             break;
00190          case WAIT_TIMEOUT:
00191             cc = -1;
00192             break;
00193          default:
00194             cc = -2;
00195             break;
00196       }
00197    }
00198       
00199    return cc;
00200 }
00201 
00202 #pragma warning (push)
00203 #pragma warning (disable: 4355)
00204 
00206 SocketBaseImpl::SocketBaseImpl()
00207    : SelectableIFC()
00208    , IOIFC()
00209    , m_isConnected(false)
00210    , m_sockfd(INVALID_SOCKET)
00211    , m_localAddress()
00212    , m_peerAddress()
00213    , m_event(NULL)
00214    , m_recvTimeoutExprd(false)
00215    , m_streamBuf(this)
00216    , m_in(&m_streamBuf)
00217    , m_out(&m_streamBuf)
00218    , m_inout(&m_streamBuf)
00219    , m_recvTimeout(-1)
00220    , m_sendTimeout(-1)
00221    , m_connectTimeout(0)
00222 {
00223    m_out.exceptions(std::ios::badbit);
00224    m_inout.exceptions(std::ios::badbit);
00225    m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00226    OW_ASSERT(m_event != NULL);
00227 }
00229 SocketBaseImpl::SocketBaseImpl(SocketHandle_t fd,
00230       SocketAddress::AddressType addrType)
00231    : SelectableIFC()
00232    , IOIFC()
00233    , m_isConnected(true)
00234    , m_sockfd(fd)
00235    , m_localAddress(SocketAddress::getAnyLocalHost())
00236    , m_peerAddress(SocketAddress::allocEmptyAddress(addrType))
00237    , m_event(NULL)
00238    , m_recvTimeoutExprd(false)
00239    , m_streamBuf(this)
00240    , m_in(&m_streamBuf)
00241    , m_out(&m_streamBuf)
00242    , m_inout(&m_streamBuf)
00243    , m_recvTimeout(-1)
00244    , m_sendTimeout(-1)
00245    , m_connectTimeout(0)
00246 {
00247    OW_ASSERT(addrType == SocketAddress::INET);
00248 
00249    m_out.exceptions(std::ios::badbit);
00250    m_inout.exceptions(std::ios::badbit);
00251    m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00252    OW_ASSERT(m_event != NULL);
00253    fillInetAddrParms();
00254 }
00256 SocketBaseImpl::SocketBaseImpl(const SocketAddress& addr)
00257    : SelectableIFC()
00258    , IOIFC()
00259    , m_isConnected(false)
00260    , m_sockfd(INVALID_SOCKET)
00261    , m_localAddress(SocketAddress::getAnyLocalHost())
00262    , m_peerAddress(addr)
00263    , m_event(NULL)
00264    , m_recvTimeoutExprd(false)
00265    , m_streamBuf(this)
00266    , m_in(&m_streamBuf)
00267    , m_out(&m_streamBuf)
00268    , m_inout(&m_streamBuf)
00269    , m_recvTimeout(-1)
00270    , m_sendTimeout(-1)
00271    , m_connectTimeout(0)
00272 {
00273    m_out.exceptions(std::ios::badbit);
00274    m_inout.exceptions(std::ios::badbit);
00275    m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00276    OW_ASSERT(m_event != NULL);
00277    connect(m_peerAddress);
00278 }
00279 
00280 #pragma warning (pop)
00281 
00283 SocketBaseImpl::~SocketBaseImpl()
00284 {
00285    try
00286    {
00287       disconnect();
00288    }
00289    catch (...)
00290    {
00291       // don't let exceptions escape
00292    }
00293    ::CloseHandle(m_event);
00294 }
00296 Select_t
00297 SocketBaseImpl::getSelectObj() const
00298 {
00299    Select_t st;
00300    st.event = m_event;
00301    st.sockfd = m_sockfd;
00302    st.networkevents = FD_READ | FD_WRITE;
00303    st.doreset = true;
00304    return st;
00305 }
00307 void
00308 SocketBaseImpl::connect(const SocketAddress& addr)
00309 {
00310    if (m_isConnected)
00311    {
00312       disconnect();
00313    }
00314    m_streamBuf.reset();
00315    m_in.clear();
00316    m_out.clear();
00317    m_inout.clear();
00318    OW_ASSERT(addr.getType() == SocketAddress::INET);
00319 
00320    m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00321    if (m_sockfd == INVALID_SOCKET)
00322    {
00323       OW_THROW(SocketException, 
00324          Format("Failed to create a socket: %1",
00325          System::lastErrorMsg(true)).c_str());
00326    }
00327 
00328    int cc;
00329    WSANETWORKEVENTS networkEvents;
00330 
00331    // Connect non-blocking
00332    if(::WSAEventSelect(m_sockfd, m_event, FD_CONNECT) != 0)
00333    {
00334       OW_THROW(SocketException, 
00335          Format("WSAEventSelect Failed: %1",
00336          System::lastErrorMsg(true)).c_str());
00337    }
00338 
00339    if (::connect(m_sockfd, addr.getNativeForm(), addr.getNativeFormSize())
00340       == SOCKET_ERROR)
00341    {
00342       int lastError = ::WSAGetLastError();
00343         if (lastError != WSAEWOULDBLOCK && lastError != WSAEINPROGRESS)
00344       {
00345          _closeSocket(m_sockfd);
00346          OW_THROW(SocketException,
00347             Format("Failed to connect to: %1: %2(%3)", addr.toString(),
00348                lastError, System::lastErrorMsg(true)).c_str());
00349       }
00350 
00351       int tmoutval = (m_connectTimeout > 0) ? m_connectTimeout : INFINITE;
00352 
00353       // Wait for connection event to come through
00354       while (true)
00355       {
00356          // Wait for the socket's event to get signaled
00357          if ((cc = waitForEvent(m_event, tmoutval)) < 1)
00358          {
00359             _closeSocket(m_sockfd);
00360             switch (cc)
00361             {
00362                case 0:     // Shutdown event
00363                   OW_THROW(SocketException,
00364                      "Sockets have been shutdown");
00365                case -1: // Timed out
00366                   OW_THROW(SocketException,
00367                      Format("Win32SocketBaseImpl connection"
00368                         " timed out. Timeout val = %1",
00369                         m_connectTimeout).c_str());
00370                default: // Error on wait
00371                   OW_THROW(SocketException, Format("SocketBaseImpl::"
00372                      "connect() wait failed: %1(%2)",
00373                      ::WSAGetLastError(),
00374                      System::lastErrorMsg(true)).c_str());
00375             }
00376          }
00377 
00378          // Find out what network event took place
00379          if (::WSAEnumNetworkEvents(m_sockfd, m_event, &networkEvents)
00380             == SOCKET_ERROR)
00381          {
00382             _closeSocket(m_sockfd);
00383             OW_THROW(SocketException,
00384                Format("SocketBaseImpl::connect()"
00385                   " failed getting network events: %1(%2)",
00386                   ::WSAGetLastError(),
00387                   System::lastErrorMsg(true)).c_str());
00388          }
00389 
00390          // Was it a connect event?
00391          if (networkEvents.lNetworkEvents & FD_CONNECT)
00392          {
00393             // Did connect fail?
00394             if (networkEvents.iErrorCode[FD_CONNECT_BIT])
00395             {
00396                ::WSASetLastError(networkEvents.iErrorCode[FD_CONNECT_BIT]);
00397                _closeSocket(m_sockfd);
00398                     OW_THROW(SocketException,
00399                   Format("SocketBaseImpl::connect() failed: %1(%2)",
00400                   ::WSAGetLastError(),
00401                   System::lastErrorMsg(true)).c_str());
00402             }
00403             break;
00404          }
00405       }  // while (true) - waiting for connection event
00406    }  // if SOCKET_ERROR on connect
00407 
00408    // Set socket back to blocking
00409    if(::WSAEventSelect(m_sockfd, m_event, 0) != 0)
00410    {
00411       _closeSocket(m_sockfd);
00412       OW_THROW(SocketException, 
00413          Format("Resetting socket with WSAEventSelect Failed: %1",
00414          System::lastErrorMsg(true)).c_str());
00415    }
00416    u_long ioctlarg = 0;
00417    ::ioctlsocket(m_sockfd, FIONBIO, &ioctlarg);
00418 
00419    m_isConnected = true;
00420 
00421    m_peerAddress = addr; // To get the hostname from addr
00422 
00423    OW_ASSERT(addr.getType() == SocketAddress::INET);
00424 
00425    fillInetAddrParms();
00426 }
00427 
00429 void
00430 SocketBaseImpl::disconnect()
00431 {
00432    if(m_in)
00433    {
00434       m_in.clear(ios::eofbit);
00435    }
00436    if(m_out)
00437    {
00438         m_out.clear(ios::eofbit);
00439    }
00440    if(!m_inout.fail())
00441    {
00442       m_inout.clear(ios::eofbit);
00443    }
00444 
00445    ::SetEvent(m_event);
00446    _closeSocket(m_sockfd);
00447    m_isConnected = false;
00448 }
00449 
00451 void
00452 SocketBaseImpl::fillInetAddrParms()
00453 {
00454    socklen_t len;
00455    InetSocketAddress_t addr;
00456    ::memset(&addr, 0, sizeof(addr));
00457    len = sizeof(addr);
00458    bool gotAddr = false;
00459 
00460    if (m_sockfd != INVALID_SOCKET)
00461    {
00462       len = sizeof(addr);
00463       if (::getsockname(m_sockfd,
00464          reinterpret_cast<struct sockaddr*>(&addr), &len) != SOCKET_ERROR)
00465       {
00466          m_localAddress.assignFromNativeForm(&addr, len);
00467       }
00468       else if (getAddrFromIface(addr) == 0)
00469       {
00470          len = sizeof(addr);
00471          m_localAddress.assignFromNativeForm(&addr, len);
00472       }
00473 
00474       len = sizeof(addr);
00475       if (::getpeername(m_sockfd, reinterpret_cast<struct sockaddr*>(&addr),
00476          &len) != SOCKET_ERROR)
00477       {
00478          m_peerAddress.assignFromNativeForm(&addr, len);
00479       }
00480    }
00481    else if (getAddrFromIface(addr) == 0)
00482    {
00483       m_localAddress.assignFromNativeForm(&addr, len);
00484    }
00485 }
00486 
00487 static Mutex guard;
00489 int
00490 SocketBaseImpl::write(const void* dataOut, int dataOutLen, bool errorAsException)
00491 {
00492    int rc = 0;
00493    bool isError = false;
00494    if (m_isConnected)
00495    {
00496       isError = waitForOutput(m_sendTimeout);
00497       if (isError)
00498       {
00499          rc = -1;
00500       }
00501       else
00502       {
00503          rc = writeAux(dataOut, dataOutLen);
00504          if (!m_traceFileOut.empty() && rc > 0)
00505          {
00506             MutexLock ml(guard);
00507             ofstream traceFile(m_traceFileOut.c_str(), std::ios::app);
00508             if (!traceFile)
00509             {
00510                OW_THROW(IOException, "Failed opening socket dump file");
00511             }
00512             if (!traceFile.write(static_cast<const char*>(dataOut), rc))
00513             {
00514                OW_THROW(IOException, "Failed writing to socket dump");
00515             }
00516 
00517             ofstream comboTraceFile(String(m_traceFileOut + "Combo").c_str(), std::ios::app);
00518             if (!comboTraceFile)
00519             {
00520                OW_THROW(IOException, "Failed opening socket dump file");
00521             }
00522             comboTraceFile << "\n--->Out " << rc << " bytes<---\n";
00523             if (!comboTraceFile.write(static_cast<const char*>(dataOut), rc))
00524             {
00525                OW_THROW(IOException, "Failed writing to socket dump");
00526             }
00527          }
00528       }
00529    }
00530    else
00531    {
00532       rc = -1;
00533    }
00534    if (rc < 0 && errorAsException)
00535    {
00536       OW_THROW(SocketException, "SocketBaseImpl::write");
00537    }
00538    return rc;
00539 }
00541 int
00542 SocketBaseImpl::read(void* dataIn, int dataInLen, bool errorAsException)   
00543 {
00544    int rc = 0;
00545    bool isError = false;
00546    if (m_isConnected)
00547    {
00548       isError = waitForInput(m_recvTimeout);
00549       if (isError)
00550       {
00551          rc = -1;
00552       }
00553       else
00554       {
00555          rc = readAux(dataIn, dataInLen);
00556          if (!m_traceFileIn.empty() && rc > 0)
00557          {
00558             MutexLock ml(guard);
00559             ofstream traceFile(m_traceFileIn.c_str(), std::ios::app);
00560             if (!traceFile)
00561             {
00562                OW_THROW(IOException, "Failed opening tracefile");
00563             }
00564             if (!traceFile.write(reinterpret_cast<const char*>(dataIn), rc))
00565             {
00566                OW_THROW(IOException, "Failed writing to socket dump");
00567             }
00568 
00569             ofstream comboTraceFile(String(m_traceFileOut + "Combo").c_str(), std::ios::app);
00570             if (!comboTraceFile)
00571             {
00572                OW_THROW(IOException, "Failed opening socket dump file");
00573             }
00574             comboTraceFile << "\n--->In " << rc << " bytes<---\n";
00575             if (!comboTraceFile.write(reinterpret_cast<const char*>(dataIn), rc))
00576             {
00577                OW_THROW(IOException, "Failed writing to socket dump");
00578             }
00579          }
00580       }
00581    }
00582    else
00583    {
00584       rc = -1;
00585    }
00586    if (rc < 0)
00587    {
00588       if (errorAsException)
00589          OW_THROW(SocketException, "SocketBaseImpl::read");
00590    }
00591    return rc;
00592 }
00594 bool
00595 SocketBaseImpl::waitForInput(int timeOutSecs)
00596 {
00597    int rval = SocketUtils::waitForIO(m_sockfd, m_event, timeOutSecs, FD_READ);
00598    if (rval == ETIMEDOUT)
00599    {
00600       m_recvTimeoutExprd = true;
00601    }
00602    else
00603    {
00604       m_recvTimeoutExprd = false;
00605    }
00606    return (rval != 0);
00607 }
00609 bool
00610 SocketBaseImpl::waitForOutput(int timeOutSecs)
00611 {
00612    return SocketUtils::waitForIO(m_sockfd, m_event, timeOutSecs,
00613       FD_WRITE) != 0;
00614 }
00616 istream&
00617 SocketBaseImpl::getInputStream()
00618 {
00619    return m_in;
00620 }
00622 ostream&
00623 SocketBaseImpl::getOutputStream()
00624 {
00625    return m_out;
00626 }
00628 iostream&
00629 SocketBaseImpl::getIOStream()
00630 {
00631    return m_inout;
00632 }
00634 // STATIC
00635 void
00636 SocketBaseImpl::setDumpFiles(const String& in, const String& out)
00637 {
00638    m_traceFileOut = out;
00639    m_traceFileIn = in;
00640 }
00641 
00642 } // end namespace OW_NAMESPACE
00643 
00644 #endif   // #if defined(OW_WIN32)

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