blocxx

ServerSocketImpl.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/ServerSocketImpl.hpp"
00041 #include "blocxx/Format.hpp"
00042 #include "blocxx/ByteSwap.hpp"
00043 #include "blocxx/FileSystem.hpp"
00044 #include "blocxx/File.hpp"
00045 #include "blocxx/Thread.hpp"
00046 #include "blocxx/SocketUtils.hpp"
00047 #include "blocxx/System.hpp"
00048 #include "blocxx/TimeoutTimer.hpp"
00049 
00050 extern "C"
00051 {
00052 #if !defined(BLOCXX_WIN32)
00053 #include <sys/types.h>
00054 #include <sys/stat.h>
00055 #include <sys/socket.h>
00056 #include <sys/time.h>
00057 #include <netinet/in.h>
00058 #include <arpa/inet.h>
00059 #include <netdb.h>
00060 #include <unistd.h>
00061 #include <fcntl.h>
00062 
00063 #define INVALID_SOCKET -1
00064 #endif
00065 }
00066 
00067 #include <cerrno>
00068 
00069 namespace BLOCXX_NAMESPACE
00070 {
00072 ServerSocketImpl::ServerSocketImpl(SSLServerCtxRef sslCtx)
00073    : m_sockfd(INVALID_SOCKET)
00074    , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET))
00075    , m_isActive(false)
00076    , m_sslCtx(sslCtx)
00077 #if defined(BLOCXX_WIN32)
00078    , m_event(NULL)
00079    , m_shuttingDown(false)
00080 {
00081    m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00082    BLOCXX_ASSERT(m_event != NULL);
00083 }
00084 #else
00085    , m_udsFile()
00086 {
00087 }
00088 #endif
00089 
00091 ServerSocketImpl::ServerSocketImpl(SocketFlags::ESSLFlag isSSL)
00092    : m_sockfd(INVALID_SOCKET)
00093    , m_localAddress(SocketAddress::allocEmptyAddress(SocketAddress::INET))
00094    , m_isActive(false)
00095    , m_isSSL(isSSL)
00096 #if defined(BLOCXX_WIN32)
00097    , m_event(NULL)
00098    , m_shuttingDown(false)
00099 {
00100    m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00101    BLOCXX_ASSERT(m_event != NULL);
00102 }
00103 #else
00104    , m_udsFile()
00105 {
00106 }
00107 #endif
00108 
00110 ServerSocketImpl::~ServerSocketImpl()
00111 {
00112    try
00113    {
00114       close();
00115    }
00116    catch (...)
00117    {
00118       // don't let exceptions escape
00119    }
00120 #if defined(BLOCXX_WIN32)
00121    ::CloseHandle(m_event);
00122 #endif
00123 }
00124 
00126 Select_t
00127 ServerSocketImpl::getSelectObj() const
00128 {
00129 #if defined(BLOCXX_WIN32)
00130    Select_t st;
00131    st.event = m_event;
00132    st.sockfd = m_sockfd;
00133    st.isSocket = true;
00134    st.networkevents = FD_ACCEPT;
00135    return st;
00136 #else
00137    return m_sockfd;
00138 #endif
00139 }
00140 
00142 void
00143 ServerSocketImpl::doListen(UInt16 port, SocketFlags::ESSLFlag isSSL,
00144    int queueSize, const String& listenAddr,
00145    SocketFlags::EReuseAddrFlag reuseAddr)
00146 {
00147    m_isSSL = isSSL;
00148    doListen(port, queueSize,listenAddr, reuseAddr);
00149 }
00150 
00151 #if defined(BLOCXX_WIN32)
00152 
00153 void
00154 ServerSocketImpl::doListen(UInt16 port,
00155    int queueSize, const String& listenAddr,
00156    SocketFlags::EReuseAddrFlag reuseAddr)
00157 {
00158    SocketHandle_t sock_ipv6 = INVALID_SOCKET;
00159    m_localAddress = SocketAddress::allocEmptyAddress(SocketAddress::INET);
00160    close();
00161 
00162 #ifdef BLOCXX_HAVE_IPV6
00163    // This will try to use IPv6 (AF_INET6).  If it is not supported, it will
00164    // fall back to the normal IPv4 (AF_INET).
00165    sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0);
00166    if (sock_ipv6 == INVALID_SOCKET)
00167    {
00168       switch(errno)
00169       {
00170       case EPROTONOSUPPORT:
00171       case EAFNOSUPPORT:
00172       case EPFNOSUPPORT:
00173       case EINVAL:
00174          m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
00175          break;
00176       default:
00177          break;
00178       }
00179    }
00180    else
00181    {
00182        m_sockfd = sock_ipv6;
00183    }
00184 #else
00185    m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
00186 #endif
00187    if (m_sockfd  == INVALID_SOCKET)
00188    {
00189       BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00190          System::lastErrorMsg(true)).c_str());
00191    }
00192    // Set listen socket to nonblocking
00193    unsigned long cmdArg = 1;
00194    if (::ioctlsocket(m_sockfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
00195    {
00196       BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00197          System::lastErrorMsg(true)).c_str());
00198    }
00199 
00200    if (reuseAddr)
00201    {
00202       DWORD reuse = 1;
00203       ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR,
00204          (const char*)&reuse, sizeof(reuse));
00205    }
00206 
00207    if ( sock_ipv6 == INVALID_SOCKET )
00208    {
00209       // IPv4
00210       ServerSocketImpl::doListenIPv4( port, queueSize, listenAddr);
00211    }
00212 #ifdef BLOCXX_HAVE_IPV6
00213    else
00214    {
00215       // IPv6
00216       ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr, reuseAddr);
00217    }
00218 #endif
00219 }
00221 void
00222 ServerSocketImpl::doListenIPv4(UInt16 port, int queueSize, const String& listenAddr )
00223 {
00224    // use IPv4 protocol
00225    InetSocketAddress_t  inetAddr;
00226    memset(&inetAddr, 0, sizeof(inetAddr));
00227    reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_family  =  AF_INET;
00228    reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_port    =  hton16(port);
00229    if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
00230    {
00231       reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = hton32(INADDR_ANY);
00232    }
00233    else
00234    {
00235       SocketAddress addr = SocketAddress::getByName(listenAddr);
00236       reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = 
00237           reinterpret_cast<const sockaddr_in*>(addr.getInetAddress())->sin_addr.s_addr;
00238    }
00239    if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
00240    {
00241       close();
00242       BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00243          System::lastErrorMsg(true)).c_str());
00244    }
00245    if (::listen(m_sockfd, queueSize) == -1)
00246    {
00247       close();
00248       BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00249          System::lastErrorMsg(true)).c_str());
00250    }
00251    fillAddrParms();
00252    m_isActive = true;
00253 }
00255 #ifdef BLOCXX_HAVE_IPV6
00256 void
00257 ServerSocketImpl::doListenIPv6(UInt16 port, int queueSize, const String& listenAddr)
00258 {
00259    // use IPv6 protocol
00260    InetSocketAddress_t  inetAddr;
00261    memset(&inetAddr, 0, sizeof(inetAddr));
00262    reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_family =  AF_INET6;
00263    reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_port   =  hton16(port);
00264    if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
00265    {
00266       // copy IPv6 address any
00267       memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any, sizeof(struct in6_addr));
00268    }
00269    else
00270    {
00271       // create network address structure for IPv6 protocol
00272       if(!inet_pton(AF_INET6, listenAddr.c_str(), (void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr))
00273       {
00274          addrinfo *addrinfos;
00275          addrinfo hints;
00276          memset(&hints, 0, sizeof(hints));
00277          hints.ai_socktype = SOCK_STREAM;
00278          hints.ai_family   = AF_INET6;
00279          if(getaddrinfo(listenAddr.c_str(), NULL, &hints, &addrinfos))
00280          {
00281             close();
00282             BLOCXX_THROW(SocketException, Format("ServerSocketImpl:: doListen(): getaddrinfo() %1",
00283                System::lastErrorMsg(true)).c_str());
00284          }
00285          memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen);
00286          freeaddrinfo(addrinfos);
00287       }
00288    }
00289    if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
00290    {
00291       close();
00292       BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00293          System::lastErrorMsg(true)).c_str());
00294    }
00295    if (::listen(m_sockfd, queueSize) == -1)
00296    {
00297       close();
00298       BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00299          System::lastErrorMsg(true)).c_str());
00300    }
00301    fillAddrParms();
00302    m_isActive = true;
00303 }
00304 #endif // BLOCXX_HAVE_IPV6
00305 
00306 namespace
00307 {
00308 
00309 int
00310 waitForAcceptIO(SocketHandle_t fd, HANDLE eventArg, const Timeout& timeOutSecs,
00311    long networkEvents)
00312 {
00313    TimeoutTimer timer(timeOutSecs);
00314 
00315    if (networkEvents != -1L)
00316    {
00317       if(::WSAEventSelect(fd, eventArg, networkEvents) != 0)
00318       {
00319          BLOCXX_THROW(SocketException,
00320             Format("WSAEventSelect failed in waitForAcceptIO: %1",
00321             System::lastErrorMsg(true)).c_str());
00322       }
00323    }
00324 
00325    int cc;
00326    switch(::WaitForSingleObject(eventArg, timer.asDWORDMs()))
00327    {
00328       case WAIT_OBJECT_0:
00329          ::ResetEvent(eventArg);
00330          cc = 0;
00331          break;
00332       case WAIT_TIMEOUT:
00333          cc = ETIMEDOUT;
00334          break;
00335       default:
00336          cc = -1;
00337          break;
00338    }
00339 
00340    return cc;
00341 }
00342 
00343 }
00344 
00346 Socket
00347 ServerSocketImpl::accept(const Timeout& timeoutSecs)
00348 {
00349    BLOCXX_ASSERT(m_localAddress.getType() == SocketAddress::INET);
00350 
00351    if (!m_isActive)
00352    {
00353       BLOCXX_THROW(SocketException, "ServerSocketImpl::accept: NONE");
00354    }
00355 
00356    // Register interest in FD_ACCEPT events
00357    if(::WSAEventSelect(m_sockfd, m_event, FD_ACCEPT) != 0)
00358    {
00359       BLOCXX_THROW(SocketException,
00360          Format("WSAEventSelect failed in accept: %1",
00361          System::lastErrorMsg(true)).c_str());
00362    }
00363 
00364    SOCKET clntfd;
00365    socklen_t clntlen;
00366    InetSocketAddress_t clntInetAddr;
00367    HANDLE events[2];
00368    int cc;
00369 
00370    while (true)
00371    {
00372       clntlen = sizeof(clntInetAddr);
00373       clntfd = ::accept(m_sockfd,
00374          reinterpret_cast<struct sockaddr*>(&clntInetAddr), &clntlen);
00375       if (clntfd != INVALID_SOCKET)
00376       {
00377          // Got immediate connection
00378          break;
00379       }
00380 
00381       if (::WSAGetLastError() != WSAEWOULDBLOCK)
00382       {
00383          BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00384             System::lastErrorMsg(true)).c_str());
00385       }
00386 
00387       //cc = SocketUtils::waitForIO(m_sockfd, m_event, INFINITE, FD_ACCEPT);
00388       cc = waitForAcceptIO(m_sockfd, m_event, timeoutSecs, FD_ACCEPT);
00389       if(m_shuttingDown)
00390       {
00391          cc = -2;
00392       }
00393 
00394       switch (cc)
00395       {
00396          case -1:
00397             BLOCXX_THROW(SocketException, "Error while waiting for network events");
00398          case -2:
00399             BLOCXX_THROW(SocketException, "Shutdown event was signaled");
00400          case ETIMEDOUT:
00401             BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection");
00402       }
00403    }
00404 
00405    // Unregister for any events.  necessary to put us back in blocking mode.
00406    if(::WSAEventSelect(clntfd, NULL, 0) != 0)
00407    {
00408       BLOCXX_THROW(SocketException,
00409          Format("WSAEventSelect failed in accept: %1",
00410          System::lastErrorMsg(true)).c_str());
00411    }
00412 
00413    // set socket back to blocking; otherwise it'll inherit non-blocking from the listening socket
00414    unsigned long cmdArg = 0;
00415    if (::ioctlsocket(clntfd, FIONBIO, &cmdArg) == SOCKET_ERROR)
00416    {
00417       BLOCXX_THROW(SocketException, Format("ServerSocketImpl: %1",
00418          System::lastErrorMsg(true)).c_str());
00419    }
00420 
00421    if (!m_sslCtx && m_isSSL == SocketFlags::E_SSL)
00422    {
00423       return Socket(clntfd, m_localAddress.getType(), m_isSSL);
00424    }
00425 
00426    return Socket(clntfd, m_localAddress.getType(), m_sslCtx);
00427 }
00428 #else
00429 
00430 void
00431 ServerSocketImpl::doListen(UInt16 port,
00432    int queueSize, const String& listenAddr,
00433    SocketFlags::EReuseAddrFlag reuseAddr)
00434 {
00435    SocketHandle_t sock_ipv6 = INVALID_SOCKET;
00436    m_localAddress = SocketAddress::allocEmptyAddress(SocketAddress::INET);
00437    close();
00438 
00439 #ifdef BLOCXX_HAVE_IPV6
00440    // This will try to use IPv6 (AF_INET6).  If it is not supported, it will
00441    // fall back to the normal IPv4 (AF_INET).
00442    sock_ipv6 = ::socket(AF_INET6, SOCK_STREAM, 0);
00443    if (sock_ipv6 == INVALID_SOCKET)
00444    {
00445       switch(errno)
00446       {
00447       case EPROTONOSUPPORT:
00448       case EAFNOSUPPORT:
00449       case EPFNOSUPPORT:
00450       case EINVAL:
00451          // open socket for IPv4 protocol
00452          m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
00453          break;
00454       default:
00455          break;
00456       }
00457    }
00458    else
00459    {
00460       m_sockfd = sock_ipv6;
00461 #ifdef IPV6_V6ONLY
00462       int ipv6_proto = IPPROTO_IPV6;
00463 #ifdef SOL_IP
00464       ipv6_proto = SOL_IP;
00465 #endif
00466       int ipv6_only=0;
00467       ::setsockopt(m_sockfd, ipv6_proto, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only));
00468 #endif
00469    }
00470 #else
00471    m_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
00472 #endif
00473    if (m_sockfd  == INVALID_SOCKET)
00474    {
00475       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()");
00476    }
00477    // set the close on exec flag so child process can't keep the socket.
00478    if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
00479    {
00480       close();
00481       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set "
00482          "close-on-exec flag on listen socket");
00483    }
00484    // set listen socket to nonblocking; see Unix Network Programming,
00485    // pages 422-424.
00486    int fdflags = ::fcntl(m_sockfd, F_GETFL, 0);
00487    ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
00488    // is this safe? Should be, but some OS kernels have problems with it.
00489    // It's OK on current linux versions.  Definitely not on
00490    // OLD (kernel < 1.3.60) ones.  Who knows about on other OS's like UnixWare or
00491    // OpenServer?
00492    // See http://monkey.org/openbsd/archive/misc/9601/msg00031.html
00493    // or just google for "bind() Security Problems"
00494    // Let the kernel reuse the port without waiting for it to time out.
00495    // Without this line, you can't stop and immediately re-start the daemon.
00496    if (reuseAddr)
00497    {
00498       int reuse = 1;
00499 #if defined(BLOCXX_NCR)
00500       ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));
00501 #else
00502       ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
00503 #endif
00504    }
00505    if ( sock_ipv6 == INVALID_SOCKET)
00506    {
00507       // IPv4
00508       ServerSocketImpl::doListenIPv4( port, queueSize, listenAddr );
00509    }
00510 #ifdef BLOCXX_HAVE_IPV6
00511    else
00512    {  // IPv6
00513       ServerSocketImpl::doListenIPv6( port, queueSize, listenAddr );
00514    }
00515 #endif
00516 }
00517 
00519 void
00520 ServerSocketImpl::doListenIPv4(UInt16 port, int queueSize, const String& listenAddr )
00521 {
00522    // use IPv4 protocol
00523    InetSocketAddress_t  inetAddr;
00524    memset(&inetAddr, 0, sizeof(inetAddr));
00525    reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_family  =  AF_INET;
00526    reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_port    =  hton16(port);
00527    if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
00528    {
00529       reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = hton32(INADDR_ANY);
00530    }
00531    else
00532    {
00533       SocketAddress addr = SocketAddress::getByName(listenAddr);
00534       reinterpret_cast<sockaddr_in*>(&inetAddr)->sin_addr.s_addr = 
00535           reinterpret_cast<const sockaddr_in*>(addr.getInetAddress())->sin_addr.s_addr;
00536    }
00537    if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
00538    {
00539       close();
00540       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind");
00541    }
00542    if (::listen(m_sockfd, queueSize) == -1)
00543    {
00544       close();
00545       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen");
00546    }
00547    fillAddrParms();
00548    m_isActive = true;
00549 }
00550 
00551 #ifdef BLOCXX_HAVE_IPV6
00552 
00553 void
00554 ServerSocketImpl::doListenIPv6(UInt16 port, int queueSize, const String& listenAddr)
00555 {
00556    // use IPv6 protocol
00557    InetSocketAddress_t  inetAddr;
00558    memset(&inetAddr, 0, sizeof(inetAddr));
00559    reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_family =  AF_INET6;
00560    reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_port   =  hton16(port);
00561    if (listenAddr == SocketAddress::ALL_LOCAL_ADDRESSES)
00562    {
00563       // copy IPv6 address any
00564       memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr.s6_addr, &in6addr_any, sizeof(struct in6_addr));
00565    }
00566    else
00567    {
00568       // create network address structure for IPv6 protocol
00569       if(!inet_pton(AF_INET6, listenAddr.c_str(), (void*)&reinterpret_cast<sockaddr_in6*>(&inetAddr)->sin6_addr))
00570       {
00571          addrinfo *addrinfos;
00572          addrinfo hints;
00573          memset(&hints, 0, sizeof(hints));
00574          hints.ai_socktype = SOCK_STREAM;
00575          hints.ai_family   = AF_INET6;
00576          if(getaddrinfo(listenAddr.c_str(), NULL, &hints, &addrinfos))
00577          {
00578             close();
00579             BLOCXX_THROW_ERRNO_MSG(SocketException,"ServerSocketImpl::doListen(): getaddrinfo()");
00580          }
00581          memcpy(reinterpret_cast<sockaddr_in6*>(&inetAddr), addrinfos->ai_addr, addrinfos->ai_addrlen);
00582          freeaddrinfo(addrinfos);
00583       }
00584    }
00585    if (::bind(m_sockfd, reinterpret_cast<sockaddr*>(&inetAddr), sizeof(inetAddr)) == -1)
00586    {
00587       close();
00588       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind");
00589    }
00590    if (::listen(m_sockfd, queueSize) == -1)
00591    {
00592       close();
00593       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen");
00594    }
00595    fillAddrParms();
00596    m_isActive = true;
00597 }
00598 #endif
00599 
00600 void
00601 ServerSocketImpl::doListenUDS(const String& filename, int queueSize, bool reuseAddr)
00602 {
00603    m_localAddress = SocketAddress::getUDS(filename);
00604    close();
00605    m_sockfd = ::socket(PF_UNIX,SOCK_STREAM, 0);
00606    if (m_sockfd == INVALID_SOCKET)
00607    {
00608       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): socket()");
00609    }
00610    // set the close on exec flag so child process can't keep the socket.
00611    if (::fcntl(m_sockfd, F_SETFD, FD_CLOEXEC) == -1)
00612    {
00613       close();
00614       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): fcntl() failed to set "
00615          "close-on-exec flag on listen socket");
00616    }
00617 
00618    // set listen socket to nonblocking; see Unix Network Programming,
00619    // pages 422-424.
00620    int fdflags = ::fcntl(m_sockfd, F_GETFL, 0);
00621    ::fcntl(m_sockfd, F_SETFL, fdflags | O_NONBLOCK);
00622 
00623    if (reuseAddr)
00624    {
00625       // Let the kernel reuse the port without waiting for it to time out.
00626       // Without this line, you can't stop and immediately re-start the daemon.
00627       int reuse = 1;
00628 #if defined(BLOCXX_NCR)
00629       ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
00630 #else
00631       ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
00632 #endif
00633    }
00634    String lockfilename = filename + ".lock";
00635    m_udsFile = FileSystem::openOrCreateFile(lockfilename);
00636    if (!m_udsFile)
00637    {
00638       BLOCXX_THROW_ERRNO_MSG(SocketException,
00639          Format("ServerSocketImpl::doListen(): Unable to open or create Unix Domain Socket lock: %1",
00640             lockfilename).c_str());
00641    }
00642    // if we can't get a lock, someone else has got it open.
00643    if (m_udsFile.tryLock() == -1)
00644    {
00645       BLOCXX_THROW_ERRNO_MSG(SocketException,
00646          Format("ServerSocketImpl::doListen(): Unable to lock Unix Domain Socket: %1",
00647             filename).c_str());
00648    }
00649    // We got the lock, so clobber the UDS if it's there so bind will succeed.
00650    // If it's not gone, bind will fail.
00651    if (FileSystem::exists(filename))
00652    {
00653       if (!FileSystem::removeFile(filename.c_str()))
00654       {
00655          BLOCXX_THROW_ERRNO_MSG(SocketException,
00656             Format("ServerSocketImpl::doListen(): Unable to unlink Unix Domain Socket: %1",
00657                filename).c_str());
00658       }
00659    }
00660 
00661 #if defined(BLOCXX_NCR)
00662    if (::bind(m_sockfd, const_cast<SocketAddress_t *>(m_localAddress.getNativeForm()), m_localAddress.getNativeFormSize()) == -1)
00663 #else
00664    if (::bind(m_sockfd, m_localAddress.getNativeForm(), m_localAddress.getNativeFormSize()) == -1)
00665 #endif
00666    {
00667       close();
00668       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): bind()");
00669    }
00670    // give anybody access to the socket
00671    // unfortunately, fchmod() doesn't work on a UDS
00672    if (::chmod(filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) == -1)
00673    {
00674       close();
00675       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): chmod()");
00676    }
00677    if (::listen(m_sockfd, queueSize) == -1)
00678    {
00679       close();
00680       BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::doListen(): listen()");
00681    }
00682    fillAddrParms();
00683    m_isActive = true;
00684 }
00686 /*
00687 String
00688 ServerSocketImpl::addrString()
00689 {
00690    return inetAddrToString(m_localAddress, m_localPort);
00691 }
00692 */
00694 Socket
00695 ServerSocketImpl::accept(const Timeout& timeout)
00696 {
00697    if (!m_isActive)
00698    {
00699       BLOCXX_THROW(SocketException, "ServerSocketImpl::accept(): m_isActive == false");
00700    }
00701    int rc = 0;
00702    if ((rc = SocketUtils::waitForIO(m_sockfd, timeout, SocketFlags::E_WAIT_FOR_INPUT)) == 0)
00703    {
00704       int clntfd;
00705       socklen_t clntlen;
00706       InetSocketAddress_t clntInetAddr;
00707       struct sockaddr_un clntUnixAddr;
00708       struct sockaddr* pSA(0);
00709       if (m_localAddress.getType() == SocketAddress::INET)
00710       {
00711          pSA = reinterpret_cast<struct sockaddr*>(&clntInetAddr);
00712          clntlen = sizeof(clntInetAddr);
00713       }
00714       else if (m_localAddress.getType() == SocketAddress::UDS)
00715       {
00716          pSA = reinterpret_cast<struct sockaddr*>(&clntUnixAddr);
00717          clntlen = sizeof(clntUnixAddr);
00718       }
00719       else
00720       {
00721          BLOCXX_ASSERT(0);
00722       }
00723       
00724       clntfd = ::accept(m_sockfd, pSA, &clntlen);
00725       if (clntfd < 0)
00726       {
00727          // check to see if client aborts connection between select and accept.
00728          // see Unix Network Programming pages 422-424.
00729          if (errno == EWOULDBLOCK
00730              || errno == ECONNABORTED
00731 #ifdef EPROTO
00732              || errno == EPROTO
00733 #endif
00734             )
00735          {
00736             BLOCXX_THROW(SocketException, "Client aborted TCP connection "
00737                "between select() and accept()");
00738          }
00739       
00740          if (errno == EINTR)
00741          {
00742             Thread::testCancel();
00743          }
00744          BLOCXX_THROW_ERRNO_MSG(SocketException, "ServerSocketImpl::accept(): accept()");
00745       }
00746       // set socket back to blocking; see Unix Network Programming,
00747       // pages 422-424.
00748       int fdflags = ::fcntl(clntfd, F_GETFL, 0);
00749       // On most OSs non-blocking is inherited from the listen socket,
00750       // but it's not on Openserver.
00751       if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
00752       {
00753          ::fcntl(clntfd, F_SETFL, fdflags ^ O_NONBLOCK);
00754       }
00755       // TODO, how to make this bw compatible?
00756       //return Socket(clntfd, m_localAddress.getType(), m_isSSL);
00757       if (!m_sslCtx && m_isSSL == SocketFlags::E_SSL)
00758       {
00759          return Socket(clntfd, m_localAddress.getType(), m_isSSL); // for bw compat.
00760       }
00761       return Socket(clntfd, m_localAddress.getType(), m_sslCtx);
00762    }
00763    else if (rc == ETIMEDOUT)
00764    {
00765       // The timeout expired.
00766       BLOCXX_THROW(SocketTimeoutException,"Timed out waiting for a connection");
00767    }
00768    else
00769    {
00770       BLOCXX_THROW_ERRNO_MSG(SocketException,"Timed out waiting for a connection");
00771    }
00772 }
00773 #endif
00774 
00776 void
00777 ServerSocketImpl::close()
00778 {
00779    if (m_isActive)
00780    {
00781 #if defined(BLOCXX_WIN32)
00782       ::closesocket(m_sockfd);
00783       m_sockfd = INVALID_SOCKET;
00784 #else
00785 		::close(m_sockfd);
00786       if (m_localAddress.getType() == SocketAddress::UDS)
00787       {
00788          String filename = m_localAddress.toString();
00789          if (!FileSystem::removeFile(filename.c_str()))
00790          {
00791             BLOCXX_THROW_ERRNO_MSG(SocketException,
00792                Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket: %1",
00793                   filename).c_str());
00794          }
00795          if (m_udsFile)
00796          {
00797             String lockfilename = filename + ".lock";
00798             if (m_udsFile.unlock() == -1)
00799             {
00800                BLOCXX_THROW_ERRNO_MSG(SocketException,
00801                   Format("ServerSocketImpl::close(): Failed to unlock Unix Domain Socket: %1",
00802                      lockfilename).c_str());
00803             }
00804             m_udsFile.close();
00805             if (!FileSystem::removeFile(lockfilename.c_str()))
00806             {
00807                BLOCXX_THROW_ERRNO_MSG(SocketException,
00808                   Format("ServerSocketImpl::close(): Unable to unlink Unix Domain Socket lock: %1",
00809                      lockfilename).c_str());
00810             }
00811          }
00812       }
00813 #endif
00814       m_isActive = false;
00815    }
00816 }
00818 void
00819 ServerSocketImpl::fillAddrParms()
00820 {
00821    socklen_t len;
00822    if (m_localAddress.getType() == SocketAddress::INET)
00823    {
00824       // get information of local address for IPv6 protocol
00825       struct sockaddr *p_addr;
00826       InetSocketAddress_t ss;
00827       memset(&ss, 0, sizeof(ss));
00828       len = sizeof(ss);
00829       p_addr = reinterpret_cast<struct sockaddr*>(&ss);
00830       if (getsockname(m_sockfd, p_addr, &len) == -1)
00831       {
00832          BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname");
00833       }
00834       m_localAddress.assignFromNativeForm(&ss, len);
00835    }
00836 #if !defined(BLOCXX_WIN32)
00837    else if (m_localAddress.getType() == SocketAddress::UDS)
00838    {
00839       struct sockaddr_un addr;
00840       memset(&addr, 0, sizeof(addr));
00841       len = sizeof(addr);
00842       if (getsockname(m_sockfd, reinterpret_cast<struct sockaddr*>(&addr), &len) == -1)
00843       {
00844          BLOCXX_THROW_ERRNO_MSG(SocketException, "SocketImpl::fillAddrParms(): getsockname");
00845       }
00846       m_localAddress.assignFromNativeForm(&addr, len);
00847    }
00848 #endif
00849    else
00850    {
00851       BLOCXX_ASSERT(0);
00852    }
00853 }
00854 
00855 } // end namespace BLOCXX_NAMESPACE
00856