Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / tcp_sock.cpp
blob7aee959c36e7eaee383c4af60b3599f16c6efb84
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
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/>.
20 #include "stdnet.h"
22 #include "nel/net/tcp_sock.h"
23 #include "nel/net/net_log.h"
25 #ifdef NL_OS_WINDOWS
26 # include <winsock2.h>
27 # ifndef NL_COMP_MINGW
28 # define NOMINMAX
29 # endif
30 # include <windows.h>
31 # define socklen_t int
32 # define ERROR_NUM WSAGetLastError()
33 #elif defined NL_OS_UNIX
34 # include <unistd.h>
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>
41 # include <netdb.h>
42 # include <cerrno>
43 # define SOCKET_ERROR -1
44 # define INVALID_SOCKET -1
45 # define ERROR_NUM errno
46 # define ERROR_MSG strerror(errno)
47 typedef int SOCKET;
48 #endif
50 using namespace NLMISC;
52 namespace NLNET {
56 * Constructor
58 CTcpSock::CTcpSock( bool logging ) :
59 CSock( 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 )
82 if ( _Logging )
84 // LNETL0_DEBUG( "LNETL0: Closing socket %d before reconnecting", _Sock );
86 close();
88 createSocket( SOCK_STREAM, IPPROTO_TCP );
90 // activate keep alive
91 setKeepAlive(true);
93 // Connection
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)
106 #ifdef NL_OS_WINDOWS
107 ::shutdown( _Sock, SD_BOTH );
108 #elif defined NL_OS_UNIX
109 ::shutdown( _Sock, SHUT_RDWR );
110 #endif
111 /*CSynchronized<bool>::CAccessor sync( &_SyncConnected );
112 sync.value() = false;*/
113 _Connected = false;
118 * Active disconnection for download way only
120 void CTcpSock::shutdownReceiving()
122 #ifdef NL_OS_WINDOWS
123 ::shutdown( _Sock, SD_RECEIVE );
124 #elif defined NL_OS_UNIX
125 ::shutdown( _Sock, SHUT_RD );
126 #endif
131 * Active disconnection for upload way only
133 void CTcpSock::shutdownSending()
135 #ifdef NL_OS_WINDOWS
136 ::shutdown( _Sock, SD_SEND );
137 #elif defined NL_OS_UNIX
138 ::shutdown( _Sock, SHUT_WR );
139 #endif
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 )
159 int b = value?1:0;
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 )
174 // Create socket
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" );
188 // Connection
189 CSock::connect( addr );
194 * Returns the TCP Window Size for the current socket
196 uint32 CTcpSock::getWindowSize()
198 int windowsize = 0;
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 )
204 return windowsize;
206 else
208 return 0;
213 } // NLNET