1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/net/tcp_sock.h"
23 #include "nel/net/net_log.h"
26 # include <winsock2.h>
27 # ifndef NL_COMP_MINGW
31 # define socklen_t int
32 # define ERROR_NUM WSAGetLastError()
33 #elif defined NL_OS_UNIX
35 # include <sys/types.h>
36 # include <sys/time.h>
37 # include <sys/socket.h>
38 # include <netinet/in.h>
39 # include <netinet/tcp.h>
40 # include <arpa/inet.h>
43 # define SOCKET_ERROR -1
44 # define INVALID_SOCKET -1
45 # define ERROR_NUM errno
46 # define ERROR_MSG strerror(errno)
50 using namespace NLMISC
;
58 CTcpSock::CTcpSock( bool logging
) :
64 * Construct a CTcpSocket object using an already connected socket
66 CTcpSock::CTcpSock( SOCKET sock
, const CInetAddress
& remoteaddr
) :
67 CSock( sock
, remoteaddr
)
71 /* Connection. You can reconnect a socket after being disconnected.
72 * This method does not return a boolean, otherwise a programmer could ignore the result and no
73 * exception would be thrown if connection fails :
74 * - If addr is not valid, an exception ESocket is thrown
75 * - If connect() fails for another reason, an exception ESocketConnectionFailed is thrown
77 void CTcpSock::connect( const CInetAddress
& addr
)
79 // Create a new socket
80 if ( _Sock
!= INVALID_SOCKET
)
84 // LNETL0_DEBUG( "LNETL0: Closing socket %d before reconnecting", _Sock );
88 createSocket( SOCK_STREAM
, IPPROTO_TCP
);
90 // activate keep alive
94 CSock::connect( addr
);
99 * Active disconnection. After disconnecting, you can't connect back with the same socket.
101 void CTcpSock::disconnect()
103 LNETL0_DEBUG( "LNETL0: Socket %d disconnecting from %s...", _Sock
, _RemoteAddr
.asString().c_str() );
105 // This shutdown resets the connection immediately (not a graceful closure)
107 ::shutdown( _Sock
, SD_BOTH
);
108 #elif defined NL_OS_UNIX
109 ::shutdown( _Sock
, SHUT_RDWR
);
111 /*CSynchronized<bool>::CAccessor sync( &_SyncConnected );
112 sync.value() = false;*/
118 * Active disconnection for download way only
120 void CTcpSock::shutdownReceiving()
123 ::shutdown( _Sock
, SD_RECEIVE
);
124 #elif defined NL_OS_UNIX
125 ::shutdown( _Sock
, SHUT_RD
);
131 * Active disconnection for upload way only
133 void CTcpSock::shutdownSending()
136 ::shutdown( _Sock
, SD_SEND
);
137 #elif defined NL_OS_UNIX
138 ::shutdown( _Sock
, SHUT_WR
);
144 void CTcpSock::setKeepAlive( bool keepAlive
)
146 nlassert(_Sock
!= INVALID_SOCKET
);
147 int b
= keepAlive
?1:0;
148 if ( setsockopt( _Sock
, SOL_SOCKET
, SO_KEEPALIVE
, (char*)&b
, sizeof(b
) ) != 0 )
150 throw ESocket( "setKeepAlive failed" );
155 * Sets/unsets TCP_NODELAY
157 void CTcpSock::setNoDelay( bool value
)
160 if ( setsockopt( _Sock
, IPPROTO_TCP
, TCP_NODELAY
, (char*)&b
, sizeof(b
) ) != 0 )
162 throw ESocket( "setNoDelay failed" );
167 /* Sets a custom TCP Window size (SO_RCVBUF and SO_SNDBUF).
168 * You must close the socket is necessary, before calling this method.
170 * See http://www.ncsa.uiuc.edu/People/vwelch/net_perf/tcp_windows.html
172 void CTcpSock::connectWithCustomWindowSize( const CInetAddress
& addr
, int windowsize
)
175 if ( _Sock
!= INVALID_SOCKET
)
177 nlerror( "Cannot connect with custom window size when already connected" );
179 createSocket( SOCK_STREAM
, IPPROTO_TCP
);
181 // Change window size
182 if ( setsockopt( _Sock
, SOL_SOCKET
, SO_SNDBUF
, (char*)&windowsize
, sizeof(windowsize
) ) != 0
183 || setsockopt( _Sock
, SOL_SOCKET
, SO_RCVBUF
, (char*)&windowsize
, sizeof(windowsize
) ) != 0 )
185 throw ESocket( "setWindowSize failed" );
189 CSock::connect( addr
);
194 * Returns the TCP Window Size for the current socket
196 uint32
CTcpSock::getWindowSize()
199 socklen_t len
= sizeof( windowsize
);
201 /* send buffer -- query for buffer size */
202 if ( getsockopt( _Sock
, SOL_SOCKET
, SO_SNDBUF
, (char*) &windowsize
, &len
) == 0 )