socketConnection.cpp

00001 
00002 /* Copyright (c) 2005-2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include <limits>
00019 
00020 #include "socketConnection.h"
00021 
00022 #include "connectionDescription.h"
00023 #include "node.h"
00024 
00025 #include <eq/base/base.h>
00026 #include <eq/base/log.h>
00027 
00028 #include <errno.h>
00029 #include <sstream>
00030 #include <string.h>
00031 #include <sys/types.h>
00032 
00033 #ifdef WIN32
00034 #  ifndef WSA_FLAG_SDP
00035 #    define WSA_FLAG_SDP 0x40
00036 #  endif
00037 #  define EQ_SOCKET_ERROR getErrorString( GetLastError( )) << \
00038     "(" << GetLastError() << ")"
00039 #  include "socketConnectionWin32.cpp"
00040 
00041 #else
00042 #  define EQ_SOCKET_ERROR strerror( errno ) << "(" << errno << ")"
00043 #  include <arpa/inet.h>
00044 #  include <netdb.h>
00045 #  include <netinet/tcp.h>
00046 #  include <sys/socket.h>
00047 #  ifndef AF_INET_SDP
00048 #    define AF_INET_SDP 27
00049 #  endif
00050 
00051 #  include "socketConnectionPosix.cpp"
00052 #endif
00053 
00054 namespace eq
00055 {
00056 namespace net
00057 {
00058 bool SocketConnection::_createSocket()
00059 {
00060 #ifdef WIN32
00061     const DWORD flags = _description->type == CONNECTIONTYPE_SDP ?
00062                             WSA_FLAG_OVERLAPPED | WSA_FLAG_SDP :
00063                             WSA_FLAG_OVERLAPPED;
00064 
00065     const SOCKET fd = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0,0,flags );
00066 
00067     if( _description->type == CONNECTIONTYPE_SDP )
00068         EQINFO << "Created SDP socket" << std::endl;
00069 #else
00070     Socket fd;
00071     if( _description->type == CONNECTIONTYPE_SDP )
00072         fd = ::socket( AF_INET_SDP, SOCK_STREAM, IPPROTO_TCP );
00073     else
00074         fd = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
00075 #endif
00076 
00077     if( fd == INVALID_SOCKET )
00078     {
00079         EQERROR << "Could not create socket: " << EQ_SOCKET_ERROR << std::endl;
00080         return false;
00081     }
00082 
00083     _tuneSocket( fd );
00084 
00085     _readFD  = fd;
00086     _writeFD = fd; // TCP/IP sockets are bidirectional
00087     return true;
00088 }
00089 
00090 void SocketConnection::_tuneSocket( const Socket fd )
00091 {
00092     const int on         = 1;
00093     setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, 
00094                 reinterpret_cast<const char*>( &on ), sizeof( on ));
00095     setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, 
00096                 reinterpret_cast<const char*>( &on ), sizeof( on ));
00097     
00098 #ifdef WIN32
00099     const int size = 128768;
00100     setsockopt( fd, SOL_SOCKET, SO_RCVBUF, 
00101                 reinterpret_cast<const char*>( &size ), sizeof( size ));
00102     setsockopt( fd, SOL_SOCKET, SO_SNDBUF,
00103                 reinterpret_cast<const char*>( &size ), sizeof( size ));
00104 #endif
00105 }
00106 
00107 bool SocketConnection::_parseAddress( sockaddr_in& socketAddress )
00108 {
00109     socketAddress.sin_family      = AF_INET;
00110     socketAddress.sin_addr.s_addr = htonl( INADDR_ANY );
00111     socketAddress.sin_port        = htons( _description->TCPIP.port );
00112     memset( &(socketAddress.sin_zero), 0, 8 ); // zero the rest
00113 
00114     const std::string& hostname = _description->getHostname();
00115     if( !hostname.empty( ))
00116     {
00117         hostent *hptr = gethostbyname( hostname.c_str( ));
00118         if( hptr )
00119             memcpy(&socketAddress.sin_addr.s_addr, hptr->h_addr,hptr->h_length);
00120         else
00121         {
00122             EQWARN << "Can't resolve host " << hostname << std::endl;
00123             return false;
00124         }
00125     }
00126 
00127     EQINFO << "Address " << inet_ntoa( socketAddress.sin_addr )
00128            << ":" << ntohs( socketAddress.sin_port ) << std::endl;
00129     return true;
00130 }
00131 //----------------------------------------------------------------------
00132 // listen
00133 //----------------------------------------------------------------------
00134 bool SocketConnection::listen()
00135 {
00136     EQASSERT( _description->type == CONNECTIONTYPE_TCPIP || 
00137               _description->type == CONNECTIONTYPE_SDP );
00138 
00139     if( _state != STATE_CLOSED )
00140         return false;
00141 
00142     _state = STATE_CONNECTING;
00143     _fireStateChanged();
00144 
00145     if( !_createSocket())
00146         return false;
00147 
00148     sockaddr_in socketAddress;
00149     const size_t size = sizeof( sockaddr_in ); 
00150 
00151     if( !_parseAddress( socketAddress ))
00152     {
00153         EQWARN << "Can't parse connection parameters" << std::endl;
00154         close();
00155         return false;
00156     }
00157 
00158     const bool bound = (::bind(_readFD, (sockaddr *)&socketAddress, size) == 0);
00159 
00160     if( !bound )
00161     {
00162         EQWARN << "Could not bind socket " << _readFD << ": " 
00163                << EQ_SOCKET_ERROR << " to "
00164                << inet_ntoa( socketAddress.sin_addr )
00165                << ":" << ntohs( socketAddress.sin_port ) << " AF " 
00166                << (int)socketAddress.sin_family << std::endl;
00167 
00168         close();
00169         return false;
00170     }
00171     else if( socketAddress.sin_port == 0 )
00172         EQINFO << "Bound to port " << _getPort() << std::endl;
00173 
00174     const bool listening = (::listen( _readFD, 10 ) == 0);
00175         
00176     if( !listening )
00177     {
00178         EQWARN << "Could not listen on socket: " << EQ_SOCKET_ERROR << std::endl;
00179         close();
00180         return false;
00181     }
00182 
00183     // get socket parameters
00184     sockaddr_in address; // must use new sockaddr_in variable !?!
00185     socklen_t   used = sizeof(address);
00186     getsockname( _readFD, (struct sockaddr *)&address, &used ); 
00187 
00188     _description->TCPIP.port = ntohs( address.sin_port );
00189 
00190     const std::string& hostname = _description->getHostname();
00191     if( hostname.empty( ))
00192     {
00193         if( address.sin_addr.s_addr == INADDR_ANY )
00194         {
00195             char cHostname[256];
00196             gethostname( cHostname, 256 );
00197             _description->setHostname( cHostname );
00198         }
00199         else
00200             _description->setHostname( inet_ntoa( address.sin_addr ));
00201     }
00202     
00203     _initAIOAccept();
00204     _state = STATE_LISTENING;
00205     _fireStateChanged();
00206 
00207     EQINFO << "Listening on " << _description->getHostname() << "["
00208            << inet_ntoa( socketAddress.sin_addr ) << "]:" 
00209            << _description->TCPIP.port << " (" << _description->toString()
00210            << ")" << std::endl;
00211     
00212     return true;
00213 }
00214 
00215 uint16_t SocketConnection::_getPort() const
00216 {
00217     sockaddr_in address;
00218     socklen_t used = sizeof(address);
00219     getsockname( _readFD, (struct sockaddr *) &address, &used ); 
00220     return ntohs(address.sin_port);
00221 }
00222 
00223 }
00224 }
Generated on Mon Aug 10 18:58:41 2009 for Equalizer 0.9 by  doxygen 1.5.8