Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / udp_sock.cpp
blob1968ca1da01e776e3621167772ce0f1b62e2fa74
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/udp_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 //#include <fcntl.h>
44 # define SOCKET_ERROR -1
45 # define INVALID_SOCKET -1
46 # define ERROR_NUM errno
47 # define ERROR_MSG strerror(errno)
48 typedef int SOCKET;
49 #endif
51 using namespace NLMISC;
53 namespace NLNET {
57 * Constructor
59 CUdpSock::CUdpSock( bool logging ) :
60 CSock( logging ),
61 _Bound( false )
63 // Socket creation
64 createSocket( SOCK_DGRAM, IPPROTO_UDP );
68 /** Binds the socket to the specified port. Call bind() for an unreliable socket if the host acts as a server and waits for
69 * messages. If the host acts as a client, call sendTo(), there is no need to bind the socket.
71 void CUdpSock::bind( uint16 port )
73 CInetAddress addr; // any IP address
74 addr.setPort( port );
75 bind( addr );
76 setLocalAddress(); // will not set the address if the host is multihomed, use bind(CInetAddress) instead
81 * Same as bind(uint16) but binds on a specified address/port (useful when the host has several addresses)
83 void CUdpSock::bind( const CInetAddress& addr )
85 #ifndef NL_OS_WINDOWS
86 // Set Reuse Address On (does not work on Win98 and is useless on Win2000)
87 int value = true;
88 if ( setsockopt( _Sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ) == SOCKET_ERROR )
90 throw ESocket( "ReuseAddr failed" );
92 #endif
94 _LocalAddr = addr;
96 // Bind the socket
97 if ( ::bind( _Sock, (sockaddr*)(_LocalAddr.sockAddr()), sizeof(sockaddr) ) == SOCKET_ERROR )
99 throw ESocket( "Bind failed" );
101 _Bound = true;
102 if ( _Logging )
104 LNETL0_DEBUG( "LNETL0: Socket %d bound at %s", _Sock, _LocalAddr.asString().c_str() );
110 * Sends a message
112 void CUdpSock::sendTo( const uint8 *buffer, uint len, const CInetAddress& addr )
115 // Send
116 if ( ::sendto( _Sock, (const char*)buffer, len, 0, (sockaddr*)(addr.sockAddr()), sizeof(sockaddr) ) != (sint32)len )
118 throw ESocket( "Unable to send datagram" );
120 _BytesSent += len;
122 if ( _Logging )
124 LNETL0_DEBUG( "LNETL0: Socket %d sent %d bytes to %s", _Sock, len, addr.asString().c_str() );
127 // If socket is unbound, retrieve local address
128 if ( ! _Bound )
130 setLocalAddress();
131 _Bound = true;
134 #ifdef NL_OS_WINDOWS
135 // temporary by ace to know size of SO_MAX_MSG_SIZE
136 static bool first = true;
137 if (first)
139 uint MMS, SB;
140 int size = sizeof (MMS);
141 getsockopt (_Sock, SOL_SOCKET, SO_SNDBUF, (char *)&SB, &size);
142 getsockopt (_Sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&MMS, &size);
143 LNETL0_INFO ("LNETL0: The udp SO_MAX_MSG_SIZE=%u, SO_SNDBUF=%u", MMS, SB);
144 first = false;
146 #endif
151 * Receives data from the peer. (blocking function)
153 bool CUdpSock::receive( uint8 *buffer, uint32& len, bool throw_exception )
155 nlassert( _Connected && (buffer!=NULL) );
157 // Receive incoming message
158 len = ::recv( _Sock, (char*)buffer, len , 0 );
160 // Check for errors (after setting the address)
161 if ( ((int)len) == SOCKET_ERROR )
163 if ( throw_exception )
164 throw ESocket( "Cannot receive data" );
165 return false;
168 _BytesReceived += len;
169 if ( _Logging )
171 LNETL0_DEBUG( "LNETL0: Socket %d received %d bytes from peer %s", _Sock, len, _RemoteAddr.asString().c_str() );
173 return true;
178 * Receives data and say who the sender is. (blocking function)
180 bool CUdpSock::receivedFrom( uint8 *buffer, uint& len, CInetAddress& addr, bool throw_exception )
182 // Receive incoming message
183 sockaddr_in saddr;
184 socklen_t saddrlen = sizeof(saddr);
186 len = ::recvfrom( _Sock, (char*)buffer, len , 0, (sockaddr*)&saddr, &saddrlen );
188 // If an error occurs, the saddr is not valid
189 // When the remote socket is closed, get sender's address to know who is quitting
190 addr.setSockAddr( &saddr );
192 // Check for errors (after setting the address)
193 if ( ((int)len) == SOCKET_ERROR )
195 if ( throw_exception )
196 throw ESocket( "Cannot receive data" );
197 return false;
200 _BytesReceived += len;
201 if ( _Logging )
203 LNETL0_DEBUG( "LNETL0: Socket %d received %d bytes from %s", _Sock, len, addr.asString().c_str() );
205 return true;
209 } // NLNET