00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdnet.h"
00027
00028 #include "nel/net/listen_sock.h"
00029
00030 #ifdef NL_OS_WINDOWS
00031
00032 #include <winsock2.h>
00033 typedef sint socklen_t;
00034
00035 #elif defined NL_OS_UNIX
00036
00037 #include <unistd.h>
00038 #include <sys/types.h>
00039 #include <sys/socket.h>
00040 #include <netinet/in.h>
00041 #include <arpa/inet.h>
00042 #include <netdb.h>
00043 #include <errno.h>
00044 #include <fcntl.h>
00045 #define SOCKET_ERROR -1
00046 #define INVALID_SOCKET -1
00047 typedef int SOCKET;
00048
00049 #endif
00050
00051
00052 using namespace std;
00053
00054
00055 namespace NLNET
00056 {
00057
00058
00059
00060
00061
00062 CListenSock::CListenSock() : CTcpSock(), _Bound( false )
00063 {
00064
00065 createSocket( SOCK_STREAM, IPPROTO_TCP );
00066
00068 setBacklog( -1 );
00069 }
00070
00071
00072
00073
00074
00075 void CListenSock::init( uint16 port )
00076 {
00077
00078 CInetAddress localaddr;
00079 localaddr.setPort( port );
00080 init( localaddr );
00081
00082
00083 _LocalAddr = CInetAddress::localHost();
00084 _LocalAddr.setPort( port );
00085 nldebug( "LNETL0: Socket %d listen socket is at %s", _Sock, _LocalAddr.asString().c_str() );
00086 }
00087
00088
00089
00090
00091
00092 void CListenSock::init( const CInetAddress& addr )
00093 {
00094 if ( ! addr.isValid() )
00095 {
00096 nldebug( "LNETL0: Binding listen socket to any address, port %hu", addr.port() );
00097 }
00098
00099 #ifndef NL_OS_WINDOWS
00100
00101 int value = true;
00102 if ( setsockopt( _Sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ) == SOCKET_ERROR )
00103 {
00104 throw ESocket( "ReuseAddr failed" );
00105 }
00106 #endif
00107
00108
00109 if ( ::bind( _Sock, (const sockaddr *)addr.sockAddr(), sizeof(sockaddr_in) ) != 0 )
00110 {
00111 throw ESocket( "Unable to bind listen socket to port" );
00112 }
00113 _LocalAddr = addr;
00114 _Bound = true;
00115
00116
00117 if ( ::listen( _Sock, _BackLog ) != 0 )
00118 {
00119 throw ESocket( "Unable to listen on specified port" );
00120 }
00121
00122 }
00123
00124
00125
00126
00127
00128 CTcpSock *CListenSock::accept()
00129 {
00130
00131 sockaddr_in saddr;
00132 socklen_t saddrlen = sizeof(saddr);
00133 SOCKET newsock = ::accept( _Sock, (sockaddr*)&saddr, &saddrlen );
00134 if ( newsock == INVALID_SOCKET )
00135 {
00136
00137
00138
00139
00140 {
00141 throw ESocket( "Accept returned an invalid socket");
00142 }
00143 }
00144
00145
00146 CInetAddress addr;
00147 addr.setSockAddr( &saddr );
00148 nldebug( "LNETL0: Socket %d accepted an incoming connection from %s, opening socket %d", _Sock, addr.asString().c_str(), newsock );
00149 CTcpSock *connection = new CTcpSock( newsock, addr );
00150 return connection;
00151 }
00152
00153
00154
00155
00156
00157 void CListenSock::setBacklog( sint backlog )
00158 {
00159 if ( backlog == -1 )
00160 {
00161 _BackLog = SOMAXCONN;
00162 }
00163 else
00164 {
00165 _BackLog = backlog;
00166 }
00167 if ( _Bound )
00168 {
00169 if ( ::listen( _Sock, _BackLog ) != 0 )
00170 {
00171 throw ESocket( "Unable to listen on specified port, while changing backlog" );
00172 }
00173 }
00174 }
00175
00176
00177 }