LCOV - code coverage report
Current view: top level - co - socketConnection.cpp (source / functions) Hit Total Coverage
Test: Collage Lines: 139 188 73.9 %
Date: 2018-01-09 16:37:03 Functions: 18 19 94.7 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                    2010, Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *
       5             :  * This file is part of Collage <https://github.com/Eyescale/Collage>
       6             :  *
       7             :  * This library is free software; you can redistribute it and/or modify it under
       8             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       9             :  * by the Free Software Foundation.
      10             :  *
      11             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      13             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      14             :  * details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      18             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             :  */
      20             : 
      21             : #include "socketConnection.h"
      22             : 
      23             : #include "connectionDescription.h"
      24             : #include "exception.h"
      25             : #include "global.h"
      26             : 
      27             : #include <co/exception.h>
      28             : #include <lunchbox/log.h>
      29             : #include <lunchbox/os.h>
      30             : #include <lunchbox/sleep.h>
      31             : 
      32             : #include <limits>
      33             : #include <sstream>
      34             : #include <string.h>
      35             : #include <sys/types.h>
      36             : 
      37             : #ifdef _WIN32
      38             : #include <mswsock.h>
      39             : #include <winsock2.h>
      40             : #include <ws2tcpip.h>
      41             : #define CO_RECV_TIMEOUT 250 /*ms*/
      42             : #else
      43             : #include <arpa/inet.h>
      44             : #include <netdb.h>
      45             : #include <netinet/tcp.h>
      46             : #include <sys/errno.h>
      47             : #include <sys/socket.h>
      48             : #endif
      49             : 
      50             : namespace co
      51             : {
      52         141 : SocketConnection::SocketConnection()
      53             : #ifdef _WIN32
      54             :     : _overlappedAcceptData(0)
      55             :     , _overlappedSocket(INVALID_SOCKET)
      56             :     , _overlappedDone(0)
      57             : #endif
      58             : {
      59             : #ifdef _WIN32
      60             :     memset(&_overlappedRead, 0, sizeof(_overlappedRead));
      61             :     memset(&_overlappedWrite, 0, sizeof(_overlappedWrite));
      62             : #endif
      63             : 
      64         282 :     ConnectionDescriptionPtr description = _getDescription();
      65         141 :     description->type = CONNECTIONTYPE_TCPIP;
      66         141 :     description->bandwidth = 102400; // 100MB/s
      67             : 
      68         141 :     LBVERB << "New SocketConnection @" << (void*)this << std::endl;
      69         141 : }
      70             : 
      71         423 : SocketConnection::~SocketConnection()
      72             : {
      73         141 :     _close();
      74         282 : }
      75             : 
      76             : namespace
      77             : {
      78          49 : std::string getHostName(const sockaddr_in& address)
      79             : {
      80             :     char hostname[NI_MAXHOST];
      81          49 :     if (getnameinfo((sockaddr*)&address.sin_addr, sizeof(sockaddr_in), hostname,
      82             :                     sizeof(hostname), 0, 0, 0) == 0)
      83             :     {
      84           0 :         return std::string(hostname);
      85             :     }
      86          49 :     if (address.sin_addr.s_addr == htonl(INADDR_ANY))
      87          29 :         return "*";
      88          20 :     return std::string();
      89             : }
      90             : 
      91          95 : bool _parseAddress(ConstConnectionDescriptionPtr description,
      92             :                    sockaddr_in& address)
      93             : {
      94          95 :     address.sin_family = AF_INET;
      95          95 :     address.sin_addr.s_addr = htonl(INADDR_ANY);
      96          95 :     address.sin_port = htons(description->port);
      97          95 :     memset(&(address.sin_zero), 0, 8); // zero the rest
      98             : 
      99          95 :     const std::string& hostname = description->getHostname();
     100          95 :     if (!hostname.empty())
     101             :     {
     102             :         addrinfo hints;
     103          66 :         memset(&hints, 0, sizeof(hints));
     104          66 :         hints.ai_flags = 0;
     105          66 :         hints.ai_family = AF_INET;
     106          66 :         hints.ai_socktype = SOCK_STREAM;
     107          66 :         addrinfo* info = 0;
     108             : 
     109          66 :         if (getaddrinfo(hostname.c_str(), NULL, &hints, &info) == 0)
     110             :         {
     111          66 :             address.sin_addr.s_addr =
     112          66 :                 ((sockaddr_in*)(info->ai_addr))->sin_addr.s_addr;
     113          66 :             freeaddrinfo(info);
     114             :         }
     115             :         else
     116             :         {
     117           0 :             LBWARN << "Can't resolve host " << hostname << std::endl;
     118           0 :             return false;
     119             :         }
     120             :     }
     121             : 
     122         190 :     LBVERB << "Address " << getHostName(address) << ":"
     123         285 :            << ntohs(address.sin_port) << std::endl;
     124          95 :     return true;
     125             : }
     126             : }
     127             : 
     128             : //----------------------------------------------------------------------
     129             : // connect
     130             : //----------------------------------------------------------------------
     131          46 : bool SocketConnection::connect()
     132             : {
     133          92 :     ConnectionDescriptionPtr description = _getDescription();
     134          46 :     LBASSERT(description->type == CONNECTIONTYPE_TCPIP);
     135          46 :     if (!isClosed())
     136           0 :         return false;
     137             : 
     138          46 :     if (description->port == 0)
     139           0 :         return false;
     140             : 
     141          46 :     if (description->getHostname().empty())
     142          25 :         description->setHostname("127.0.0.1");
     143             : 
     144             :     sockaddr_in address;
     145          46 :     if (!_parseAddress(description, address))
     146             :     {
     147           0 :         LBWARN << "Can't parse connection parameters" << std::endl;
     148           0 :         return false;
     149             :     }
     150             : 
     151          46 :     _setState(STATE_CONNECTING);
     152             : 
     153          46 :     if (!_createSocket())
     154           0 :         return false;
     155             : 
     156          46 :     if (address.sin_addr.s_addr == 0)
     157             :     {
     158           0 :         LBWARN << "Refuse to connect to 0.0.0.0" << std::endl;
     159           0 :         close();
     160           0 :         return false;
     161             :     }
     162             : 
     163             : #ifdef _WIN32
     164             :     const bool connected = WSAConnect(_readFD, (sockaddr*)&address,
     165             :                                       sizeof(address), 0, 0, 0, 0) == 0;
     166             : #else
     167          46 :     int nTries = 10;
     168          46 :     while (nTries--)
     169             :     {
     170             :         const bool connected =
     171          46 :             (::connect(_readFD, (sockaddr*)&address, sizeof(address)) == 0);
     172          46 :         if (connected)
     173          46 :             break;
     174             : 
     175           0 :         switch (errno)
     176             :         {
     177             :         case EINTR: // Happens sometimes, but looks harmless
     178           0 :             LBDEBUG << "connect: " << lunchbox::sysError << ", retrying"
     179           0 :                     << std::endl;
     180           0 :             lunchbox::sleep(5 /*ms*/);
     181           0 :             break;
     182             : 
     183             :         default:
     184           0 :             nTries = 0;
     185           0 :             break;
     186             :         }
     187             :     }
     188          46 :     const bool connected = nTries > 0;
     189             : #endif
     190             : 
     191          46 :     if (!connected)
     192             :     {
     193           0 :         LBDEBUG << "Could not connect to '" << description->getHostname() << ":"
     194           0 :                 << description->port << "': " << lunchbox::sysError
     195           0 :                 << std::endl;
     196           0 :         close();
     197           0 :         return false;
     198             :     }
     199             : 
     200          46 :     _initAIORead();
     201          46 :     _setState(STATE_CONNECTED);
     202          46 :     LBDEBUG << "Connected " << description->toString() << std::endl;
     203          46 :     return true;
     204             : }
     205             : 
     206         281 : void SocketConnection::_close()
     207             : {
     208         281 :     if (isClosed())
     209         140 :         return;
     210             : 
     211         141 :     if (isListening())
     212          49 :         _exitAIOAccept();
     213          92 :     else if (isConnected())
     214          92 :         _exitAIORead();
     215             : 
     216         141 :     LBASSERT(_readFD > 0);
     217             : 
     218             : #ifdef _WIN32
     219             :     const bool closed = (::closesocket(_readFD) == 0);
     220             : #else
     221         141 :     const bool closed = (::close(_readFD) == 0);
     222             : #endif
     223             : 
     224         141 :     if (!closed)
     225           0 :         LBWARN << "Could not close socket: " << lunchbox::sysError << std::endl;
     226             : 
     227         141 :     _readFD = INVALID_SOCKET;
     228         141 :     _writeFD = INVALID_SOCKET;
     229         141 :     _setState(STATE_CLOSED);
     230             : }
     231             : 
     232             : //----------------------------------------------------------------------
     233             : // Async IO handles
     234             : //----------------------------------------------------------------------
     235             : #ifdef _WIN32
     236             : void SocketConnection::_initAIORead()
     237             : {
     238             :     _overlappedRead.hEvent = CreateEvent(0, FALSE, FALSE, 0);
     239             :     LBASSERT(_overlappedRead.hEvent);
     240             : 
     241             :     _overlappedWrite.hEvent = CreateEvent(0, FALSE, FALSE, 0);
     242             :     LBASSERT(_overlappedWrite.hEvent);
     243             :     if (!_overlappedRead.hEvent)
     244             :         LBERROR << "Can't create event for AIO notification: "
     245             :                 << lunchbox::sysError << std::endl;
     246             : }
     247             : 
     248             : void SocketConnection::_initAIOAccept()
     249             : {
     250             :     _initAIORead();
     251             :     _overlappedAcceptData = malloc(2 * (sizeof(sockaddr_in) + 16));
     252             : }
     253             : 
     254             : void SocketConnection::_exitAIOAccept()
     255             : {
     256             :     if (_overlappedAcceptData)
     257             :     {
     258             :         free(_overlappedAcceptData);
     259             :         _overlappedAcceptData = 0;
     260             :     }
     261             : 
     262             :     _exitAIORead();
     263             : }
     264             : void SocketConnection::_exitAIORead()
     265             : {
     266             :     if (_overlappedRead.hEvent)
     267             :     {
     268             :         CloseHandle(_overlappedRead.hEvent);
     269             :         _overlappedRead.hEvent = 0;
     270             :     }
     271             : 
     272             :     if (_overlappedWrite.hEvent)
     273             :     {
     274             :         CloseHandle(_overlappedWrite.hEvent);
     275             :         _overlappedWrite.hEvent = 0;
     276             :     }
     277             : }
     278             : #else
     279          49 : void SocketConnection::_initAIOAccept()
     280             : { /* NOP */
     281          49 : }
     282          49 : void SocketConnection::_exitAIOAccept()
     283             : { /* NOP */
     284          49 : }
     285          46 : void SocketConnection::_initAIORead()
     286             : { /* NOP */
     287          46 : }
     288          92 : void SocketConnection::_exitAIORead()
     289             : { /* NOP */
     290          92 : }
     291             : #endif
     292             : 
     293             : //----------------------------------------------------------------------
     294             : // accept
     295             : //----------------------------------------------------------------------
     296             : #ifdef _WIN32
     297             : void SocketConnection::acceptNB()
     298             : {
     299             :     LBASSERT(isListening());
     300             : 
     301             :     // Create new accept socket
     302             :     const DWORD flags = WSA_FLAG_OVERLAPPED;
     303             : 
     304             :     LBASSERT(_overlappedAcceptData);
     305             :     LBASSERT(_overlappedSocket == INVALID_SOCKET);
     306             :     _overlappedSocket =
     307             :         WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, flags);
     308             : 
     309             :     if (_overlappedSocket == INVALID_SOCKET)
     310             :     {
     311             :         LBERROR << "Could not create accept socket: " << lunchbox::sysError
     312             :                 << ", closing listening socket" << std::endl;
     313             :         close();
     314             :         return;
     315             :     }
     316             : 
     317             :     const int on = 1;
     318             :     setsockopt(_overlappedSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
     319             :                reinterpret_cast<const char*>(&on), sizeof(on));
     320             : 
     321             :     // Start accept
     322             :     ResetEvent(_overlappedRead.hEvent);
     323             :     DWORD got;
     324             :     if (!AcceptEx(_readFD, _overlappedSocket, _overlappedAcceptData, 0,
     325             :                   sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &got,
     326             :                   &_overlappedRead) &&
     327             :         GetLastError() != WSA_IO_PENDING)
     328             :     {
     329             :         LBERROR << "Could not start accept operation: " << lunchbox::sysError
     330             :                 << ", closing connection" << std::endl;
     331             :         close();
     332             :     }
     333             : }
     334             : 
     335             : ConnectionPtr SocketConnection::acceptSync()
     336             : {
     337             :     LB_TS_THREAD(_recvThread);
     338             :     if (!isListening())
     339             :         return 0;
     340             : 
     341             :     LBASSERT(_overlappedAcceptData);
     342             :     LBASSERT(_overlappedSocket != INVALID_SOCKET);
     343             :     if (_overlappedSocket == INVALID_SOCKET)
     344             :         return 0;
     345             : 
     346             :     // complete accept
     347             :     DWORD got = 0;
     348             :     DWORD flags = 0;
     349             : 
     350             :     if (!WSAGetOverlappedResult(_readFD, &_overlappedRead, &got, TRUE, &flags))
     351             :     {
     352             :         LBWARN << "Accept completion failed: " << lunchbox::sysError
     353             :                << ", closing socket" << std::endl;
     354             :         close();
     355             :         return 0;
     356             :     }
     357             : 
     358             :     sockaddr_in* local = 0;
     359             :     sockaddr_in* remote = 0;
     360             :     int localLen = 0;
     361             :     int remoteLen = 0;
     362             :     GetAcceptExSockaddrs(_overlappedAcceptData, 0, sizeof(sockaddr_in) + 16,
     363             :                          sizeof(sockaddr_in) + 16, (sockaddr**)&local,
     364             :                          &localLen, (sockaddr**)&remote, &remoteLen);
     365             :     _tuneSocket(_overlappedSocket);
     366             : 
     367             :     ConstConnectionDescriptionPtr description = getDescription();
     368             :     SocketConnection* newConnection = new SocketConnection;
     369             :     ConnectionPtr connection(newConnection); // to keep ref-counting correct
     370             : 
     371             :     newConnection->_readFD = _overlappedSocket;
     372             :     newConnection->_writeFD = _overlappedSocket;
     373             : 
     374             : #ifndef _WIN32
     375             : // fcntl( _overlappedSocket, F_SETFL, O_NONBLOCK );
     376             : #endif
     377             : 
     378             :     newConnection->_initAIORead();
     379             :     _overlappedSocket = INVALID_SOCKET;
     380             : 
     381             :     newConnection->_setState(STATE_CONNECTED);
     382             :     ConnectionDescriptionPtr newDescription = newConnection->_getDescription();
     383             :     newDescription->bandwidth = description->bandwidth;
     384             :     newDescription->port = ntohs(remote->sin_port);
     385             :     newDescription->setHostname(getHostName(*remote));
     386             : 
     387             :     LBDEBUG << "accepted connection from " << newDescription->getHostname()
     388             :             << ":" << newDescription->port << std::endl;
     389             :     return connection;
     390             : }
     391             : 
     392             : #else // !_WIN32
     393             : 
     394          91 : void SocketConnection::acceptNB()
     395             : { /* NOP */
     396          91 : }
     397             : 
     398          46 : ConnectionPtr SocketConnection::acceptSync()
     399             : {
     400          46 :     if (!isListening())
     401           0 :         return 0;
     402             : 
     403             :     sockaddr_in newAddress;
     404          46 :     socklen_t newAddressLen = sizeof(newAddress);
     405             : 
     406             :     Socket fd;
     407          46 :     unsigned nTries = 1000;
     408          46 :     do
     409          46 :         fd = ::accept(_readFD, (sockaddr*)&newAddress, &newAddressLen);
     410          46 :     while (fd == INVALID_SOCKET && errno == EINTR && --nTries);
     411             : 
     412          46 :     if (fd == INVALID_SOCKET)
     413             :     {
     414           0 :         LBWARN << "accept failed: " << lunchbox::sysError << std::endl;
     415           0 :         return 0;
     416             :     }
     417             : 
     418          46 :     _tuneSocket(fd);
     419             : 
     420          92 :     ConstConnectionDescriptionPtr description = getDescription();
     421          46 :     SocketConnection* newConnection = new SocketConnection;
     422             : 
     423          46 :     newConnection->_readFD = fd;
     424          46 :     newConnection->_writeFD = fd;
     425          46 :     newConnection->_setState(STATE_CONNECTED);
     426          92 :     ConnectionDescriptionPtr newDescription = newConnection->_getDescription();
     427          46 :     newDescription->bandwidth = description->bandwidth;
     428          46 :     newDescription->port = ntohs(newAddress.sin_port);
     429          46 :     newDescription->setHostname(inet_ntoa(newAddress.sin_addr));
     430             : 
     431          46 :     LBDEBUG << "Accepted " << newDescription->toString() << std::endl;
     432          46 :     return newConnection;
     433             : }
     434             : 
     435             : #endif // !_WIN32
     436             : 
     437             : #ifdef _WIN32
     438             : //----------------------------------------------------------------------
     439             : // read
     440             : //----------------------------------------------------------------------
     441             : void SocketConnection::readNB(void* buffer, const uint64_t bytes)
     442             : {
     443             :     if (isClosed())
     444             :         return;
     445             : 
     446             :     WSABUF wsaBuffer = {LB_MIN(bytes, 65535), reinterpret_cast<char*>(buffer)};
     447             :     DWORD flags = 0;
     448             : 
     449             :     ResetEvent(_overlappedRead.hEvent);
     450             :     _overlappedDone = 0;
     451             :     const int result = WSARecv(_readFD, &wsaBuffer, 1, &_overlappedDone, &flags,
     452             :                                &_overlappedRead, 0);
     453             :     if (result == 0) // got data already
     454             :     {
     455             :         if (_overlappedDone == 0) // socket closed
     456             :         {
     457             :             LBDEBUG << "Got EOF, closing connection" << std::endl;
     458             :             close();
     459             :         }
     460             :         SetEvent(_overlappedRead.hEvent);
     461             :     }
     462             :     else if (GetLastError() != WSA_IO_PENDING)
     463             :     {
     464             :         LBWARN << "Could not start overlapped receive: " << lunchbox::sysError
     465             :                << ", closing connection" << std::endl;
     466             :         close();
     467             :     }
     468             : }
     469             : 
     470             : int64_t SocketConnection::readSync(void* buffer, const uint64_t bytes,
     471             :                                    const bool block)
     472             : {
     473             :     LB_TS_THREAD(_recvThread);
     474             : 
     475             :     if (_readFD == INVALID_SOCKET)
     476             :     {
     477             :         LBERROR << "Invalid read handle" << std::endl;
     478             :         return READ_ERROR;
     479             :     }
     480             : 
     481             :     if (_overlappedDone > 0)
     482             :         return _overlappedDone;
     483             : 
     484             :     DWORD got = 0;
     485             :     DWORD flags = 0;
     486             :     DWORD startTime = 0;
     487             : 
     488             :     while (true)
     489             :     {
     490             :         if (WSAGetOverlappedResult(_readFD, &_overlappedRead, &got, block,
     491             :                                    &flags))
     492             :             return got;
     493             : 
     494             :         const int err = WSAGetLastError();
     495             :         if (err == ERROR_SUCCESS || got > 0)
     496             :         {
     497             :             LBWARN << "Got " << lunchbox::sysError << " with " << got
     498             :                    << " bytes on " << getDescription() << std::endl;
     499             :             return got;
     500             :         }
     501             : 
     502             :         if (startTime == 0)
     503             :             startTime = GetTickCount();
     504             : 
     505             :         switch (err)
     506             :         {
     507             :         case WSA_IO_INCOMPLETE:
     508             :             return READ_TIMEOUT;
     509             : 
     510             :         case WSASYSCALLFAILURE: // happens sometimes!?
     511             :         case WSA_IO_PENDING:
     512             :             if (GetTickCount() - startTime > CO_RECV_TIMEOUT) // timeout
     513             :             {
     514             :                 LBWARN << "Error timeout " << std::endl;
     515             :                 return READ_ERROR;
     516             :             }
     517             : 
     518             :             LBWARN << "WSAGetOverlappedResult error loop" << std::endl;
     519             :             // one millisecond to recover
     520             :             lunchbox::sleep(1);
     521             :             break;
     522             : 
     523             :         default:
     524             :             LBWARN << "Got " << lunchbox::sysError << ", closing connection"
     525             :                    << std::endl;
     526             :             close();
     527             :             return READ_ERROR;
     528             :         }
     529             :     }
     530             : }
     531             : 
     532             : int64_t SocketConnection::write(const void* buffer, const uint64_t bytes)
     533             : {
     534             :     if (!isConnected() || _writeFD == INVALID_SOCKET)
     535             :         return -1;
     536             : 
     537             :     DWORD wrote;
     538             :     WSABUF wsaBuffer = {LB_MIN(bytes, 65535),
     539             :                         const_cast<char*>(static_cast<const char*>(buffer))};
     540             : 
     541             :     ResetEvent(_overlappedWrite.hEvent);
     542             :     if (WSASend(_writeFD, &wsaBuffer, 1, &wrote, 0, &_overlappedWrite, 0) == 0)
     543             :         // ok
     544             :         return wrote;
     545             : 
     546             :     if (WSAGetLastError() != WSA_IO_PENDING)
     547             :         return -1;
     548             : 
     549             :     const DWORD err = WaitForSingleObject(_overlappedWrite.hEvent, INFINITE);
     550             :     switch (err)
     551             :     {
     552             :     case WAIT_FAILED:
     553             :     case WAIT_ABANDONED:
     554             :     {
     555             :         LBWARN << "Write error" << lunchbox::sysError << std::endl;
     556             :         return -1;
     557             :     }
     558             : 
     559             :     default:
     560             :         LBWARN << "Unhandled write error " << err << ": " << lunchbox::sysError
     561             :                << std::endl;
     562             :     // no break;
     563             :     case WAIT_OBJECT_0:
     564             :         break;
     565             :     }
     566             : 
     567             :     DWORD got = 0;
     568             :     DWORD flags = 0;
     569             :     if (WSAGetOverlappedResult(_writeFD, &_overlappedWrite, &got, false,
     570             :                                &flags))
     571             :     {
     572             :         return got;
     573             :     }
     574             : 
     575             :     switch (WSAGetLastError())
     576             :     {
     577             :     case WSA_IO_INCOMPLETE:
     578             :         throw Exception(Exception::TIMEOUT_WRITE);
     579             : 
     580             :     default:
     581             :     {
     582             :         LBWARN << "Write error : " << lunchbox::sysError << std::endl;
     583             :         return -1;
     584             :     }
     585             :     }
     586             : 
     587             :     LBUNREACHABLE;
     588             :     return -1;
     589             : }
     590             : #endif // _WIN32
     591             : 
     592          95 : bool SocketConnection::_createSocket()
     593             : {
     594         190 :     ConstConnectionDescriptionPtr description = getDescription();
     595             : #ifdef _WIN32
     596             :     const DWORD flags = WSA_FLAG_OVERLAPPED;
     597             :     const SOCKET fd =
     598             :         WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, flags);
     599             : #else
     600          95 :     const Socket fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     601             : #endif
     602             : 
     603          95 :     if (fd == INVALID_SOCKET)
     604             :     {
     605           0 :         LBERROR << "Could not create socket: " << lunchbox::sysError
     606           0 :                 << std::endl;
     607           0 :         return false;
     608             :     }
     609             : 
     610          95 :     _tuneSocket(fd);
     611             : 
     612          95 :     _readFD = fd;
     613          95 :     _writeFD = fd; // TCP/IP sockets are bidirectional
     614             : 
     615          95 :     return true;
     616             : }
     617             : 
     618         141 : void SocketConnection::_tuneSocket(const Socket fd)
     619             : {
     620         141 :     const int on = 1;
     621             :     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char*>(&on),
     622         141 :                sizeof(on));
     623             :     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&on),
     624         141 :                sizeof(on));
     625             : 
     626             : #ifdef _WIN32
     627             :     const int size = 128768;
     628             :     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char*>(&size),
     629             :                sizeof(size));
     630             :     setsockopt(fd, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&size),
     631             :                sizeof(size));
     632             : #endif
     633         141 : }
     634             : 
     635             : //----------------------------------------------------------------------
     636             : // listen
     637             : //----------------------------------------------------------------------
     638          49 : bool SocketConnection::listen()
     639             : {
     640          98 :     ConnectionDescriptionPtr description = _getDescription();
     641          49 :     LBASSERT(description->type == CONNECTIONTYPE_TCPIP);
     642             : 
     643          49 :     if (!isClosed())
     644           0 :         return false;
     645             : 
     646          49 :     _setState(STATE_CONNECTING);
     647             : 
     648             :     sockaddr_in address;
     649          49 :     const size_t size = sizeof(sockaddr_in);
     650             : 
     651          49 :     if (!_parseAddress(description, address))
     652             :     {
     653           0 :         LBWARN << "Can't parse connection parameters" << std::endl;
     654           0 :         return false;
     655             :     }
     656             : 
     657          49 :     if (!_createSocket())
     658           0 :         return false;
     659             : 
     660          49 :     const bool bound = (::bind(_readFD, (sockaddr*)&address, size) == 0);
     661             : 
     662          49 :     if (!bound)
     663             :     {
     664           0 :         LBWARN << "Could not bind socket " << _readFD << ": "
     665           0 :                << lunchbox::sysError << " to " << getHostName(address) << ":"
     666           0 :                << ntohs(address.sin_port) << " AF " << (int)address.sin_family
     667           0 :                << std::endl;
     668             : 
     669           0 :         close();
     670           0 :         return false;
     671             :     }
     672             : 
     673          49 :     if (::listen(_readFD, SOMAXCONN) != 0)
     674             :     {
     675           0 :         LBWARN << "Could not listen on socket: " << lunchbox::sysError
     676           0 :                << std::endl;
     677           0 :         close();
     678           0 :         return false;
     679             :     }
     680             : 
     681             :     // get socket parameters
     682          49 :     socklen_t used = size;
     683          49 :     getsockname(_readFD, (struct sockaddr*)&address, &used);
     684          49 :     description->port = ntohs(address.sin_port);
     685             : 
     686          97 :     std::string hostname = description->getHostname();
     687          49 :     if (hostname.empty())
     688             :     {
     689          29 :         if (address.sin_addr.s_addr == INADDR_ANY)
     690             :         {
     691          29 :             char cHostname[256] = {0};
     692          29 :             gethostname(cHostname, 256);
     693          29 :             hostname = cHostname;
     694             : 
     695          28 :             description->setHostname(hostname);
     696             :         }
     697             :         else
     698           0 :             description->setHostname(getHostName(address));
     699             :     }
     700             : 
     701          49 :     _initAIOAccept();
     702          49 :     _setState(STATE_LISTENING);
     703             : 
     704         196 :     LBDEBUG << "Listening on " << description->getHostname() << "["
     705         147 :             << getHostName(address) << "]:" << description->port << " ("
     706         245 :             << description->toString() << ")" << std::endl;
     707             : 
     708          49 :     return true;
     709             : }
     710             : 
     711           0 : uint16_t SocketConnection::_getPort() const
     712             : {
     713             :     sockaddr_in address;
     714           0 :     socklen_t used = sizeof(address);
     715           0 :     getsockname(_readFD, (struct sockaddr*)&address, &used);
     716           0 :     return ntohs(address.sin_port);
     717             : }
     718          63 : }

Generated by: LCOV version 1.11