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/udp_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>
44 # define SOCKET_ERROR -1
45 # define INVALID_SOCKET -1
46 # define ERROR_NUM errno
47 # define ERROR_MSG strerror(errno)
51 using namespace NLMISC
;
59 CUdpSock::CUdpSock( bool logging
) :
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
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
)
86 // Set Reuse Address On (does not work on Win98 and is useless on Win2000)
88 if ( setsockopt( _Sock
, SOL_SOCKET
, SO_REUSEADDR
, &value
, sizeof(value
) ) == SOCKET_ERROR
)
90 throw ESocket( "ReuseAddr failed" );
97 if ( ::bind( _Sock
, (sockaddr
*)(_LocalAddr
.sockAddr()), sizeof(sockaddr
) ) == SOCKET_ERROR
)
99 throw ESocket( "Bind failed" );
104 LNETL0_DEBUG( "LNETL0: Socket %d bound at %s", _Sock
, _LocalAddr
.asString().c_str() );
112 void CUdpSock::sendTo( const uint8
*buffer
, uint len
, const CInetAddress
& addr
)
116 if ( ::sendto( _Sock
, (const char*)buffer
, len
, 0, (sockaddr
*)(addr
.sockAddr()), sizeof(sockaddr
) ) != (sint32
)len
)
118 throw ESocket( "Unable to send datagram" );
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
135 // temporary by ace to know size of SO_MAX_MSG_SIZE
136 static bool first
= true;
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
);
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" );
168 _BytesReceived
+= len
;
171 LNETL0_DEBUG( "LNETL0: Socket %d received %d bytes from peer %s", _Sock
, len
, _RemoteAddr
.asString().c_str() );
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
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" );
200 _BytesReceived
+= len
;
203 LNETL0_DEBUG( "LNETL0: Socket %d received %d bytes from %s", _Sock
, len
, addr
.asString().c_str() );