mirror of
https://github.com/tribes2/engine.git
synced 2026-01-20 19:54:46 +00:00
739 lines
15 KiB
C++
739 lines
15 KiB
C++
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// V12 Engine
|
||
|
|
//
|
||
|
|
// Copyright (c) 2001 GarageGames.Com
|
||
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
#include <sys/types.h>
|
||
|
|
#include <sys/socket.h>
|
||
|
|
#include <sys/time.h>
|
||
|
|
#include <netdb.h>
|
||
|
|
#include <errno.h>
|
||
|
|
#include <netinet/in.h>
|
||
|
|
#include <arpa/inet.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
|
||
|
|
/* The ares library is a C API */
|
||
|
|
extern "C" {
|
||
|
|
#define class ares_class
|
||
|
|
#include <ares.h>
|
||
|
|
#undef class
|
||
|
|
}
|
||
|
|
|
||
|
|
#include "platformLinux/async.h"
|
||
|
|
|
||
|
|
#include "platformLinux/platformLinux.h"
|
||
|
|
#include "Platform/platform.h"
|
||
|
|
#include "Platform/event.h"
|
||
|
|
#include "console/console.h"
|
||
|
|
#include "Platform/gameInterface.h"
|
||
|
|
#include "Core/fileStream.h"
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Local types
|
||
|
|
//
|
||
|
|
typedef struct {
|
||
|
|
int fd;
|
||
|
|
U16 port;
|
||
|
|
} NameLookup;
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Sundry module-local variables.
|
||
|
|
//
|
||
|
|
static ares_channel channel;
|
||
|
|
static U16 defaultPort = 28000;
|
||
|
|
static U16 netPort = 0;
|
||
|
|
static NetSocket udpSocket = -1;
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Our asychronous callbacks.
|
||
|
|
//
|
||
|
|
static int selectCallback( int fd, int event, int status )
|
||
|
|
{
|
||
|
|
static ConnectedNotifyEvent notifyEvent;
|
||
|
|
static ConnectedReceiveEvent receiveEvent;
|
||
|
|
static ConnectedAcceptEvent acceptEvent;
|
||
|
|
|
||
|
|
int bytesRead = 0;
|
||
|
|
Net::Error error = Net::NoError;
|
||
|
|
|
||
|
|
switch( event ) {
|
||
|
|
case FD_READ:
|
||
|
|
error = Net::recv( fd, receiveEvent.data, MaxPacketDataSize, &bytesRead );
|
||
|
|
|
||
|
|
if( error == Net::NoError & bytesRead != 0 ) {
|
||
|
|
receiveEvent.tag = fd;
|
||
|
|
receiveEvent.size = ConnectedReceiveEventHeaderSize + bytesRead;
|
||
|
|
Game->postEvent( receiveEvent );
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
case FD_CONNECT:
|
||
|
|
notifyEvent.tag = fd;
|
||
|
|
|
||
|
|
if( status ) {
|
||
|
|
notifyEvent.state = ConnectedNotifyEvent::Connected;
|
||
|
|
} else {
|
||
|
|
notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
|
||
|
|
}
|
||
|
|
|
||
|
|
Game->postEvent( notifyEvent );
|
||
|
|
break;
|
||
|
|
case FD_CLOSE:
|
||
|
|
|
||
|
|
for( ; ; ) {
|
||
|
|
error = Net::recv( fd, receiveEvent.data, MaxPacketDataSize, &bytesRead );
|
||
|
|
|
||
|
|
if( error != Net::NoError || bytesRead == 0 ) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
receiveEvent.tag = fd;
|
||
|
|
receiveEvent.size = ConnectedReceiveEventHeaderSize + bytesRead;
|
||
|
|
Game->postEvent( receiveEvent );
|
||
|
|
}
|
||
|
|
|
||
|
|
notifyEvent.tag = fd;
|
||
|
|
notifyEvent.state = ConnectedNotifyEvent::Disconnected;
|
||
|
|
Game->postEvent( notifyEvent );
|
||
|
|
break;
|
||
|
|
case FD_ACCEPT:
|
||
|
|
acceptEvent.portTag = fd;
|
||
|
|
acceptEvent.connectionTag = Net::accept( fd, &acceptEvent.address );
|
||
|
|
|
||
|
|
if( acceptEvent.connectionTag != InvalidSocket ) {
|
||
|
|
Net::setBlocking( acceptEvent.connectionTag, false );
|
||
|
|
AsyncSelect( acceptEvent.connectionTag, selectCallback, FD_READ | FD_CONNECT | FD_CLOSE );
|
||
|
|
Game->postEvent( acceptEvent );
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
static void lookupCallback( void* arg, int status, struct hostent* host )
|
||
|
|
{
|
||
|
|
static ConnectedNotifyEvent notifyEvent;
|
||
|
|
|
||
|
|
char* errorMem = 0;
|
||
|
|
char** addr = 0;
|
||
|
|
NameLookup* lookup = static_cast<NameLookup*>( arg );
|
||
|
|
|
||
|
|
if( status != ARES_SUCCESS ) {
|
||
|
|
ares_strerror( status, &errorMem );
|
||
|
|
Con::printf( "couldn't perform lookup: %s", errorMem );
|
||
|
|
ares_free_errmem( errorMem );
|
||
|
|
delete lookup;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct sockaddr_in ipAddr;
|
||
|
|
|
||
|
|
dMemcpy( &ipAddr.sin_addr.s_addr, host->h_addr_list[0], sizeof( struct in_addr ) );
|
||
|
|
ipAddr.sin_port = lookup->port;
|
||
|
|
ipAddr.sin_family = AF_INET;
|
||
|
|
|
||
|
|
notifyEvent.tag = lookup->fd;
|
||
|
|
|
||
|
|
int error = ::connect( lookup->fd, (struct sockaddr*) &ipAddr, sizeof( ipAddr ) );
|
||
|
|
|
||
|
|
if( error == -1 && errno != EINPROGRESS ) {
|
||
|
|
notifyEvent.state = ConnectedNotifyEvent::DNSFailed;
|
||
|
|
::close( lookup->fd );
|
||
|
|
} else {
|
||
|
|
AsyncSelect( lookup->fd, selectCallback, FD_READ | FD_CONNECT | FD_CLOSE );
|
||
|
|
notifyEvent.state = ConnectedNotifyEvent::DNSResolved;
|
||
|
|
}
|
||
|
|
|
||
|
|
Game->postEvent( notifyEvent );
|
||
|
|
delete lookup;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Utilities.
|
||
|
|
//
|
||
|
|
static void netToIPSocketAddress( const NetAddress* addr, struct sockaddr_in* ip )
|
||
|
|
{
|
||
|
|
memset( ip, 0, sizeof( struct sockaddr_in ) );
|
||
|
|
ip->sin_family = AF_INET;
|
||
|
|
ip->sin_port = htons( addr->port );
|
||
|
|
ip->sin_addr.s_addr = *( (U32*) addr->netNum );
|
||
|
|
}
|
||
|
|
|
||
|
|
static void IPSocketToNetAddress( const sockaddr_in* ip, NetAddress* addr )
|
||
|
|
{
|
||
|
|
addr->type = NetAddress::IPAddress;
|
||
|
|
addr->port = htons( ip->sin_port );
|
||
|
|
*( (U32*) addr->netNum ) = ip->sin_addr.s_addr;
|
||
|
|
}
|
||
|
|
|
||
|
|
static Net::Error getLastError( void )
|
||
|
|
{
|
||
|
|
|
||
|
|
// God knows what distinguishes Invalid from Wrong...
|
||
|
|
switch( errno ) {
|
||
|
|
case 0:
|
||
|
|
return Net::NoError;
|
||
|
|
case EBADF:
|
||
|
|
case ENOTSOCK:
|
||
|
|
return Net::NotASocket;
|
||
|
|
case EAGAIN:
|
||
|
|
return Net::WouldBlock;
|
||
|
|
case ENOTCONN:
|
||
|
|
return Net::InvalidPacketProtocol;
|
||
|
|
case EOPNOTSUPP:
|
||
|
|
return Net::WrongProtocolType;
|
||
|
|
default:
|
||
|
|
return Net::UnknownError;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// Net:: implementation
|
||
|
|
//
|
||
|
|
bool Net::init( void )
|
||
|
|
{
|
||
|
|
int status;
|
||
|
|
char* errorMem;
|
||
|
|
|
||
|
|
if( AsyncInit( ) == -1 ) {
|
||
|
|
Con::printf( "AsyncInit failed" );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
status = ares_init( &channel );
|
||
|
|
|
||
|
|
if( status != ARES_SUCCESS ) {
|
||
|
|
Con::printf( "ares_init: %s", ares_strerror( status, &errorMem ) );
|
||
|
|
ares_free_errmem( errorMem );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Net::shutdown( void )
|
||
|
|
{
|
||
|
|
AsyncShutdown( );
|
||
|
|
ares_destroy( channel );
|
||
|
|
closePort( );
|
||
|
|
}
|
||
|
|
|
||
|
|
NetSocket Net::openListenPort( U16 port )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( Game->isJournalReading( ) ) {
|
||
|
|
U32 ret;
|
||
|
|
Game->journalRead( &ret );
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
NetSocket fd = openSocket( );
|
||
|
|
bind( fd, port );
|
||
|
|
listen( fd, 4 );
|
||
|
|
setBlocking( fd, false );
|
||
|
|
|
||
|
|
if( AsyncSelect( fd, selectCallback, FD_ACCEPT ) == -1 ) {
|
||
|
|
Con::printf( "Error: %d", errno );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( Game->isJournalWriting( ) ) {
|
||
|
|
Game->journalWrite( fd );
|
||
|
|
}
|
||
|
|
|
||
|
|
return fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
NetSocket Net::openConnectTo( const char* addressString )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( !dStrnicmp( addressString, "ip:", 3 ) ) {
|
||
|
|
addressString += 3;
|
||
|
|
}
|
||
|
|
|
||
|
|
char remoteAddr[256];
|
||
|
|
dStrncpy( remoteAddr, addressString, 256 );
|
||
|
|
|
||
|
|
char* portString = dStrchr( remoteAddr, ':' );
|
||
|
|
U16 port;
|
||
|
|
|
||
|
|
if( portString ) {
|
||
|
|
*portString++ = 0;
|
||
|
|
port = htons( dAtoi( portString ) );
|
||
|
|
} else {
|
||
|
|
port = htons( defaultPort );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( !dStricmp( remoteAddr, "broadcast" ) ) {
|
||
|
|
return InvalidSocket;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( Game->isJournalReading( ) ) {
|
||
|
|
U32 ret;
|
||
|
|
Game->journalRead( &ret );
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
NetSocket fd = openSocket( );
|
||
|
|
setBlocking( fd, false );
|
||
|
|
|
||
|
|
struct sockaddr_in ipAddr;
|
||
|
|
|
||
|
|
ipAddr.sin_addr.s_addr = inet_addr( remoteAddr );
|
||
|
|
|
||
|
|
if( ipAddr.sin_addr.s_addr != INADDR_NONE ) {
|
||
|
|
ipAddr.sin_port = port;
|
||
|
|
ipAddr.sin_family = AF_INET;
|
||
|
|
|
||
|
|
int error = ::connect( fd, (struct sockaddr*) &ipAddr, sizeof( ipAddr ) );
|
||
|
|
|
||
|
|
if( error == -1 && errno != EINPROGRESS ) {
|
||
|
|
Con::printf( "Last error: %d", errno );
|
||
|
|
::close( fd );
|
||
|
|
fd = InvalidSocket;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( fd != InvalidSocket ) {
|
||
|
|
AsyncSelect( fd, selectCallback, FD_READ | FD_CONNECT | FD_CLOSE );
|
||
|
|
}
|
||
|
|
|
||
|
|
} else {
|
||
|
|
NameLookup* lookup = new NameLookup;
|
||
|
|
lookup->fd = fd;
|
||
|
|
lookup->port = port;
|
||
|
|
ares_gethostbyname( channel, remoteAddr, AF_INET, lookupCallback, lookup );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( Game->isJournalWriting( ) ) {
|
||
|
|
Game->journalWrite( fd );
|
||
|
|
}
|
||
|
|
|
||
|
|
return fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Net::closeConnectTo( NetSocket fd )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( Game->isJournalReading( ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
AsyncCancel( fd );
|
||
|
|
|
||
|
|
::close( fd );
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::sendTo( NetSocket fd, const U8* buffer, int size )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( Game->isJournalReading( ) ) {
|
||
|
|
U32 error;
|
||
|
|
Game->journalRead( &error );
|
||
|
|
return static_cast<Net::Error>( error );
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error error = send( fd, buffer, size );
|
||
|
|
|
||
|
|
if( Game->isJournalWriting( ) ) {
|
||
|
|
Game->journalWrite( static_cast<U32>( error ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
return error;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Net::openPort( S32 port )
|
||
|
|
{
|
||
|
|
closePort( );
|
||
|
|
|
||
|
|
udpSocket = socket( AF_INET, SOCK_DGRAM, 0 );
|
||
|
|
|
||
|
|
if( udpSocket != -1 ) {
|
||
|
|
Net::Error error;
|
||
|
|
|
||
|
|
error = bind( udpSocket, port );
|
||
|
|
|
||
|
|
if( error == NoError ) {
|
||
|
|
error = setBufferSize( udpSocket, 32768 );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( error == NoError ) {
|
||
|
|
error = setBroadcast( udpSocket, true );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( error == NoError ) {
|
||
|
|
error = setBlocking( udpSocket, false );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( error == NoError ) {
|
||
|
|
Con::printf( "UDP initialized on port %d", port );
|
||
|
|
} else {
|
||
|
|
close( udpSocket );
|
||
|
|
udpSocket = -1;
|
||
|
|
Con::printf( "Unable to initialize UDP -- error %d", error );
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
netPort = port;
|
||
|
|
return ( udpSocket != -1 );
|
||
|
|
}
|
||
|
|
|
||
|
|
void Net::closePort( void )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( udpSocket != -1 ) {
|
||
|
|
close( udpSocket );
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::sendto( const NetAddress* addr, const U8* buffer, S32 size )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( Game->isJournalReading( ) ) {
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct sockaddr_in ip;
|
||
|
|
netToIPSocketAddress( addr, &ip );
|
||
|
|
|
||
|
|
if( ::sendto( udpSocket, buffer, size, 0, (struct sockaddr*) &ip, sizeof( ip ) ) == -1 ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Net::process( void )
|
||
|
|
{
|
||
|
|
PacketReceiveEvent event;
|
||
|
|
|
||
|
|
for( ; ; ) {
|
||
|
|
struct sockaddr sa;
|
||
|
|
socklen_t length = sizeof( sa );
|
||
|
|
S32 bytes = -1;
|
||
|
|
|
||
|
|
if( udpSocket != -1 ) {
|
||
|
|
bytes = recvfrom( udpSocket, event.data, MaxPacketDataSize, 0, &sa, &length );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( bytes == -1 ) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( sa.sa_family == AF_INET ) {
|
||
|
|
IPSocketToNetAddress( (struct sockaddr_in*) &sa, &event.sourceAddress );
|
||
|
|
} else {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
NetAddress& addr = event.sourceAddress;
|
||
|
|
|
||
|
|
if( addr.type == NetAddress::IPAddress &&
|
||
|
|
addr.netNum[0] == 127 && addr.netNum[1] == 0 &&
|
||
|
|
addr.netNum[1] == 0 && addr.netNum[2] == 1 &&
|
||
|
|
addr.port == netPort ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( bytes <= 0 ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
event.size = PacketReceiveEventHeaderSize + bytes;
|
||
|
|
Game->postEvent( event );
|
||
|
|
}
|
||
|
|
|
||
|
|
// do ares DNS processing
|
||
|
|
fd_set read_fds, write_fds;
|
||
|
|
int nfds = 0;
|
||
|
|
struct timeval* timeout = 0;
|
||
|
|
struct timeval tv;
|
||
|
|
struct timezone tz;
|
||
|
|
|
||
|
|
FD_ZERO( &read_fds );
|
||
|
|
FD_ZERO( &write_fds );
|
||
|
|
nfds = ares_fds( channel, &read_fds, &write_fds );
|
||
|
|
|
||
|
|
if( nfds == 0 ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
timeout = ares_timeout( channel, 0, &tv );
|
||
|
|
select( nfds, &read_fds, &write_fds, 0, timeout );
|
||
|
|
ares_process( channel, &read_fds, &write_fds );
|
||
|
|
}
|
||
|
|
|
||
|
|
NetSocket Net::openSocket( void )
|
||
|
|
{
|
||
|
|
int fd;
|
||
|
|
|
||
|
|
if( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) {
|
||
|
|
return InvalidSocket;
|
||
|
|
}
|
||
|
|
|
||
|
|
return fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::closeSocket( NetSocket fd )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( fd == InvalidSocket ) {
|
||
|
|
return NotASocket;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( close( fd ) ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::connect( NetSocket fd, const NetAddress* addr )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( addr->type != NetAddress::IPAddress ) {
|
||
|
|
return WrongProtocolType;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct sockaddr_in addrIn;
|
||
|
|
|
||
|
|
netToIPSocketAddress( addr, &addrIn );
|
||
|
|
|
||
|
|
if( ::connect( fd, (struct sockaddr*) &addrIn, sizeof( addrIn ) ) ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::listen( NetSocket fd, S32 backlog )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( ::listen( fd, backlog ) ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
NetSocket Net::accept( NetSocket fd, NetAddress* addr )
|
||
|
|
{
|
||
|
|
struct sockaddr_in ip;
|
||
|
|
socklen_t length = sizeof( ip );
|
||
|
|
|
||
|
|
int ret = ::accept( fd, (struct sockaddr*) &ip, &length );
|
||
|
|
|
||
|
|
if( ret != -1 ) {
|
||
|
|
IPSocketToNetAddress( &ip, addr );
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
return InvalidSocket;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::bind( NetSocket fd, U16 port )
|
||
|
|
{
|
||
|
|
struct sockaddr_in ip;
|
||
|
|
|
||
|
|
dMemset( &ip, 0, sizeof( ip ) );
|
||
|
|
ip.sin_family = AF_INET;
|
||
|
|
|
||
|
|
// It's entirely possible that there are two NIC cards.
|
||
|
|
// We let the user specify which one the server runs on.
|
||
|
|
|
||
|
|
// thanks to [TPG]P1aGu3 for the name
|
||
|
|
const char* serverIP = Con::getVariable( "Host::BindAddress" );
|
||
|
|
// serverIP is guaranteed to be non-0.
|
||
|
|
AssertFatal( serverIP, "serverIP is NULL!" );
|
||
|
|
|
||
|
|
if( serverIP[0] != '\0' ) {
|
||
|
|
// we're not empty
|
||
|
|
ip.sin_addr.s_addr = inet_addr( serverIP );
|
||
|
|
|
||
|
|
if( ip.sin_addr.s_addr != INADDR_NONE ) {
|
||
|
|
Con::printf( "Binding server port to %s", serverIP );
|
||
|
|
} else {
|
||
|
|
Con::warnf( ConsoleLogEntry::General,
|
||
|
|
"inet_addr() failed for %s while binding!",
|
||
|
|
serverIP );
|
||
|
|
ip.sin_addr.s_addr = INADDR_ANY;
|
||
|
|
}
|
||
|
|
|
||
|
|
} else {
|
||
|
|
Con::printf( "Binding server port to default IP" );
|
||
|
|
ip.sin_addr.s_addr = INADDR_ANY;
|
||
|
|
}
|
||
|
|
|
||
|
|
ip.sin_port = htons( port );
|
||
|
|
|
||
|
|
if( ::bind( fd, (struct sockaddr*) &ip, sizeof( ip ) ) ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::setBufferSize( NetSocket fd, S32 size )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof( size ) ) ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( setsockopt( fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof( size ) ) ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::setBroadcast( NetSocket fd, bool broadcast )
|
||
|
|
{
|
||
|
|
S32 bc = broadcast;
|
||
|
|
|
||
|
|
if( setsockopt( fd, SOL_SOCKET, SO_BROADCAST, &bc, sizeof( bc ) ) ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::setBlocking( NetSocket fd, bool blocking )
|
||
|
|
{
|
||
|
|
int flags;
|
||
|
|
|
||
|
|
// Let's do it the Posix.1g way!
|
||
|
|
if( ( flags = fcntl( fd, F_GETFL, 0 ) ) < 0 ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
if( blocking ) {
|
||
|
|
flags &= ~O_NONBLOCK;
|
||
|
|
} else {
|
||
|
|
flags |= O_NONBLOCK;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( fcntl( fd, F_SETFL, flags ) < 0 ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::send( NetSocket fd, const U8* buffer, S32 size )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( ::send( fd, buffer, size, 0 ) == -1 ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
Net::Error Net::recv( NetSocket fd, U8* buffer, S32 size, S32* read )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( ( *read = ::recv( fd, buffer, size, 0 ) ) == -1 ) {
|
||
|
|
return getLastError( );
|
||
|
|
}
|
||
|
|
|
||
|
|
return NoError;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Net::compareAddresses( const NetAddress* a1, const NetAddress* a2 )
|
||
|
|
{
|
||
|
|
// cast our separated ipv4 into a 32-bit word for compare
|
||
|
|
bool sameType = ( a1->type == a2->type );
|
||
|
|
bool sameNum = ( *( (U32*) a1->netNum ) == *( (U32*) a2->netNum ) );
|
||
|
|
bool samePort = ( a1->port == a2->port );
|
||
|
|
return ( sameType && sameNum && samePort );
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Net::stringToAddress( const char* addressString, NetAddress* address )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( dStrnicmp( addressString, "ip:", 3 ) == 0 ) {
|
||
|
|
addressString += 3;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( dStrnicmp( addressString, "ipx:", 4 ) == 0 ) {
|
||
|
|
// foo on IPX.
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( dStrlen( addressString ) > 255 ) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct sockaddr_in ipAddr;
|
||
|
|
char remoteAddr[256];
|
||
|
|
dStrcpy( remoteAddr, addressString );
|
||
|
|
char* portString = dStrchr( remoteAddr, ':' );
|
||
|
|
|
||
|
|
if( portString ) {
|
||
|
|
*portString++ = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct hostent* he = 0;
|
||
|
|
|
||
|
|
if( dStricmp( remoteAddr, "broadcast" ) == 0 ) {
|
||
|
|
ipAddr.sin_addr.s_addr = htonl( INADDR_BROADCAST );
|
||
|
|
} else {
|
||
|
|
ipAddr.sin_addr.s_addr = inet_addr( remoteAddr );
|
||
|
|
|
||
|
|
if( ipAddr.sin_addr.s_addr == INADDR_NONE ) {
|
||
|
|
|
||
|
|
if( ( he == gethostbyname( remoteAddr ) ) == NULL ) {
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
memcpy( &ipAddr.sin_addr.s_addr, he->h_addr, sizeof( struct in_addr ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( portString ) {
|
||
|
|
ipAddr.sin_port = htons( dAtoi( portString ) );
|
||
|
|
} else {
|
||
|
|
ipAddr.sin_port = htons( defaultPort );
|
||
|
|
}
|
||
|
|
|
||
|
|
ipAddr.sin_family = AF_INET;
|
||
|
|
IPSocketToNetAddress( &ipAddr, address );
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Net::addressToString( const NetAddress* address, char addressString[256] )
|
||
|
|
{
|
||
|
|
|
||
|
|
if( address->type == NetAddress::IPAddress ) {
|
||
|
|
struct sockaddr_in ipAddr;
|
||
|
|
|
||
|
|
netToIPSocketAddress( address, &ipAddr );
|
||
|
|
|
||
|
|
if( ipAddr.sin_addr.s_addr == htonl( INADDR_BROADCAST ) ) {
|
||
|
|
dSprintf( addressString, 256, "IP:Broadcast:%d", ntohs( ipAddr.sin_port ) );
|
||
|
|
} else {
|
||
|
|
dSprintf( addressString, 256, "IP:%d.%d.%d.%d:%d",
|
||
|
|
( ipAddr.sin_addr.s_addr ) & 0xff,
|
||
|
|
( ipAddr.sin_addr.s_addr >> 8 ) & 0xff,
|
||
|
|
( ipAddr.sin_addr.s_addr >> 16 ) & 0xff,
|
||
|
|
( ipAddr.sin_addr.s_addr >> 24 ) & 0xff,
|
||
|
|
ntohs( ipAddr.sin_port ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|