Return to udp_sock.cpp CVS log | Up to Nevrax / code / nel / src / net |
File: Nevrax / code / nel / src / net / udp_sock.cpp (download) Revision 1.11, Wed Apr 17 09:54:00 2002 UTC (3 months, 1 week ago) by cado Branch: MAIN CVS Tags: georges_v2, HEAD Changes since 1.10: +3 -4 lines BUGFIX: wrong address |
/** \file udp_sock.cpp * Network engine, layer 0, udp socket * * $Id: udp_sock.cpp,v 1.11 2002/04/17 09:54:00 cado Exp $ */ /* Copyright, 2000 Nevrax Ltd. * * This file is part of NEVRAX NEL. * NEVRAX NEL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * NEVRAX NEL is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * You should have received a copy of the GNU General Public License * along with NEVRAX NEL; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ #include "stdnet.h" #include "nel/net/udp_sock.h" #ifdef NL_OS_WINDOWS #include <winsock2.h> #define socklen_t int #define ERROR_NUM WSAGetLastError() #elif defined NL_OS_UNIX #include <unistd.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netdb.h> #include <errno.h> //#include <fcntl.h> #define SOCKET_ERROR -1 #define INVALID_SOCKET -1 #define ERROR_NUM errno #define ERROR_MSG strerror(errno) typedef int SOCKET; #endif using namespace NLMISC; namespace NLNET { /* * Constructor */ CUdpSock::CUdpSock( bool logging ) : CSock( logging ), _Bound( false ) { // Socket creation createSocket( SOCK_DGRAM, IPPROTO_UDP ); } /** Binds the socket to the specified port. Call bind() for an unreliable socket if the host acts as a server and waits for * messages. If the host acts as a client, call sendTo(), there is no need to bind the socket. */ void CUdpSock::bind( uint16 port ) { CInetAddress addr; // any IP address addr.setPort( port ); bind( addr ); setLocalAddress(); // will not set the address if the host is multihomed, use bind(CInetAddress) instead } /* * Same as bind(uint16) but binds on a specified address/port (useful when the host has several addresses) */ void CUdpSock::bind( const CInetAddress& addr ) { #ifndef NL_OS_WINDOWS // Set Reuse Address On (does not work on Win98 and is useless on Win2000) int value = true; if ( setsockopt( _Sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ) == SOCKET_ERROR ) { throw ESocket( "ReuseAddr failed" ); } #endif _LocalAddr = addr; // Bind the socket if ( ::bind( _Sock, (sockaddr*)(_LocalAddr.sockAddr()), sizeof(sockaddr) ) == SOCKET_ERROR ) { throw ESocket( "Bind failed" ); } _Bound = true; if ( _Logging ) { nldebug( "LNETL0: Socket %d bound at %s", _Sock, _LocalAddr.asString().c_str() ); } } /* * Sends a message */ void CUdpSock::sendTo( const uint8 *buffer, uint len, const CInetAddress& addr ) { // Send if ( ::sendto( _Sock, (const char*)buffer, len, 0, (sockaddr*)(addr.sockAddr()), sizeof(sockaddr) ) != (sint32)len ) { throw ESocket( "Unable to send datagram" ); } _BytesSent += len; if ( _Logging ) { nldebug( "LNETL0: Socket %d sent %d bytes to %s", _Sock, len, addr.asString().c_str() ); } // If socket is unbound, retrieve local address if ( ! _Bound ) { setLocalAddress(); _Bound = true; } #ifdef NL_OS_WINDOWS // temporary by ace to know size of SO_MAX_MSG_SIZE static bool first = true; if (first) { uint MMS, SB; int size = sizeof (MMS); getsockopt (_Sock, SOL_SOCKET, SO_SNDBUF, (char *)&SB, &size); getsockopt (_Sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&MMS, &size); nlinfo ("the udp SO_MAX_MSG_SIZE=%u, SO_SNDBUF=%u", MMS, SB); first = false; } #endif } /* * Receives data from the peer. (blocking function) */ void CUdpSock::receive( uint8 *buffer, uint32& len ) { nlassert( _Connected && (buffer!=NULL) ); // Receive incoming message len = ::recv( _Sock, (char*)buffer, len , 0 ); // Check for errors (after setting the address) if ( len == SOCKET_ERROR ) { throw ESocket( "Cannot receive data" ); } _BytesReceived += len; if ( _Logging ) { nldebug( "LNETL0: Socket %d received %d bytes from peer %s", _Sock, len, _RemoteAddr.asString().c_str() ); } } /* * Receives data and say who the sender is. (blocking function) */ void CUdpSock::receivedFrom( uint8 *buffer, uint& len, CInetAddress& addr ) { // Receive incoming message sockaddr_in saddr; socklen_t saddrlen = sizeof(saddr); len = ::recvfrom( _Sock, (char*)buffer, len , 0, (sockaddr*)&saddr, &saddrlen ); // If an error occurs, the saddr is not valid // When the remote socket is closed, get sender's address to know who is quitting addr.setSockAddr( &saddr ); // Check for errors (after setting the address) if ( len == SOCKET_ERROR ) { throw ESocket( "Cannot receive data" ); } _BytesReceived += len; if ( _Logging ) { nldebug( "LNETL0: Socket %d received %d bytes from %s", _Sock, len, addr.asString().c_str() ); } } } // NLNET