2004-08-21 01:25:48 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program 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
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2005-07-03 15:16:20 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-21 01:25:48 +00:00
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// net_wins.c
struct sockaddr ;
# include "quakedef.h"
2005-11-29 13:32:15 +00:00
# include "netinc.h"
2004-08-21 01:25:48 +00:00
2005-05-26 12:55:34 +00:00
netadr_t net_local_cl_ipadr ;
netadr_t net_local_cl_ip6adr ;
netadr_t net_local_cl_ipxadr ;
netadr_t net_local_sv_ipadr ;
netadr_t net_local_sv_ip6adr ;
netadr_t net_local_sv_ipxadr ;
2005-11-30 01:20:53 +00:00
netadr_t net_local_sv_tcpipadr ;
2004-08-21 01:25:48 +00:00
netadr_t net_from ;
sizebuf_t net_message ;
//#define MAX_UDP_PACKET (MAX_MSGLEN*2) // one more than msg + header
# define MAX_UDP_PACKET 8192 // one more than msg + header
qbyte net_message_buffer [ MAX_UDP_PACKET ] ;
# ifdef _WIN32
WSADATA winsockdata ;
# endif
# ifdef IPPROTO_IPV6
# ifdef _WIN32
int ( WINAPI * pgetaddrinfo ) (
const char * nodename ,
const char * servname ,
const struct addrinfo * hints ,
struct addrinfo * * res
) ;
void ( WSAAPI * pfreeaddrinfo ) ( struct addrinfo * ) ;
# else
# define pgetaddrinfo getaddrinfo
# define pfreeaddrinfo freeaddrinfo
/*int (*pgetaddrinfo)
(
const char * nodename ,
const char * servname ,
const struct addrinfo * hints ,
struct addrinfo * * res
) ;
void ( * pfreeaddrinfo ) ( struct addrinfo * ) ;
*/
# endif
# endif
2005-11-30 01:20:53 +00:00
void NET_GetLocalAddress ( int socket , netadr_t * out ) ;
int TCP_OpenListenSocket ( int port ) ;
2004-08-21 01:25:48 +00:00
2005-06-04 04:20:20 +00:00
extern cvar_t sv_public , sv_listen ;
2005-11-30 01:20:53 +00:00
extern cvar_t sv_tcpport ;
2004-08-21 01:25:48 +00:00
# define MAX_LOOPBACK 4
typedef struct
{
qbyte data [ MAX_UDP_PACKET ] ;
int datalen ;
} loopmsg_t ;
typedef struct
{
loopmsg_t msgs [ MAX_LOOPBACK ] ;
int get , send ;
} loopback_t ;
loopback_t loopbacks [ 2 ] ;
//=============================================================================
2005-11-30 01:20:53 +00:00
int NetadrToSockadr ( netadr_t * a , struct sockaddr_qstorage * s )
2004-08-21 01:25:48 +00:00
{
switch ( a - > type )
{
case NA_BROADCAST_IP :
memset ( s , 0 , sizeof ( struct sockaddr_in ) ) ;
( ( struct sockaddr_in * ) s ) - > sin_family = AF_INET ;
* ( int * ) & ( ( struct sockaddr_in * ) s ) - > sin_addr = INADDR_BROADCAST ;
( ( struct sockaddr_in * ) s ) - > sin_port = a - > port ;
2005-11-30 01:20:53 +00:00
return sizeof ( struct sockaddr_in ) ;
2004-08-21 01:25:48 +00:00
case NA_IP :
memset ( s , 0 , sizeof ( struct sockaddr_in ) ) ;
( ( struct sockaddr_in * ) s ) - > sin_family = AF_INET ;
2006-02-17 02:51:59 +00:00
* ( int * ) & ( ( struct sockaddr_in * ) s ) - > sin_addr = * ( int * ) & a - > address . ip ;
2004-08-21 01:25:48 +00:00
( ( struct sockaddr_in * ) s ) - > sin_port = a - > port ;
2005-11-30 01:20:53 +00:00
return sizeof ( struct sockaddr_in ) ;
2004-08-21 01:25:48 +00:00
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
memset ( s , 0 , sizeof ( struct sockaddr_in ) ) ;
( ( struct sockaddr_in6 * ) s ) - > sin6_family = AF_INET6 ;
memset ( ( int * ) & ( ( struct sockaddr_in6 * ) s ) - > sin6_addr , 0 , sizeof ( * ( int * ) & ( ( struct sockaddr_in6 * ) s ) - > sin6_addr ) ) ;
( ( struct sockaddr_in6 * ) s ) - > sin6_addr . s6_addr [ 0 ] = 0xff ;
( ( struct sockaddr_in6 * ) s ) - > sin6_addr . s6_addr [ 1 ] = 0x02 ;
( ( struct sockaddr_in6 * ) s ) - > sin6_addr . s6_addr [ 15 ] = 0x01 ;
( ( struct sockaddr_in6 * ) s ) - > sin6_port = a - > port ;
2005-11-30 01:20:53 +00:00
return sizeof ( struct sockaddr_in6 ) ;
2004-08-21 01:25:48 +00:00
case NA_IPV6 :
memset ( s , 0 , sizeof ( struct sockaddr_in ) ) ;
( ( struct sockaddr_in6 * ) s ) - > sin6_family = AF_INET6 ;
2006-02-17 02:51:59 +00:00
memcpy ( & ( ( struct sockaddr_in6 * ) s ) - > sin6_addr , a - > address . ip6 , sizeof ( struct in6_addr ) ) ;
2004-08-21 01:25:48 +00:00
( ( struct sockaddr_in6 * ) s ) - > sin6_port = a - > port ;
2005-11-30 01:20:53 +00:00
return sizeof ( struct sockaddr_in6 ) ;
2004-08-21 01:25:48 +00:00
# endif
# ifdef USEIPX
case NA_IPX :
( ( struct sockaddr_ipx * ) s ) - > sa_family = AF_IPX ;
2006-02-17 02:51:59 +00:00
memcpy ( ( ( struct sockaddr_ipx * ) s ) - > sa_netnum , & a - > address . ipx [ 0 ] , 4 ) ;
memcpy ( ( ( struct sockaddr_ipx * ) s ) - > sa_nodenum , & a - > address . ipx [ 4 ] , 6 ) ;
2004-08-21 01:25:48 +00:00
( ( struct sockaddr_ipx * ) s ) - > sa_socket = a - > port ;
2005-11-30 01:20:53 +00:00
return sizeof ( struct sockaddr_ipx ) ;
2004-08-21 01:25:48 +00:00
case NA_BROADCAST_IPX :
memset ( s , 0 , sizeof ( struct sockaddr_ipx ) ) ;
( ( struct sockaddr_ipx * ) s ) - > sa_family = AF_IPX ;
memset ( & ( ( struct sockaddr_ipx * ) s ) - > sa_netnum , 0 , 4 ) ;
memset ( & ( ( struct sockaddr_ipx * ) s ) - > sa_nodenum , 0xff , 6 ) ;
( ( struct sockaddr_ipx * ) s ) - > sa_socket = a - > port ;
2005-11-30 01:20:53 +00:00
return sizeof ( struct sockaddr_ipx ) ;
2004-08-21 01:25:48 +00:00
# endif
default :
Sys_Error ( " Bad type - needs fixing " ) ;
2005-11-30 01:20:53 +00:00
return 0 ;
2004-08-21 01:25:48 +00:00
}
}
void SockadrToNetadr ( struct sockaddr_qstorage * s , netadr_t * a )
{
2005-01-29 02:26:42 +00:00
switch ( ( ( struct sockaddr * ) s ) - > sa_family )
2004-08-21 01:25:48 +00:00
{
case AF_INET :
a - > type = NA_IP ;
2006-02-17 02:51:59 +00:00
* ( int * ) & a - > address . ip = ( ( struct sockaddr_in * ) s ) - > sin_addr . s_addr ;
2004-08-21 01:25:48 +00:00
a - > port = ( ( struct sockaddr_in * ) s ) - > sin_port ;
break ;
# ifdef IPPROTO_IPV6
case AF_INET6 :
a - > type = NA_IPV6 ;
2006-02-17 02:51:59 +00:00
memcpy ( & a - > address . ip6 , & ( ( struct sockaddr_in6 * ) s ) - > sin6_addr , sizeof ( a - > address . ip6 ) ) ;
2004-08-21 01:25:48 +00:00
a - > port = ( ( struct sockaddr_in6 * ) s ) - > sin6_port ;
break ;
# endif
# ifdef USEIPX
case AF_IPX :
a - > type = NA_IPX ;
2006-02-17 02:51:59 +00:00
* ( int * ) a - > address . ip = 0xffffffff ;
memcpy ( & a - > address . ipx [ 0 ] , ( ( struct sockaddr_ipx * ) s ) - > sa_netnum , 4 ) ;
memcpy ( & a - > address . ipx [ 4 ] , ( ( struct sockaddr_ipx * ) s ) - > sa_nodenum , 6 ) ;
2004-08-21 01:25:48 +00:00
a - > port = ( ( struct sockaddr_ipx * ) s ) - > sa_socket ;
break ;
# endif
case AF_UNSPEC :
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_INVALID ;
break ;
default :
Sys_Error ( " SockadrToNetadr: bad socket family " ) ;
}
}
qboolean NET_CompareAdr ( netadr_t a , netadr_t b )
{
if ( a . type ! = b . type )
return false ;
if ( a . type = = NA_LOOPBACK )
return true ;
if ( a . type = = NA_IP | | a . type = = NA_BROADCAST_IP )
{
2006-02-17 02:51:59 +00:00
if ( ( memcmp ( a . address . ip , b . address . ip , sizeof ( a . address . ip ) ) = = 0 ) & & a . port = = b . port )
2004-08-21 01:25:48 +00:00
return true ;
return false ;
}
# ifdef IPPROTO_IPV6
if ( a . type = = NA_IPV6 | | a . type = = NA_BROADCAST_IP6 )
{
2006-02-17 02:51:59 +00:00
if ( ( memcmp ( a . address . ip6 , b . address . ip6 , sizeof ( a . address . ip6 ) ) = = 0 ) & & a . port = = b . port )
2004-08-21 01:25:48 +00:00
return true ;
return false ;
}
# endif
if ( a . type = = NA_IPX | | a . type = = NA_BROADCAST_IPX )
{
2006-02-17 02:51:59 +00:00
if ( ( memcmp ( a . address . ipx , b . address . ipx , sizeof ( a . address . ipx ) ) = = 0 ) & & a . port = = b . port )
2004-08-21 01:25:48 +00:00
return true ;
return false ;
}
Sys_Error ( " NET_CompareAdr: Bad address type " ) ;
return false ;
}
/*
= = = = = = = = = = = = = = = = = = =
NET_CompareBaseAdr
Compares without the port
= = = = = = = = = = = = = = = = = = =
*/
qboolean NET_CompareBaseAdr ( netadr_t a , netadr_t b )
{
if ( a . type ! = b . type )
return false ;
if ( a . type = = NA_LOOPBACK )
return true ;
if ( a . type = = NA_IP )
{
2006-02-17 02:51:59 +00:00
if ( ( memcmp ( a . address . ip , b . address . ip , sizeof ( a . address . ip ) ) = = 0 ) )
2004-08-21 01:25:48 +00:00
return true ;
return false ;
}
# ifdef IPPROTO_IPV6
if ( a . type = = NA_IPV6 | | a . type = = NA_BROADCAST_IP6 )
{
2006-02-17 02:51:59 +00:00
if ( ( memcmp ( a . address . ip6 , b . address . ip6 , 16 ) = = 0 ) )
2004-08-21 01:25:48 +00:00
return true ;
return false ;
}
# endif
if ( a . type = = NA_IPX )
{
2006-02-17 02:51:59 +00:00
if ( ( memcmp ( a . address . ipx , b . address . ipx , 10 ) = = 0 ) )
2004-08-21 01:25:48 +00:00
return true ;
return false ;
}
Sys_Error ( " NET_CompareBaseAdr: Bad address type " ) ;
return false ;
}
char * NET_AdrToString ( netadr_t a )
{
static char s [ 64 ] ;
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
switch ( a . type )
{
case NA_BROADCAST_IP :
case NA_IP :
2006-02-17 02:51:59 +00:00
sprintf ( s , " %i.%i.%i.%i:%i " ,
a . address . ip [ 0 ] ,
a . address . ip [ 1 ] ,
a . address . ip [ 2 ] ,
a . address . ip [ 3 ] ,
ntohs ( a . port ) ) ;
2004-08-21 01:25:48 +00:00
break ;
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
2006-02-17 02:51:59 +00:00
sprintf ( s , " [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%i " ,
a . address . ip6 [ 0 ] ,
a . address . ip6 [ 1 ] ,
a . address . ip6 [ 2 ] ,
a . address . ip6 [ 3 ] ,
a . address . ip6 [ 4 ] ,
a . address . ip6 [ 5 ] ,
a . address . ip6 [ 6 ] ,
a . address . ip6 [ 7 ] ,
a . address . ip6 [ 8 ] ,
a . address . ip6 [ 9 ] ,
a . address . ip6 [ 10 ] ,
a . address . ip6 [ 11 ] ,
a . address . ip6 [ 12 ] ,
a . address . ip6 [ 13 ] ,
a . address . ip6 [ 14 ] ,
a . address . ip6 [ 15 ] ,
ntohs ( a . port ) ) ;
2004-08-21 01:25:48 +00:00
break ;
# endif
# ifdef USEIPX
case NA_BROADCAST_IPX :
case NA_IPX :
2006-02-17 02:51:59 +00:00
sprintf ( s , " %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i " ,
a . address . ipx [ 0 ] ,
a . address . ipx [ 1 ] ,
a . address . ipx [ 2 ] ,
a . address . ipx [ 3 ] ,
a . address . ipx [ 4 ] ,
a . address . ipx [ 5 ] ,
a . address . ipx [ 6 ] ,
a . address . ipx [ 7 ] ,
a . address . ipx [ 8 ] ,
a . address . ipx [ 9 ] ,
ntohs ( a . port ) ) ;
2004-08-21 01:25:48 +00:00
break ;
# endif
case NA_LOOPBACK :
sprintf ( s , " LocalHost " ) ;
break ;
default :
sprintf ( s , " invalid netadr_t type " ) ;
// Sys_Error("NET_AdrToString: Bad netadr_t type");
}
return s ;
}
char * NET_BaseAdrToString ( netadr_t a )
{
static char s [ 64 ] ;
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
switch ( a . type )
{
case NA_BROADCAST_IP :
case NA_IP :
2006-02-17 02:51:59 +00:00
sprintf ( s , " %i.%i.%i.%i " ,
a . address . ip [ 0 ] ,
a . address . ip [ 1 ] ,
a . address . ip [ 2 ] ,
a . address . ip [ 3 ] ) ;
2004-08-21 01:25:48 +00:00
break ;
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
2006-02-17 02:51:59 +00:00
sprintf ( s , " %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x " ,
a . address . ip6 [ 0 ] ,
a . address . ip6 [ 1 ] ,
a . address . ip6 [ 2 ] ,
a . address . ip6 [ 3 ] ,
a . address . ip6 [ 4 ] ,
a . address . ip6 [ 5 ] ,
a . address . ip6 [ 6 ] ,
a . address . ip6 [ 7 ] ,
a . address . ip6 [ 8 ] ,
a . address . ip6 [ 9 ] ,
a . address . ip6 [ 10 ] ,
a . address . ip6 [ 11 ] ,
a . address . ip6 [ 12 ] ,
a . address . ip6 [ 13 ] ,
a . address . ip6 [ 14 ] ,
a . address . ip6 [ 15 ] ) ;
2004-08-21 01:25:48 +00:00
break ;
# endif
# ifdef USEIPX
case NA_BROADCAST_IPX :
case NA_IPX :
2006-02-17 02:51:59 +00:00
sprintf ( s , " %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x " ,
a . address . ipx [ 0 ] ,
a . address . ipx [ 1 ] ,
a . address . ipx [ 2 ] ,
a . address . ipx [ 3 ] ,
a . address . ipx [ 4 ] ,
a . address . ipx [ 5 ] ,
a . address . ipx [ 6 ] ,
a . address . ipx [ 7 ] ,
a . address . ipx [ 8 ] ,
a . address . ipx [ 9 ] ) ;
2004-08-21 01:25:48 +00:00
break ;
# endif
case NA_LOOPBACK :
sprintf ( s , " LocalHost " ) ;
break ;
default :
Sys_Error ( " NET_BaseAdrToString: Bad netadr_t type " ) ;
}
return s ;
}
/*
= = = = = = = = = = = = =
NET_StringToAdr
idnewt
idnewt : 28000
192.246 .40 .70
192.246 .40 .70 : 28000
any form of ipv6 , including port number .
= = = = = = = = = = = = =
*/
# define DO(src,dest) \
copy [ 0 ] = s [ src ] ; \
copy [ 1 ] = s [ src + 1 ] ; \
sscanf ( copy , " %x " , & val ) ; \
( ( struct sockaddr_ipx * ) sadr ) - > dest = val
qboolean NET_StringToSockaddr ( char * s , struct sockaddr_qstorage * sadr )
{
struct hostent * h ;
char * colon ;
char copy [ 128 ] ;
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
memset ( sadr , 0 , sizeof ( * sadr ) ) ;
# ifdef USEIPX
if ( ( strlen ( s ) > = 23 ) & & ( s [ 8 ] = = ' : ' ) & & ( s [ 21 ] = = ' : ' ) ) // check for an IPX address
{
unsigned int val ;
( ( struct sockaddr_ipx * ) sadr ) - > sa_family = AF_IPX ;
copy [ 2 ] = 0 ;
DO ( 0 , sa_netnum [ 0 ] ) ;
DO ( 2 , sa_netnum [ 1 ] ) ;
DO ( 4 , sa_netnum [ 2 ] ) ;
DO ( 6 , sa_netnum [ 3 ] ) ;
DO ( 9 , sa_nodenum [ 0 ] ) ;
DO ( 11 , sa_nodenum [ 1 ] ) ;
DO ( 13 , sa_nodenum [ 2 ] ) ;
DO ( 15 , sa_nodenum [ 3 ] ) ;
DO ( 17 , sa_nodenum [ 4 ] ) ;
DO ( 19 , sa_nodenum [ 5 ] ) ;
sscanf ( & s [ 22 ] , " %u " , & val ) ;
( ( struct sockaddr_ipx * ) sadr ) - > sa_socket = htons ( ( unsigned short ) val ) ;
}
else
# endif
# ifdef IPPROTO_IPV6
if ( pgetaddrinfo )
{
2006-04-16 03:55:55 +00:00
struct addrinfo * addrinfo = NULL ;
struct addrinfo * pos ;
2004-08-21 01:25:48 +00:00
struct addrinfo udp6hint ;
int error ;
char * port ;
2004-09-07 23:18:20 +00:00
char dupbase [ 256 ] ;
int len ;
2004-08-21 01:25:48 +00:00
memset ( & udp6hint , 0 , sizeof ( udp6hint ) ) ;
2005-06-14 04:52:10 +00:00
udp6hint . ai_family = 0 ; //Any... we check for AF_INET6 or 4
2004-08-21 01:25:48 +00:00
udp6hint . ai_socktype = SOCK_DGRAM ;
udp6hint . ai_protocol = IPPROTO_UDP ;
2005-11-30 01:20:53 +00:00
if ( * s = = ' [ ' )
2004-08-21 01:25:48 +00:00
{
2005-11-30 01:20:53 +00:00
port = strstr ( s , " ]: " ) ;
if ( ! port )
error = EAI_NONAME ;
else
{
2005-12-01 01:21:38 +00:00
error = pgetaddrinfo ( s + 1 , port + 2 , & udp6hint , & addrinfo ) ;
2005-11-30 01:20:53 +00:00
}
2004-08-21 01:25:48 +00:00
}
else
2005-11-30 01:20:53 +00:00
{
port = s + strlen ( s ) ;
while ( port > = s )
{
if ( * port = = ' : ' )
break ;
port - - ;
}
if ( port = = s )
port = NULL ;
if ( port )
{
len = port - s ;
if ( len > = sizeof ( dupbase ) )
len = sizeof ( dupbase ) - 1 ;
strncpy ( dupbase , s , len ) ;
dupbase [ len ] = ' \0 ' ;
error = pgetaddrinfo ( dupbase , port + 1 , & udp6hint , & addrinfo ) ;
}
else
error = EAI_NONAME ;
if ( error ) //failed, try string with no port.
2004-08-21 01:25:48 +00:00
error = pgetaddrinfo ( s , NULL , & udp6hint , & addrinfo ) ; //remember, this func will return any address family that could be using the udp protocol... (ip4 or ip6)
2005-11-30 01:20:53 +00:00
}
2004-08-21 01:25:48 +00:00
if ( error )
{
return false ;
}
2005-01-29 02:26:42 +00:00
( ( struct sockaddr * ) sadr ) - > sa_family = 0 ;
2004-08-21 01:25:48 +00:00
for ( pos = addrinfo ; pos ; pos = pos - > ai_next )
{
switch ( pos - > ai_family )
{
case AF_INET6 :
if ( ( ( struct sockaddr_in * ) sadr ) - > sin_family = = AF_INET6 )
break ; //first one should be best...
2005-04-17 20:54:43 +00:00
//fallthrough
2004-08-21 01:25:48 +00:00
case AF_INET :
memcpy ( sadr , addrinfo - > ai_addr , addrinfo - > ai_addrlen ) ;
if ( pos - > ai_family = = AF_INET )
goto dblbreak ; //don't try finding any more, this is quake, they probably prefer ip4...
break ;
}
}
dblbreak :
pfreeaddrinfo ( addrinfo ) ;
2005-04-17 20:54:43 +00:00
if ( ! ( ( struct sockaddr * ) sadr ) - > sa_family ) //none suitablefound
2004-08-21 01:25:48 +00:00
return false ;
}
else
# endif
{
( ( struct sockaddr_in * ) sadr ) - > sin_family = AF_INET ;
( ( struct sockaddr_in * ) sadr ) - > sin_port = 0 ;
strcpy ( copy , s ) ;
// strip off a trailing :port if present
for ( colon = copy ; * colon ; colon + + )
if ( * colon = = ' : ' )
{
* colon = 0 ;
( ( struct sockaddr_in * ) sadr ) - > sin_port = htons ( ( short ) atoi ( colon + 1 ) ) ;
}
if ( copy [ 0 ] > = ' 0 ' & & copy [ 0 ] < = ' 9 ' ) //this is the wrong way to test. a server name may start with a number.
{
* ( int * ) & ( ( struct sockaddr_in * ) sadr ) - > sin_addr = inet_addr ( copy ) ;
}
else
{
if ( ! ( h = gethostbyname ( copy ) ) )
return 0 ;
if ( h - > h_addrtype ! = AF_INET )
return 0 ;
* ( int * ) & ( ( struct sockaddr_in * ) sadr ) - > sin_addr = * ( int * ) h - > h_addr_list [ 0 ] ;
}
}
return true ;
}
# undef DO
qboolean NET_StringToAdr ( char * s , netadr_t * a )
{
struct sockaddr_qstorage sadr ;
if ( ! strcmp ( s , " internalserver " ) )
{
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_LOOPBACK ;
return true ;
}
if ( ! NET_StringToSockaddr ( s , & sadr ) )
return false ;
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
SockadrToNetadr ( & sadr , a ) ;
return true ;
}
2005-07-03 15:16:20 +00:00
// Returns true if we can't bind the address locally--in other words,
2004-08-21 01:25:48 +00:00
// the IP is NOT one of our interfaces.
qboolean NET_IsClientLegal ( netadr_t * adr )
{
#if 0
struct sockaddr_in sadr ;
int newsocket ;
if ( adr - > ip [ 0 ] = = 127 )
return false ; // no local connections period
NetadrToSockadr ( adr , & sadr ) ;
if ( ( newsocket = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ) ) = = - 1 )
Sys_Error ( " NET_IsClientLegal: socket: " , strerror ( qerrno ) ) ;
sadr . sin_port = 0 ;
2005-07-03 15:16:20 +00:00
if ( bind ( newsocket , ( void * ) & sadr , sizeof ( sadr ) ) = = - 1 )
2004-08-21 01:25:48 +00:00
{
// It is not a local address
close ( newsocket ) ;
return true ;
}
close ( newsocket ) ;
return false ;
# else
return true ;
# endif
}
qboolean NET_IsLoopBackAddress ( netadr_t adr )
{
// return (!strcmp(cls.servername, NET_AdrToString(net_local_adr)) || !strcmp(cls.servername, "local");
return adr . type = = NA_LOOPBACK ;
}
/////////////////////////////////////////////
//loopback stuff
qboolean NET_GetLoopPacket ( netsrc_t sock , netadr_t * from , sizebuf_t * message )
{
int i ;
loopback_t * loop ;
loop = & loopbacks [ sock ] ;
if ( loop - > send - loop - > get > MAX_LOOPBACK )
loop - > get = loop - > send - MAX_LOOPBACK ;
if ( loop - > get > = loop - > send )
return false ;
i = loop - > get & ( MAX_LOOPBACK - 1 ) ;
loop - > get + + ;
if ( message - > maxsize < loop - > msgs [ i ] . datalen )
Sys_Error ( " NET_SendLoopPacket: Loopback buffer was too big " ) ;
memcpy ( message - > data , loop - > msgs [ i ] . data , loop - > msgs [ i ] . datalen ) ;
message - > cursize = loop - > msgs [ i ] . datalen ;
memset ( from , 0 , sizeof ( * from ) ) ;
from - > type = NA_LOOPBACK ;
2004-12-24 08:45:56 +00:00
message - > packing = SZ_RAWBYTES ;
message - > currentbit = 0 ;
2004-08-21 01:25:48 +00:00
return true ;
}
void NET_SendLoopPacket ( netsrc_t sock , int length , void * data , netadr_t to )
{
int i ;
loopback_t * loop ;
loop = & loopbacks [ sock ^ 1 ] ;
i = loop - > send & ( MAX_LOOPBACK - 1 ) ;
loop - > send + + ;
if ( length > sizeof ( loop - > msgs [ i ] . data ) )
Sys_Error ( " NET_SendLoopPacket: Loopback buffer is too small " ) ;
memcpy ( loop - > msgs [ i ] . data , data , length ) ;
loop - > msgs [ i ] . datalen = length ;
}
//=============================================================================
2006-05-07 05:31:01 +00:00
void SV_Tcpport_Callback ( struct cvar_s * var , char * oldvalue )
{
# ifdef TCPCONNECT
if ( svs . sockettcp = = INVALID_SOCKET & & sv_tcpport . value )
{
svs . sockettcp = TCP_OpenListenSocket ( sv_tcpport . value ) ;
if ( svs . sockettcp ! = INVALID_SOCKET )
NET_GetLocalAddress ( svs . sockettcp , & net_local_sv_tcpipadr ) ;
else
Con_Printf ( " Failed to open TCP port %i \n " , ( int ) sv_tcpport . value ) ;
}
else
{
UDP_CloseSocket ( svs . sockettcp ) ;
svs . sockettcp = INVALID_SOCKET ;
}
# endif
}
2004-08-21 01:25:48 +00:00
qboolean NET_GetPacket ( netsrc_t netsrc )
{
int ret ;
struct sockaddr_qstorage from ;
int fromlen ;
int i ;
int socket ;
2005-05-19 02:40:18 +00:00
int err ;
2004-08-21 01:25:48 +00:00
if ( NET_GetLoopPacket ( netsrc , & net_from , & net_message ) )
return true ;
for ( i = 0 ; i < 3 ; i + + )
{
if ( netsrc = = NS_SERVER )
{
# ifdef CLIENTONLY
Sys_Error ( " NET_GetPacket: Bad netsrc " ) ;
socket = 0 ;
# else
if ( i = = 0 )
socket = svs . socketip ;
else if ( i = = 1 )
socket = svs . socketip6 ;
else
socket = svs . socketipx ;
# endif
}
else
{
# ifdef SERVERONLY
Sys_Error ( " NET_GetPacket: Bad netsrc " ) ;
socket = 0 ;
# else
if ( i = = 0 )
socket = cls . socketip ;
else if ( i = = 1 )
socket = cls . socketip6 ;
else
socket = cls . socketipx ;
# endif
}
2005-05-19 02:40:18 +00:00
if ( socket = = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
continue ;
fromlen = sizeof ( from ) ;
ret = recvfrom ( socket , ( char * ) net_message_buffer , sizeof ( net_message_buffer ) , 0 , ( struct sockaddr * ) & from , & fromlen ) ;
if ( ret = = - 1 )
{
2005-05-19 02:40:18 +00:00
err = qerrno ;
if ( err = = EWOULDBLOCK )
2004-08-21 01:25:48 +00:00
continue ;
2005-05-19 02:40:18 +00:00
if ( err = = EMSGSIZE )
2004-08-21 01:25:48 +00:00
{
SockadrToNetadr ( & from , & net_from ) ;
Con_TPrintf ( TL_OVERSIZEPACKETFROM ,
NET_AdrToString ( net_from ) ) ;
continue ;
}
2005-05-19 02:40:18 +00:00
if ( err = = ECONNABORTED | | err = = ECONNRESET )
2004-08-21 01:25:48 +00:00
{
Con_TPrintf ( TL_CONNECTIONLOSTORABORTED ) ; //server died/connection lost.
# ifndef SERVERONLY
if ( cls . state ! = ca_disconnected & & netsrc = = NS_CLIENT )
{
2004-12-15 19:50:00 +00:00
if ( cls . lastarbiatarypackettime + 5 < Sys_DoubleTime ( ) ) //too many mvdsv
Cbuf_AddText ( " disconnect \n reconnect \n " , RESTRICT_LOCAL ) ; //retry connecting.
else
Con_Printf ( " Packet was not delivered - server might be badly configured \n " ) ;
2004-08-21 01:25:48 +00:00
break ;
}
# endif
continue ;
}
2005-05-19 02:40:18 +00:00
Con_Printf ( " NET_GetPacket: Error (%i): %s \n " , err , strerror ( err ) ) ;
2004-08-21 01:25:48 +00:00
continue ;
}
SockadrToNetadr ( & from , & net_from ) ;
2004-12-24 08:45:56 +00:00
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
2004-08-21 01:25:48 +00:00
net_message . cursize = ret ;
if ( net_message . cursize = = sizeof ( net_message_buffer ) )
{
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( net_from ) ) ;
2005-11-30 01:20:53 +00:00
continue ;
2004-08-21 01:25:48 +00:00
}
return ret ;
}
2005-11-30 01:20:53 +00:00
# ifdef TCPCONNECT
# ifndef SERVERONLY
if ( netsrc = = NS_CLIENT )
{
if ( cls . sockettcp ! = INVALID_SOCKET )
{ //client receiving only via tcp
ret = recv ( cls . sockettcp , cls . tcpinbuffer + cls . tcpinlen , sizeof ( cls . tcpinbuffer ) - cls . tcpinlen , 0 ) ;
if ( ret = = - 1 )
{
err = qerrno ;
if ( err = = EWOULDBLOCK )
ret = 0 ;
else
{
if ( err = = ECONNABORTED | | err = = ECONNRESET )
{
closesocket ( cls . sockettcp ) ;
cls . sockettcp = INVALID_SOCKET ;
Con_TPrintf ( TL_CONNECTIONLOSTORABORTED ) ; //server died/connection lost.
if ( cls . state ! = ca_disconnected )
{
if ( cls . lastarbiatarypackettime + 5 < Sys_DoubleTime ( ) ) //too many mvdsv
Cbuf_AddText ( " disconnect \n reconnect \n " , RESTRICT_LOCAL ) ; //retry connecting.
else
Con_Printf ( " Packet was not delivered - server might be badly configured \n " ) ;
return false ;
}
return false ;
}
closesocket ( cls . sockettcp ) ;
cls . sockettcp = INVALID_SOCKET ;
Con_Printf ( " NET_GetPacket: Error (%i): %s \n " , err , strerror ( err ) ) ;
return false ;
}
}
cls . tcpinlen + = ret ;
if ( cls . tcpinlen < 2 )
return false ;
net_message . cursize = BigShort ( * ( short * ) cls . tcpinbuffer ) ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
{
closesocket ( cls . sockettcp ) ;
cls . sockettcp = INVALID_SOCKET ;
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( net_from ) ) ;
return false ;
}
if ( net_message . cursize + 2 > cls . tcpinlen )
{ //not enough buffered to read a packet out of it.
return false ;
}
memcpy ( net_message_buffer , cls . tcpinbuffer + 2 , net_message . cursize ) ;
memmove ( cls . tcpinbuffer , cls . tcpinbuffer + net_message . cursize + 2 , cls . tcpinlen - ( net_message . cursize + 2 ) ) ;
cls . tcpinlen - = net_message . cursize + 2 ;
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
net_from = cls . sockettcpdest ;
return true ;
}
}
# endif
# ifndef CLIENTONLY
if ( netsrc = = NS_SERVER )
{
float timeval = Sys_DoubleTime ( ) ;
svtcpstream_t * st ;
st = svs . tcpstreams ;
while ( svs . tcpstreams & & svs . tcpstreams - > socketnum = = INVALID_SOCKET )
{
st = svs . tcpstreams ;
svs . tcpstreams = svs . tcpstreams - > next ;
BZ_Free ( st ) ;
}
for ( st = svs . tcpstreams ; st ; st = st - > next )
{ //client receiving only via tcp
while ( st - > next & & st - > next - > socketnum = = INVALID_SOCKET )
{
svtcpstream_t * temp ;
temp = st - > next ;
st - > next = st - > next - > next ;
BZ_Free ( temp ) ;
}
//due to the above checks about invalid sockets, the socket is always open for st below.
if ( st - > timeouttime < timeval )
goto closesvstream ;
ret = recv ( st - > socketnum , st - > inbuffer + st - > inlen , sizeof ( st - > inbuffer ) - st - > inlen , 0 ) ;
if ( ret = = 0 )
goto closesvstream ;
else if ( ret = = - 1 )
{
err = qerrno ;
if ( err = = EWOULDBLOCK )
ret = 0 ;
else
{
if ( err = = ECONNABORTED | | err = = ECONNRESET )
{
Con_TPrintf ( TL_CONNECTIONLOSTORABORTED ) ; //server died/connection lost.
}
else
Con_Printf ( " NET_GetPacket: Error (%i): %s \n " , err , strerror ( err ) ) ;
closesvstream :
closesocket ( st - > socketnum ) ;
st - > socketnum = INVALID_SOCKET ;
continue ;
}
}
st - > inlen + = ret ;
if ( st - > waitingforprotocolconfirmation )
{
if ( st - > inlen < 6 )
continue ;
if ( strncmp ( st - > inbuffer , " qizmo \n " , 6 ) )
{
Con_Printf ( " Unknown TCP client \n " ) ;
goto closesvstream ;
}
memmove ( st - > inbuffer , st - > inbuffer + 6 , st - > inlen - ( 6 ) ) ;
st - > inlen - = 6 ;
st - > waitingforprotocolconfirmation = false ;
}
if ( st - > inlen < 2 )
continue ;
net_message . cursize = BigShort ( * ( short * ) st - > inbuffer ) ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
{
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( net_from ) ) ;
goto closesvstream ;
}
if ( net_message . cursize + 2 > st - > inlen )
{ //not enough buffered to read a packet out of it.
continue ;
}
memcpy ( net_message_buffer , st - > inbuffer + 2 , net_message . cursize ) ;
memmove ( st - > inbuffer , st - > inbuffer + net_message . cursize + 2 , st - > inlen - ( net_message . cursize + 2 ) ) ;
st - > inlen - = net_message . cursize + 2 ;
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
net_from = st - > remoteaddr ;
return true ;
}
if ( svs . sockettcp ! = INVALID_SOCKET )
{
int newsock ;
newsock = accept ( svs . sockettcp , ( struct sockaddr * ) & from , & fromlen ) ;
if ( newsock ! = INVALID_SOCKET )
{
int _true = true ;
setsockopt ( newsock , IPPROTO_TCP , TCP_NODELAY , ( char * ) & _true , sizeof ( _true ) ) ;
st = Z_Malloc ( sizeof ( svtcpstream_t ) ) ;
st - > waitingforprotocolconfirmation = true ;
st - > next = svs . tcpstreams ;
svs . tcpstreams = st ;
st - > socketnum = newsock ;
st - > inlen = 0 ;
SockadrToNetadr ( & from , & st - > remoteaddr ) ;
send ( newsock , " qizmo \n " , 6 , 0 ) ;
st - > timeouttime = timeval + 30 ;
}
}
}
# endif
# endif
2004-08-21 01:25:48 +00:00
return false ;
}
//=============================================================================
void NET_SendPacket ( netsrc_t netsrc , int length , void * data , netadr_t to )
{
int ret ;
struct sockaddr_qstorage addr ;
int socket ;
2005-04-17 20:54:43 +00:00
int size ;
2004-08-21 01:25:48 +00:00
if ( to . type = = NA_LOOPBACK )
{
2005-02-28 07:16:19 +00:00
// if (Cvar_Get("drop", "0", 0, "network debugging")->value)
2004-08-21 01:25:48 +00:00
// if ((rand()&15)==15) //simulate PL
// return;
NET_SendLoopPacket ( netsrc , length , data , to ) ;
return ;
}
if ( netsrc = = NS_SERVER )
{
# ifdef CLIENTONLY
Sys_Error ( " NET_SendPacket: bad netsrc " ) ;
socket = 0 ;
# else
2005-11-30 01:20:53 +00:00
# ifdef TCPCONNECT
svtcpstream_t * st ;
for ( st = svs . tcpstreams ; st ; st = st - > next )
{
if ( st - > socketnum = = INVALID_SOCKET )
continue ;
if ( NET_CompareAdr ( to , st - > remoteaddr ) )
{
unsigned short slen = BigShort ( ( unsigned short ) length ) ;
send ( st - > socketnum , ( char * ) & slen , sizeof ( slen ) , 0 ) ;
send ( st - > socketnum , data , length , 0 ) ;
st - > timeouttime = Sys_DoubleTime ( ) + 20 ;
return ;
}
}
# endif
2004-08-21 01:25:48 +00:00
# ifdef USEIPX
if ( to . type = = NA_BROADCAST_IPX | | to . type = = NA_IPX )
socket = svs . socketipx ;
else
# endif
# ifdef IPPROTO_IPV6
if ( to . type = = NA_IPV6 )
socket = svs . socketip6 ;
else
# endif
socket = svs . socketip ;
# endif
}
else
{
# ifdef SERVERONLY
Sys_Error ( " NET_SendPacket: bad netsrc " ) ;
socket = 0 ;
# else
2005-11-30 01:20:53 +00:00
# ifdef TCPCONNECT
if ( cls . sockettcp ! = - 1 )
{
if ( NET_CompareAdr ( to , cls . sockettcpdest ) )
{ //this goes to the server
//so send it via tcp
unsigned short slen = BigShort ( ( unsigned short ) length ) ;
send ( cls . sockettcp , ( char * ) & slen , sizeof ( slen ) , 0 ) ;
send ( cls . sockettcp , data , length , 0 ) ;
return ;
}
}
# endif
2004-08-21 01:25:48 +00:00
# ifdef USEIPX
if ( to . type = = NA_BROADCAST_IPX | | to . type = = NA_IPX )
socket = cls . socketipx ;
else
# endif
# ifdef IPPROTO_IPV6
if ( to . type = = NA_BROADCAST_IP6 | | to . type = = NA_IPV6 )
socket = cls . socketip6 ;
else
# endif
socket = cls . socketip ;
# endif
}
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
NetadrToSockadr ( & to , & addr ) ;
2005-04-17 20:54:43 +00:00
switch ( to . type )
{
default :
size = 0 ; //should cause an error. :)
break ;
# ifdef USEIPX //who uses ipx nowadays anyway?
case NA_BROADCAST_IPX :
case NA_IPX :
size = sizeof ( struct sockaddr_ipx ) ;
break ;
# endif
case NA_BROADCAST_IP :
case NA_IP :
2005-04-17 20:59:11 +00:00
size = sizeof ( struct sockaddr_in ) ;
2005-04-17 20:54:43 +00:00
break ;
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
2005-04-17 20:59:11 +00:00
size = sizeof ( struct sockaddr_in6 ) ;
2005-04-17 20:54:43 +00:00
break ;
# endif
}
ret = sendto ( socket , data , length , 0 , ( struct sockaddr * ) & addr , size ) ;
2004-08-21 01:25:48 +00:00
if ( ret = = - 1 )
{
// wouldblock is silent
if ( qerrno = = EWOULDBLOCK )
return ;
if ( qerrno = = ECONNREFUSED )
return ;
# ifndef SERVERONLY
if ( qerrno = = EADDRNOTAVAIL )
Con_DPrintf ( " NET_SendPacket Warning: %i \n " , qerrno ) ;
else
# endif
Con_TPrintf ( TL_NETSENDERROR , qerrno ) ;
}
}
//=============================================================================
2005-11-30 01:20:53 +00:00
int TCP_OpenStream ( netadr_t remoteaddr )
{
unsigned long _true = true ;
int newsocket ;
int temp ;
struct sockaddr_qstorage qs ;
temp = NetadrToSockadr ( & remoteaddr , & qs ) ;
2005-12-15 19:15:39 +00:00
2005-11-30 01:20:53 +00:00
if ( ( newsocket = socket ( ( ( struct sockaddr_in * ) & qs ) - > sin_family , SOCK_STREAM , IPPROTO_TCP ) ) = = INVALID_SOCKET )
return INVALID_SOCKET ;
if ( connect ( newsocket , ( struct sockaddr * ) & qs , temp ) = = INVALID_SOCKET )
{
closesocket ( newsocket ) ;
return INVALID_SOCKET ;
}
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " UDP_OpenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
return newsocket ;
}
int TCP_OpenListenSocket ( int port )
{
int newsocket ;
struct sockaddr_in address ;
unsigned long _true = true ;
int i ;
int maxport = port + 100 ;
if ( ( newsocket = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ) ) = = INVALID_SOCKET )
return INVALID_SOCKET ;
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " TCP_OpenListenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
address . sin_family = AF_INET ;
//ZOID -- check for interface binding option
if ( ( i = COM_CheckParm ( " -ip " ) ) ! = 0 & & i < com_argc ) {
address . sin_addr . s_addr = inet_addr ( com_argv [ i + 1 ] ) ;
Con_TPrintf ( TL_NETBINDINTERFACE ,
inet_ntoa ( address . sin_addr ) ) ;
} else
address . sin_addr . s_addr = INADDR_ANY ;
for ( ; ; )
{
if ( port = = PORT_ANY )
address . sin_port = 0 ;
else
address . sin_port = htons ( ( short ) port ) ;
if ( bind ( newsocket , ( void * ) & address , sizeof ( address ) ) = = - 1 )
{
if ( ! port )
{
Con_Printf ( " Cannot bind tcp socket \n " ) ;
closesocket ( newsocket ) ;
return INVALID_SOCKET ;
}
port + + ;
if ( port > maxport )
{
Con_Printf ( " Cannot bind tcp socket \n " ) ;
closesocket ( newsocket ) ;
return INVALID_SOCKET ;
}
}
else
break ;
}
if ( listen ( newsocket , 1 ) = = INVALID_SOCKET )
{
Con_Printf ( " Cannot listen on tcp socket \n " ) ;
closesocket ( newsocket ) ;
return INVALID_SOCKET ;
}
return newsocket ;
}
2004-08-21 01:25:48 +00:00
int UDP_OpenSocket ( int port , qboolean bcast )
{
int newsocket ;
struct sockaddr_in address ;
unsigned long _true = true ;
int i ;
int maxport = port + 100 ;
2005-10-01 03:09:17 +00:00
if ( ( newsocket = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ) ) = = INVALID_SOCKET )
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " UDP_OpenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
if ( bcast )
{
_true = true ;
if ( setsockopt ( newsocket , SOL_SOCKET , SO_BROADCAST , ( char * ) & _true , sizeof ( _true ) ) = = - 1 )
{
Con_Printf ( " Cannot create broadcast socket \n " ) ;
2005-05-19 02:40:18 +00:00
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
}
address . sin_family = AF_INET ;
//ZOID -- check for interface binding option
if ( ( i = COM_CheckParm ( " -ip " ) ) ! = 0 & & i < com_argc ) {
address . sin_addr . s_addr = inet_addr ( com_argv [ i + 1 ] ) ;
Con_TPrintf ( TL_NETBINDINTERFACE ,
inet_ntoa ( address . sin_addr ) ) ;
} else
address . sin_addr . s_addr = INADDR_ANY ;
for ( ; ; )
{
if ( port = = PORT_ANY )
address . sin_port = 0 ;
else
address . sin_port = htons ( ( short ) port ) ;
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
if ( bind ( newsocket , ( void * ) & address , sizeof ( address ) ) = = - 1 )
{
if ( ! port )
Sys_Error ( " UDP_OpenSocket: bind: %s " , strerror ( qerrno ) ) ;
port + + ;
if ( port > maxport )
Sys_Error ( " UDP_OpenSocket: bind: %s " , strerror ( qerrno ) ) ;
}
else
break ;
}
return newsocket ;
}
# ifdef IPPROTO_IPV6
int UDP6_OpenSocket ( int port , qboolean bcast )
{
int newsocket ;
struct sockaddr_in6 address ;
unsigned long _true = true ;
// int i;
int maxport = port + 100 ;
if ( ( newsocket = socket ( PF_INET6 , SOCK_DGRAM , 0 ) ) = = - 1 )
{
Con_Printf ( " IPV6 is not supported: %s \n " , strerror ( qerrno ) ) ;
2005-05-19 02:40:18 +00:00
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " UDP_OpenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
if ( bcast )
{
2005-07-03 15:16:20 +00:00
// address.sin6_addr
2004-08-21 01:25:48 +00:00
// _true = true;
// if (setsockopt(newsocket, SOL_SOCKET, IP_ADD_MEMBERSHIP, (char *)&_true, sizeof(_true)) == -1)
// {
Con_Printf ( " Cannot create broadcast socket \n " ) ;
closesocket ( newsocket ) ;
2005-05-19 02:40:18 +00:00
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
// }
}
address . sin6_family = AF_INET6 ;
//ZOID -- check for interface binding option
// if ((i = COM_CheckParm("-ip6")) != 0 && i < com_argc) {
// address.sin6_addr = inet_addr(com_argv[i+1]);
/// Con_TPrintf(TL_NETBINDINTERFACE,
// inet_ntoa(address.sin6_addr));
// } else
2004-09-04 17:40:49 +00:00
memset ( & address . sin6_addr , 0 , sizeof ( struct in6_addr ) ) ;
2004-08-21 01:25:48 +00:00
for ( ; ; )
{
if ( port = = PORT_ANY )
address . sin6_port = 0 ;
else
address . sin6_port = htons ( ( short ) port ) ;
if ( bind ( newsocket , ( void * ) & address , sizeof ( address ) ) = = - 1 )
{
if ( ! port )
Sys_Error ( " UDP6_OpenSocket: bind: %s " , strerror ( qerrno ) ) ;
port + + ;
if ( port > maxport )
Sys_Error ( " UDP6_OpenSocket: bind: %s " , strerror ( qerrno ) ) ;
}
else
break ;
}
return newsocket ;
}
# endif
void UDP_CloseSocket ( int socket )
{
closesocket ( socket ) ;
}
int IPX_OpenSocket ( int port , qboolean bcast )
{
# ifndef USEIPX
return 0 ;
# else
int newsocket ;
struct sockaddr_ipx address ;
u_long _true = 1 ;
if ( ( newsocket = socket ( PF_IPX , SOCK_DGRAM , NSPROTO_IPX ) ) = = - 1 )
{
if ( qerrno ! = EAFNOSUPPORT )
2005-10-07 16:27:20 +00:00
Con_Printf ( " WARNING: IPX_Socket: socket: %i \n " , qerrno ) ;
2005-05-19 02:40:18 +00:00
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
// make it non-blocking
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
{
2005-10-07 16:27:20 +00:00
Con_Printf ( " WARNING: IPX_Socket: ioctl FIONBIO: %i \n " , qerrno ) ;
2005-05-19 02:40:18 +00:00
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
if ( bcast )
{
// make it broadcast capable
if ( setsockopt ( newsocket , SOL_SOCKET , SO_BROADCAST , ( char * ) & _true , sizeof ( _true ) ) = = - 1 )
{
2005-10-07 16:27:20 +00:00
Con_Printf ( " WARNING: IPX_Socket: setsockopt SO_BROADCAST: %i \n " , qerrno ) ;
2005-05-19 02:40:18 +00:00
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
}
address . sa_family = AF_IPX ;
memset ( address . sa_netnum , 0 , 4 ) ;
memset ( address . sa_nodenum , 0 , 6 ) ;
if ( port = = PORT_ANY )
address . sa_socket = 0 ;
else
address . sa_socket = htons ( ( short ) port ) ;
if ( bind ( newsocket , ( void * ) & address , sizeof ( address ) ) = = - 1 )
{
Con_Printf ( " WARNING: IPX_Socket: bind: %i \n " , qerrno ) ;
closesocket ( newsocket ) ;
2005-05-19 02:40:18 +00:00
return INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
return newsocket ;
# endif
}
void IPX_CloseSocket ( int socket )
{
# ifdef USEIPX
closesocket ( socket ) ;
# endif
}
// sleeps msec or until net socket is ready
//stdin can sometimes be a socket. As a result,
//we give the option to select it for nice console imput with timeouts.
2004-11-29 01:21:00 +00:00
# ifndef CLIENTONLY
2004-08-21 01:25:48 +00:00
qboolean NET_Sleep ( int msec , qboolean stdinissocket )
{
struct timeval timeout ;
fd_set fdset ;
int i ;
FD_ZERO ( & fdset ) ;
if ( stdinissocket )
2005-04-17 20:54:43 +00:00
FD_SET ( 0 , & fdset ) ; //stdin tends to be socket 0
2004-08-21 01:25:48 +00:00
i = 0 ;
2005-04-17 20:54:43 +00:00
if ( svs . socketip ! = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
FD_SET ( svs . socketip , & fdset ) ; // network socket
i = svs . socketip ;
}
2005-05-19 02:40:18 +00:00
# ifdef IPPROTO_IPV6
2005-04-17 20:54:43 +00:00
if ( svs . socketip6 ! = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
FD_SET ( svs . socketip6 , & fdset ) ; // network socket
if ( svs . socketip6 > i )
i = svs . socketip6 ;
i = svs . socketip6 ;
}
2005-05-19 02:40:18 +00:00
# endif
2004-08-21 01:25:48 +00:00
# ifdef USEIPX
2005-04-17 20:54:43 +00:00
if ( svs . socketipx ! = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
FD_SET ( svs . socketipx , & fdset ) ; // network socket
if ( svs . socketipx > i )
i = svs . socketipx ;
}
# endif
timeout . tv_sec = msec / 1000 ;
timeout . tv_usec = ( msec % 1000 ) * 1000 ;
select ( i + 1 , & fdset , NULL , NULL , & timeout ) ;
if ( stdinissocket )
return FD_ISSET ( 0 , & fdset ) ;
return true ;
}
2004-11-29 01:21:00 +00:00
# endif
2004-08-21 01:25:48 +00:00
2005-05-26 12:55:34 +00:00
void NET_GetLocalAddress ( int socket , netadr_t * out )
2004-08-21 01:25:48 +00:00
{
char buff [ 512 ] ;
struct sockaddr_qstorage address ;
int namelen ;
2006-01-27 08:06:48 +00:00
netadr_t adr = { 0 } ;
2005-10-07 16:27:20 +00:00
qboolean notvalid = false ;
2004-08-21 01:25:48 +00:00
2005-10-07 16:27:20 +00:00
strcpy ( buff , " localhost " ) ;
2004-08-21 01:25:48 +00:00
gethostname ( buff , 512 ) ;
buff [ 512 - 1 ] = 0 ;
2005-10-07 16:27:20 +00:00
if ( ! NET_StringToAdr ( buff , & adr ) ) //urm
NET_StringToAdr ( " 127.0.0.1 " , & adr ) ;
2004-08-21 01:25:48 +00:00
namelen = sizeof ( address ) ;
if ( getsockname ( socket , ( struct sockaddr * ) & address , & namelen ) = = - 1 )
2005-10-07 16:27:20 +00:00
{
notvalid = true ;
NET_StringToSockaddr ( " 0.0.0.0 " , ( struct sockaddr_qstorage * ) & address ) ;
// Sys_Error ("NET_Init: getsockname:", strerror(qerrno));
}
2004-08-21 01:25:48 +00:00
2005-05-26 12:55:34 +00:00
SockadrToNetadr ( & address , out ) ;
2006-02-17 02:51:59 +00:00
if ( ! * ( int * ) out - > address . ip ) //socket was set to auto
* ( int * ) out - > address . ip = * ( int * ) adr . address . ip ; //change it to what the machine says it is, rather than the socket.
2004-08-21 01:25:48 +00:00
2005-10-07 16:27:20 +00:00
if ( notvalid )
Con_Printf ( " Couldn't detect local ip \n " ) ;
else
Con_TPrintf ( TL_IPADDRESSIS , NET_AdrToString ( * out ) ) ;
2004-08-21 01:25:48 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = =
NET_Init
= = = = = = = = = = = = = = = = = = = =
*/
void NET_Init ( void )
{
# ifdef _WIN32
2005-07-03 15:16:20 +00:00
WORD wVersionRequested ;
2004-08-21 01:25:48 +00:00
int r ;
# ifdef IPPROTO_IPV6
HMODULE ws2_32dll ;
ws2_32dll = LoadLibrary ( " ws2_32.dll " ) ;
if ( ws2_32dll )
{
pfreeaddrinfo = ( void * ) GetProcAddress ( ws2_32dll , " freeaddrinfo " ) ;
pgetaddrinfo = ( void * ) GetProcAddress ( ws2_32dll , " getaddrinfo " ) ;
if ( ! pgetaddrinfo | | ! pfreeaddrinfo )
{
pgetaddrinfo = NULL ;
pfreeaddrinfo = NULL ;
FreeLibrary ( ws2_32dll ) ;
}
}
else
pgetaddrinfo = NULL ;
# endif
2005-07-03 15:16:20 +00:00
wVersionRequested = MAKEWORD ( 1 , 1 ) ;
2004-08-21 01:25:48 +00:00
r = WSAStartup ( MAKEWORD ( 1 , 1 ) , & winsockdata ) ;
if ( r )
Sys_Error ( " Winsock initialization failed. " ) ;
# endif
2005-11-29 13:32:15 +00:00
2004-08-21 01:25:48 +00:00
Con_TPrintf ( TL_UDPINITED ) ;
2005-04-17 20:54:43 +00:00
# ifndef SERVERONLY
cls . socketip = INVALID_SOCKET ;
cls . socketip6 = INVALID_SOCKET ;
cls . socketipx = INVALID_SOCKET ;
2005-11-30 01:20:53 +00:00
# ifdef TCPCONNECT
cls . sockettcp = INVALID_SOCKET ;
# endif
2005-04-17 20:54:43 +00:00
# endif
# ifndef CLIENTONLY
svs . socketip = INVALID_SOCKET ;
svs . socketip6 = INVALID_SOCKET ;
svs . socketipx = INVALID_SOCKET ;
2005-11-30 01:20:53 +00:00
# ifdef TCPCONNECT
svs . sockettcp = INVALID_SOCKET ;
# endif
2005-04-17 20:54:43 +00:00
# endif
2004-08-21 01:25:48 +00:00
}
# ifndef SERVERONLY
void NET_InitClient ( void )
{
int port ;
int p ;
port = PORT_CLIENT ;
2005-11-30 01:20:53 +00:00
2004-08-21 01:25:48 +00:00
p = COM_CheckParm ( " -port " ) ;
if ( p & & p < com_argc )
{
port = atoi ( com_argv [ p + 1 ] ) ;
}
2005-11-30 01:20:53 +00:00
p = COM_CheckParm ( " -clport " ) ;
if ( p & & p < com_argc )
{
port = atoi ( com_argv [ p + 1 ] ) ;
}
2004-08-21 01:25:48 +00:00
//
// open the single socket to be used for all communications
//
cls . socketip = UDP_OpenSocket ( port , false ) ;
# ifdef IPPROTO_IPV6
cls . socketip6 = UDP6_OpenSocket ( port , false ) ;
# endif
# ifdef USEIPX
cls . socketipx = IPX_OpenSocket ( port , false ) ;
# endif
//
// init the message buffer
//
net_message . maxsize = sizeof ( net_message_buffer ) ;
net_message . data = net_message_buffer ;
//
// determine my name & address
//
2005-05-26 12:55:34 +00:00
NET_GetLocalAddress ( cls . socketip , & net_local_cl_ipadr ) ;
2004-08-21 01:25:48 +00:00
Con_TPrintf ( TL_CLIENTPORTINITED ) ;
}
# endif
# ifndef CLIENTONLY
void NET_CloseServer ( void )
{
2005-04-17 20:54:43 +00:00
if ( svs . socketip ! = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
UDP_CloseSocket ( svs . socketip ) ;
2005-04-17 20:54:43 +00:00
svs . socketip = INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
2005-05-19 02:40:18 +00:00
# ifdef IPPROTO_IPV6
2005-04-17 20:54:43 +00:00
if ( svs . socketip6 ! = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
2005-05-19 02:40:18 +00:00
UDP_CloseSocket ( svs . socketip6 ) ;
svs . socketip6 = INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
2005-05-19 02:40:18 +00:00
# endif
2004-08-21 01:25:48 +00:00
# ifdef USEIPX
2005-04-17 20:54:43 +00:00
if ( svs . socketipx ! = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
IPX_CloseSocket ( svs . socketipx ) ;
2005-04-17 20:54:43 +00:00
svs . socketipx = INVALID_SOCKET ;
2004-08-21 01:25:48 +00:00
}
# endif
2005-11-30 01:20:53 +00:00
# ifdef TCPCONNECT
if ( svs . sockettcp ! = INVALID_SOCKET )
{
2006-05-07 05:31:01 +00:00
UDP_CloseSocket ( svs . sockettcp ) ;
2005-11-30 01:20:53 +00:00
svs . sockettcp = INVALID_SOCKET ;
}
# endif
2004-08-21 01:25:48 +00:00
2005-05-26 12:55:34 +00:00
net_local_sv_ipadr . type = NA_LOOPBACK ;
net_local_sv_ip6adr . type = NA_LOOPBACK ;
net_local_sv_ipxadr . type = NA_LOOPBACK ;
2004-08-21 01:25:48 +00:00
}
void NET_InitServer ( void )
{
int port ;
int p ;
port = PORT_SERVER ;
2005-06-04 04:20:20 +00:00
if ( sv_listen . value )
2004-08-21 01:25:48 +00:00
{
2005-11-30 01:20:53 +00:00
p = COM_CheckParm ( " -port " ) ;
2004-08-21 01:25:48 +00:00
if ( p & & p < com_argc )
{
port = atoi ( com_argv [ p + 1 ] ) ;
}
2005-11-30 01:20:53 +00:00
p = COM_CheckParm ( " -svport " ) ;
2004-08-21 01:25:48 +00:00
if ( p & & p < com_argc )
{
port = atoi ( com_argv [ p + 1 ] ) ;
}
//
// open the single socket to be used for all communications
//
2005-04-17 20:54:43 +00:00
if ( svs . socketip = = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
svs . socketip = UDP_OpenSocket ( port , false ) ;
2005-05-26 12:55:34 +00:00
if ( svs . socketip ! = INVALID_SOCKET )
NET_GetLocalAddress ( svs . socketip , & net_local_sv_ipadr ) ;
2004-08-21 01:25:48 +00:00
}
# ifdef IPPROTO_IPV6
2005-04-17 20:54:43 +00:00
if ( svs . socketip6 = = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
svs . socketip6 = UDP6_OpenSocket ( port , false ) ;
2005-05-19 02:40:18 +00:00
if ( svs . socketip6 ! = INVALID_SOCKET )
2005-05-26 12:55:34 +00:00
NET_GetLocalAddress ( svs . socketip6 , & net_local_sv_ip6adr ) ;
2004-08-21 01:25:48 +00:00
}
# endif
# ifdef USEIPX
2005-04-17 20:54:43 +00:00
if ( svs . socketipx = = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
svs . socketipx = IPX_OpenSocket ( port , false ) ;
2005-05-26 12:55:34 +00:00
if ( svs . socketipx ! = INVALID_SOCKET )
NET_GetLocalAddress ( svs . socketipx , & net_local_sv_ipxadr ) ;
2004-08-21 01:25:48 +00:00
}
# endif
2006-05-07 05:31:01 +00:00
# ifdef TCPCONNECT
Cvar_ForceCallback ( & sv_tcpport ) ;
# endif
2004-08-21 01:25:48 +00:00
}
else
NET_CloseServer ( ) ;
2006-05-07 05:31:01 +00:00
2004-08-21 01:25:48 +00:00
//
// init the message buffer
//
net_message . maxsize = sizeof ( net_message_buffer ) ;
net_message . data = net_message_buffer ;
}
# endif
/*
= = = = = = = = = = = = = = = = = = = =
NET_Shutdown
= = = = = = = = = = = = = = = = = = = =
*/
void NET_Shutdown ( void )
{
# ifndef CLIENTONLY
NET_CloseServer ( ) ;
# endif
# ifndef SERVERONLY
UDP_CloseSocket ( cls . socketip ) ;
2005-05-19 02:40:18 +00:00
# ifdef IPPROTO_IPV6
2004-08-21 01:25:48 +00:00
UDP_CloseSocket ( cls . socketip6 ) ;
2005-05-19 02:40:18 +00:00
# endif
2004-08-21 01:25:48 +00:00
# ifdef USEIPX
IPX_CloseSocket ( cls . socketipx ) ;
# endif
# endif
# ifdef _WIN32
# ifdef SERVERTONLY
if ( ! serverthreadID ) //running as subsystem of client. Don't close all of it's sockets too.
# endif
WSACleanup ( ) ;
# endif
}
2006-03-14 01:25:46 +00:00
typedef struct {
vfsfile_t funcs ;
int sock ;
char readbuffer [ 65536 ] ;
int readbuffered ;
} tcpfile_t ;
void VFSTCP_Error ( tcpfile_t * f )
{
if ( f - > sock ! = INVALID_SOCKET )
{
closesocket ( f - > sock ) ;
f - > sock = INVALID_SOCKET ;
}
}
int VFSTCP_ReadBytes ( struct vfsfile_s * file , void * buffer , int bytestoread )
{
tcpfile_t * tf = ( tcpfile_t * ) file ;
int len ;
if ( tf - > sock ! = INVALID_SOCKET )
{
len = recv ( tf - > sock , tf - > readbuffer + tf - > readbuffered , sizeof ( tf - > readbuffer ) - tf - > readbuffered , 0 ) ;
if ( len = = - 1 )
{
//fixme: figure out wouldblock or error
}
else if ( len = = 0 )
VFSTCP_Error ( tf ) ;
else
tf - > readbuffered + = len ;
}
if ( bytestoread < = tf - > readbuffered )
{
memcpy ( buffer , tf - > readbuffer , bytestoread ) ;
tf - > readbuffered - = bytestoread ;
memmove ( tf - > readbuffer , tf - > readbuffer + bytestoread , tf - > readbuffered ) ;
return bytestoread ;
}
else
return 0 ;
}
int VFSTCP_WriteBytes ( struct vfsfile_s * file , void * buffer , int bytestoread )
{
tcpfile_t * tf = ( tcpfile_t * ) file ;
int len ;
if ( tf - > sock = = INVALID_SOCKET )
return 0 ;
len = send ( tf - > sock , buffer , bytestoread , 0 ) ;
if ( len = = - 1 | | len = = 0 )
{
VFSTCP_Error ( tf ) ;
return 0 ;
}
return len ;
}
qboolean VFSTCP_Seek ( struct vfsfile_s * file , unsigned long pos )
{
VFSTCP_Error ( ( tcpfile_t * ) file ) ;
return false ;
}
unsigned long VFSTCP_Tell ( struct vfsfile_s * file )
{
VFSTCP_Error ( ( tcpfile_t * ) file ) ;
return 0 ;
}
unsigned long VFSTCP_GetLen ( struct vfsfile_s * file )
{
return 0 ;
}
void VFSTCP_Close ( struct vfsfile_s * file )
{
VFSTCP_Error ( ( tcpfile_t * ) file ) ;
Z_Free ( file ) ;
}
vfsfile_t * FS_OpenTCP ( char * name )
{
tcpfile_t * newf ;
int sock ;
2006-03-23 19:22:12 +00:00
netadr_t adr = { 0 } ;
if ( NET_StringToAdr ( name , & adr ) )
{
sock = TCP_OpenStream ( adr ) ;
if ( sock = = INVALID_SOCKET )
return NULL ;
newf = Z_Malloc ( sizeof ( * newf ) ) ;
newf - > sock = sock ;
newf - > funcs . Close = VFSTCP_Close ;
newf - > funcs . Flush = NULL ;
newf - > funcs . GetLen = VFSTCP_GetLen ;
newf - > funcs . ReadBytes = VFSTCP_ReadBytes ;
newf - > funcs . Seek = VFSTCP_Seek ;
newf - > funcs . Tell = VFSTCP_Tell ;
newf - > funcs . WriteBytes = VFSTCP_WriteBytes ;
newf - > funcs . seekingisabadplan = true ;
return & newf - > funcs ;
}
else
2006-03-14 01:25:46 +00:00
return NULL ;
}