2010-02-15 23:26:55 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2007 - 2008 Kristian Duske
2014-09-22 08:55:46 +00:00
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
2010-02-15 23:26:55 +00:00
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
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 this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2010-08-14 20:55:39 +00:00
# include "q_stdinc.h"
* Makefile, Makefile.darwin, Makefile.w32, Makefile.w64: Build changes:
The SDL_net driver is now disabled by default and platform-specific network
drivers will be used. To compile for SDL_net, a command like "make SDLNET=1"
must be used, in which case a new preprocessor macro _USE_SDLNET will be
defined in the CFLAGS. For windows targets when not using SDL_net, WINSOCK2
is added as another option: A command line like "make WINSOCK2=1" will enable
WinSock2 api and a new preprocessor macro _USE_WINSOCK2 will be defined in
the CFLAGS. Or, a command line like "make WINSOCK2=0" will disable WinSock2
api and the old WinSock 1.1 api will be used instead. For Win64, WinSock2 is
enabled by default. For Win32, WinSock 1.1 is the default api.
* net_bsd.c, net_dgrm.c, net_loop.c, net_main.c, net_sdl.c, net_sdlnet.c,
net_udp.c, net_win.c, net_wins.c, net_wipx.c: Use the newly added net_sys.h
header. The sys_socket_t type is not in use, yet.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@215 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-06-21 11:10:38 +00:00
# include "arch_def.h"
# include "net_sys.h"
2010-02-15 23:26:55 +00:00
# include "quakedef.h"
2010-06-20 17:21:10 +00:00
# include "net_defs.h"
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
static sys_socket_t net_acceptsocket4 = INVALID_SOCKET ; // socket for fielding new connections
static sys_socket_t net_controlsocket4 ;
static sys_socket_t net_broadcastsocket4 = INVALID_SOCKET ;
static struct sockaddr_in broadcastaddr4 ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
static in_addr_t myAddr4 ;
static sys_socket_t net_acceptsocket6 = INVALID_SOCKET ; // socket for fielding new connections
static sys_socket_t net_controlsocket6 ;
static struct in6_addr myAddrv6 ;
2010-02-15 23:26:55 +00:00
# include "net_udp.h"
//=============================================================================
2017-09-17 02:12:53 +00:00
sys_socket_t UDP4_Init ( void )
2010-02-15 23:26:55 +00:00
{
2023-03-18 12:38:25 +00:00
int i ;
2018-04-20 14:35:32 +00:00
char * tst ;
2010-06-21 15:24:40 +00:00
struct qsockaddr addr ;
2017-09-17 02:12:53 +00:00
if ( COM_CheckParm ( " -noudp " ) | | COM_CheckParm ( " -noudp4 " ) )
2010-06-21 15:24:40 +00:00
return INVALID_SOCKET ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
myAddr4 = htonl ( INADDR_LOOPBACK ) ;
2023-03-18 12:38:25 +00:00
i = COM_CheckParm ( " -ip " ) ;
if ( i )
2010-06-19 16:37:28 +00:00
{
2023-03-18 12:38:25 +00:00
if ( i < com_argc - 1 )
2017-04-26 01:38:38 +00:00
{
2023-03-18 12:38:25 +00:00
myAddr4 = inet_addr ( com_argv [ i + 1 ] ) ;
if ( myAddr4 = = INADDR_NONE )
Sys_Error ( " %s is not a valid IP address " , com_argv [ i + 1 ] ) ;
2017-04-26 01:38:38 +00:00
}
2018-04-20 14:35:32 +00:00
else
2010-06-21 15:24:40 +00:00
{
2023-03-18 12:38:25 +00:00
Sys_Error ( " UDP4_Init: you must specify an IP address after -ip " ) ;
2010-06-21 15:24:40 +00:00
}
2023-03-18 12:38:25 +00:00
}
else
{
2020-07-02 19:05:51 +00:00
# ifdef __linux__
2023-03-18 12:38:25 +00:00
//gethostbyname(gethostname()) is only supported if the hostname can be looked up on an actual name server
//this means its usable as a test to see if other hosts can see it, but means we cannot use it to find out the local address.
//it also means stalls and slow loading and other undesirable behaviour, so lets stop doing this legacy junk.
//we probably have multiple interfaces nowadays anyway (wan and lan and wifi and localhost and linklocal addresses and zomgwtf).
2020-07-02 19:05:51 +00:00
# else
// determine my name & address
int err ;
char buff [ MAXHOSTNAMELEN ] ;
struct hostent * local ;
if ( gethostname ( buff , MAXHOSTNAMELEN ) ! = 0 )
2017-04-26 01:38:38 +00:00
{
2020-07-02 19:05:51 +00:00
err = SOCKETERRNO ;
2022-04-27 21:32:40 +00:00
Con_SafePrintf ( " UDP4_Init: WARNING: gethostname failed (%s) \n " ,
2020-07-02 19:05:51 +00:00
socketerror ( err ) ) ;
2017-04-26 01:38:38 +00:00
}
2018-04-20 14:35:32 +00:00
else
2010-06-21 15:24:40 +00:00
{
2020-07-02 19:05:51 +00:00
buff [ MAXHOSTNAMELEN - 1 ] = 0 ;
# ifdef PLATFORM_OSX
// ericw -- if our hostname ends in ".local" (a macOS thing),
// don't bother calling gethostbyname(), because it blocks for a few seconds
// and then fails (on my system anyway.)
tst = strstr ( buff , " .local " ) ;
if ( tst & & tst [ 6 ] = = ' \0 ' )
{
Con_SafePrintf ( " UDP_Init: skipping gethostbyname for %s \n " , buff ) ;
}
else
# endif
if ( ! ( local = gethostbyname ( buff ) ) )
{
2022-04-27 21:32:40 +00:00
Con_SafePrintf ( " UDP4_Init: WARNING: gethostbyname failed (%s) \n " ,
2020-07-02 19:05:51 +00:00
hstrerror ( h_errno ) ) ;
}
else if ( local - > h_addrtype ! = AF_INET )
{
Con_SafePrintf ( " UDP4_Init: address from gethostbyname not IPv4 \n " ) ;
}
else
myAddr4 = * ( in_addr_t * ) local - > h_addr_list [ 0 ] ;
2023-07-10 02:02:16 +00:00
}
2020-07-02 19:05:51 +00:00
# endif
2010-06-19 16:37:28 +00:00
}
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
if ( ( net_controlsocket4 = UDP4_OpenSocket ( 0 ) ) = = INVALID_SOCKET )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
Con_SafePrintf ( " UDP4_Init: Unable to open control socket, UDP disabled \n " ) ;
2010-06-21 15:24:40 +00:00
return INVALID_SOCKET ;
2010-02-15 23:26:55 +00:00
}
2017-09-17 02:12:53 +00:00
broadcastaddr4 . sin_family = AF_INET ;
broadcastaddr4 . sin_addr . s_addr = INADDR_BROADCAST ;
broadcastaddr4 . sin_port = htons ( ( unsigned short ) net_hostport ) ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
UDP_GetSocketAddr ( net_controlsocket4 , & addr ) ;
strcpy ( my_ipv4_address , UDP_AddrToString ( & addr , false ) ) ;
tst = strrchr ( my_ipv4_address , ' : ' ) ;
2018-04-20 14:35:32 +00:00
if ( tst ) * tst = 0 ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
Con_SafePrintf ( " UDP4 Initialized \n " ) ;
ipv4Available = true ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
return net_controlsocket4 ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
2017-09-17 02:12:53 +00:00
void UDP4_Shutdown ( void )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
UDP4_Listen ( false ) ;
UDP_CloseSocket ( net_controlsocket4 ) ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
2017-09-17 02:12:53 +00:00
sys_socket_t UDP4_Listen ( qboolean state )
2010-02-15 23:26:55 +00:00
{
if ( state )
{
2017-09-17 02:12:53 +00:00
// enable listening
if ( net_acceptsocket4 = = INVALID_SOCKET )
{
if ( ( net_acceptsocket4 = UDP4_OpenSocket ( net_hostport ) ) = = INVALID_SOCKET )
Sys_Error ( " UDP4_Listen: Unable to open accept socket " ) ;
}
2010-02-15 23:26:55 +00:00
}
2017-09-17 02:12:53 +00:00
else
{
// disable listening
if ( net_acceptsocket4 ! = INVALID_SOCKET )
{
UDP_CloseSocket ( net_acceptsocket4 ) ;
net_acceptsocket4 = INVALID_SOCKET ;
}
}
return net_acceptsocket4 ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
2017-09-17 02:12:53 +00:00
sys_socket_t UDP4_OpenSocket ( int port )
2010-02-15 23:26:55 +00:00
{
2010-06-21 15:24:40 +00:00
sys_socket_t newsocket ;
2010-02-15 23:26:55 +00:00
struct sockaddr_in address ;
2010-06-19 18:20:22 +00:00
int _true = 1 ;
2010-06-22 18:11:00 +00:00
int err ;
2010-02-15 23:26:55 +00:00
2010-06-21 15:24:40 +00:00
if ( ( newsocket = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ) ) = = INVALID_SOCKET )
2010-06-22 18:11:00 +00:00
{
err = SOCKETERRNO ;
2017-09-17 02:12:53 +00:00
Con_SafePrintf ( " UDP4_OpenSocket: %s \n " , socketerror ( err ) ) ;
2010-06-21 15:24:40 +00:00
return INVALID_SOCKET ;
2010-06-22 18:11:00 +00:00
}
2010-02-15 23:26:55 +00:00
2010-06-21 15:24:40 +00:00
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = SOCKET_ERROR )
2010-02-15 23:26:55 +00:00
goto ErrorReturn ;
2010-06-21 15:24:40 +00:00
memset ( & address , 0 , sizeof ( struct sockaddr_in ) ) ;
2010-02-15 23:26:55 +00:00
address . sin_family = AF_INET ;
address . sin_addr . s_addr = INADDR_ANY ;
2010-06-21 15:24:40 +00:00
address . sin_port = htons ( ( unsigned short ) port ) ;
if ( bind ( newsocket , ( struct sockaddr * ) & address , sizeof ( address ) ) = = 0 )
return newsocket ;
2010-02-15 23:26:55 +00:00
ErrorReturn :
2010-06-22 18:11:00 +00:00
err = SOCKETERRNO ;
2017-09-17 02:12:53 +00:00
Con_SafePrintf ( " UDP4_OpenSocket: %s \n " , socketerror ( err ) ) ;
2010-06-21 15:24:40 +00:00
UDP_CloseSocket ( newsocket ) ;
return INVALID_SOCKET ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
2010-06-21 15:24:40 +00:00
int UDP_CloseSocket ( sys_socket_t socketid )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
if ( socketid = = net_broadcastsocket4 )
net_broadcastsocket4 = INVALID_SOCKET ;
2010-06-21 15:24:40 +00:00
return closesocket ( socketid ) ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
2010-06-21 15:24:40 +00:00
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = =
PartialIPAddress
this lets you type only as much of the net address as required , using
the local network components to fill in the rest
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
static int PartialIPAddress ( const char * in , struct qsockaddr * hostaddr )
2010-02-15 23:26:55 +00:00
{
2010-06-20 10:03:05 +00:00
char buff [ 256 ] ;
char * b ;
int addr , mask , num , port , run ;
2010-02-15 23:26:55 +00:00
buff [ 0 ] = ' . ' ;
b = buff ;
strcpy ( buff + 1 , in ) ;
if ( buff [ 1 ] = = ' . ' )
b + + ;
addr = 0 ;
2010-06-20 10:03:05 +00:00
mask = - 1 ;
2010-02-15 23:26:55 +00:00
while ( * b = = ' . ' )
{
b + + ;
num = 0 ;
run = 0 ;
while ( ! ( * b < ' 0 ' | | * b > ' 9 ' ) )
{
2010-06-20 10:03:05 +00:00
num = num * 10 + * b + + - ' 0 ' ;
if ( + + run > 3 )
return - 1 ;
2010-02-15 23:26:55 +00:00
}
if ( ( * b < ' 0 ' | | * b > ' 9 ' ) & & * b ! = ' . ' & & * b ! = ' : ' & & * b ! = 0 )
return - 1 ;
if ( num < 0 | | num > 255 )
return - 1 ;
2010-06-20 10:03:05 +00:00
mask < < = 8 ;
2010-02-15 23:26:55 +00:00
addr = ( addr < < 8 ) + num ;
}
2010-06-20 10:03:05 +00:00
2010-02-15 23:26:55 +00:00
if ( * b + + = = ' : ' )
2011-06-27 13:10:19 +00:00
port = atoi ( b ) ;
2010-02-15 23:26:55 +00:00
else
port = net_hostport ;
2010-06-21 09:20:32 +00:00
hostaddr - > qsa_family = AF_INET ;
2010-06-20 10:03:05 +00:00
( ( struct sockaddr_in * ) hostaddr ) - > sin_port = htons ( ( unsigned short ) port ) ;
( ( struct sockaddr_in * ) hostaddr ) - > sin_addr . s_addr =
2017-09-17 02:12:53 +00:00
( myAddr4 & htonl ( mask ) ) | htonl ( addr ) ;
2010-06-20 10:03:05 +00:00
2010-02-15 23:26:55 +00:00
return 0 ;
}
2011-06-27 13:10:19 +00:00
2010-02-15 23:26:55 +00:00
//=============================================================================
2010-06-21 15:24:40 +00:00
int UDP_Connect ( sys_socket_t socketid , struct qsockaddr * addr )
2010-02-15 23:26:55 +00:00
{
return 0 ;
}
//=============================================================================
2017-09-17 02:12:53 +00:00
sys_socket_t UDP4_CheckNewConnections ( void )
2010-02-15 23:26:55 +00:00
{
2011-11-12 18:03:49 +00:00
int available ;
2010-06-19 16:37:28 +00:00
struct sockaddr_in from ;
socklen_t fromlen ;
char buff [ 1 ] ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
if ( net_acceptsocket4 = = INVALID_SOCKET )
2010-06-21 15:24:40 +00:00
return INVALID_SOCKET ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
if ( ioctl ( net_acceptsocket4 , FIONREAD , & available ) = = - 1 )
2010-06-21 15:24:40 +00:00
{
2010-06-22 18:11:00 +00:00
int err = SOCKETERRNO ;
Sys_Error ( " UDP: ioctlsocket (FIONREAD) failed (%s) " , socketerror ( err ) ) ;
2010-06-21 15:24:40 +00:00
}
2010-02-15 23:26:55 +00:00
if ( available )
2017-09-17 02:12:53 +00:00
return net_acceptsocket4 ;
2010-06-19 16:37:28 +00:00
// quietly absorb empty packets
2017-09-17 02:12:53 +00:00
recvfrom ( net_acceptsocket4 , buff , 0 , 0 , ( struct sockaddr * ) & from , & fromlen ) ;
2010-06-21 15:24:40 +00:00
return INVALID_SOCKET ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
2010-06-21 15:24:40 +00:00
int UDP_Read ( sys_socket_t socketid , byte * buf , int len , struct qsockaddr * addr )
2010-02-15 23:26:55 +00:00
{
2010-06-21 16:23:06 +00:00
socklen_t addrlen = sizeof ( struct qsockaddr ) ;
2010-06-19 17:04:04 +00:00
int ret ;
2010-02-15 23:26:55 +00:00
2010-06-21 16:23:06 +00:00
ret = recvfrom ( socketid , buf , len , 0 , ( struct sockaddr * ) addr , & addrlen ) ;
2010-06-21 15:24:40 +00:00
if ( ret = = SOCKET_ERROR )
{
int err = SOCKETERRNO ;
2011-01-12 20:10:34 +00:00
if ( err = = NET_EWOULDBLOCK | | err = = NET_ECONNREFUSED )
2010-06-21 15:24:40 +00:00
return 0 ;
2010-06-22 18:11:00 +00:00
Con_SafePrintf ( " UDP_Read, recvfrom: %s \n " , socketerror ( err ) ) ;
2010-06-21 15:24:40 +00:00
}
2010-02-15 23:26:55 +00:00
return ret ;
}
//=============================================================================
2017-09-17 02:12:53 +00:00
static int UDP4_MakeSocketBroadcastCapable ( sys_socket_t socketid )
2010-02-15 23:26:55 +00:00
{
2010-06-20 10:03:05 +00:00
int i = 1 ;
2010-02-15 23:26:55 +00:00
// make this socket broadcast capable
2010-06-21 15:24:40 +00:00
if ( setsockopt ( socketid , SOL_SOCKET , SO_BROADCAST , ( char * ) & i , sizeof ( i ) )
= = SOCKET_ERROR )
{
2010-06-22 18:11:00 +00:00
int err = SOCKETERRNO ;
Con_SafePrintf ( " UDP, setsockopt: %s \n " , socketerror ( err ) ) ;
2010-02-15 23:26:55 +00:00
return - 1 ;
2010-06-21 15:24:40 +00:00
}
2017-09-17 02:12:53 +00:00
net_broadcastsocket4 = socketid ;
2010-02-15 23:26:55 +00:00
return 0 ;
}
//=============================================================================
2017-09-17 02:12:53 +00:00
int UDP4_Broadcast ( sys_socket_t socketid , byte * buf , int len )
2010-02-15 23:26:55 +00:00
{
2010-06-20 10:03:05 +00:00
int ret ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
if ( socketid ! = net_broadcastsocket4 )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
if ( net_broadcastsocket4 ! = INVALID_SOCKET )
2010-06-20 10:03:05 +00:00
Sys_Error ( " Attempted to use multiple broadcasts sockets " ) ;
2017-09-17 02:12:53 +00:00
ret = UDP4_MakeSocketBroadcastCapable ( socketid ) ;
2010-02-15 23:26:55 +00:00
if ( ret = = - 1 )
{
2017-09-17 02:12:53 +00:00
Con_SafePrintf ( " Unable to make socket broadcast capable \n " ) ;
2010-02-15 23:26:55 +00:00
return ret ;
}
}
2017-09-17 02:12:53 +00:00
return UDP_Write ( socketid , buf , len , ( struct qsockaddr * ) & broadcastaddr4 ) ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
2010-06-21 15:24:40 +00:00
int UDP_Write ( sys_socket_t socketid , byte * buf , int len , struct qsockaddr * addr )
2010-02-15 23:26:55 +00:00
{
2010-06-20 10:03:05 +00:00
int ret ;
2017-09-17 02:12:53 +00:00
socklen_t addrsize ;
if ( addr - > qsa_family = = AF_INET )
addrsize = sizeof ( struct sockaddr_in ) ;
else if ( addr - > qsa_family = = AF_INET6 )
addrsize = sizeof ( struct sockaddr_in6 ) ;
else
{
Con_SafePrintf ( " UDP_Write: unknown family \n " ) ;
return - 1 ; //some kind of error. a few systems get pissy if the size doesn't exactly match the address family
}
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
ret = sendto ( socketid , buf , len , 0 , ( struct sockaddr * ) addr , addrsize ) ;
if ( ! addr - > qsa_family )
Con_SafePrintf ( " UDP_Write: family was cleared \n " ) ;
2010-06-21 15:24:40 +00:00
if ( ret = = SOCKET_ERROR )
{
int err = SOCKETERRNO ;
2011-01-12 20:10:34 +00:00
if ( err = = NET_EWOULDBLOCK )
2010-06-21 15:24:40 +00:00
return 0 ;
2017-09-17 02:12:53 +00:00
if ( err = = ENETUNREACH )
Con_SafePrintf ( " UDP_Write: %s (%s) \n " , socketerror ( err ) , UDP_AddrToString ( addr , false ) ) ;
else
Con_SafePrintf ( " UDP_Write, sendto: %s \n " , socketerror ( err ) ) ;
2010-06-21 15:24:40 +00:00
}
2010-02-15 23:26:55 +00:00
return ret ;
}
//=============================================================================
2017-09-17 02:12:53 +00:00
const char * UDP_AddrToString ( struct qsockaddr * addr , qboolean masked )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
static char buffer [ 64 ] ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
if ( addr - > qsa_family = = AF_INET )
{
int haddr = ntohl ( ( ( struct sockaddr_in * ) addr ) - > sin_addr . s_addr ) ;
q_snprintf ( buffer , sizeof ( buffer ) , " %d.%d.%d.%d:%d " , ( haddr > > 24 ) & 0xff ,
2022-04-27 21:32:40 +00:00
( haddr > > 16 ) & 0xff , ( haddr > > 8 ) & 0xff , haddr & 0xff ,
2017-09-17 02:12:53 +00:00
ntohs ( ( ( struct sockaddr_in * ) addr ) - > sin_port ) ) ;
}
else if ( addr - > qsa_family = = AF_INET6 )
{
//evil type punning.
unsigned short * s = ( unsigned short * ) & ( ( struct sockaddr_in6 * ) addr ) - > sin6_addr ;
if ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_scope_id )
{
q_snprintf ( buffer , sizeof ( buffer ) , " [%x:%x:%x:%x:%x:%x:%x:%x%%%i]:%d " ,
ntohs ( s [ 0 ] ) ,
ntohs ( s [ 1 ] ) ,
ntohs ( s [ 2 ] ) ,
ntohs ( s [ 3 ] ) ,
ntohs ( s [ 4 ] ) ,
ntohs ( s [ 5 ] ) ,
ntohs ( s [ 6 ] ) ,
ntohs ( s [ 7 ] ) ,
( int ) ( ( struct sockaddr_in6 * ) addr ) - > sin6_scope_id ,
ntohs ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_port ) ) ;
}
else
{
q_snprintf ( buffer , sizeof ( buffer ) , " [%x:%x:%x:%x:%x:%x:%x:%x]:%d " ,
ntohs ( s [ 0 ] ) ,
ntohs ( s [ 1 ] ) ,
ntohs ( s [ 2 ] ) ,
ntohs ( s [ 3 ] ) ,
ntohs ( s [ 4 ] ) ,
ntohs ( s [ 5 ] ) ,
ntohs ( s [ 6 ] ) ,
ntohs ( s [ 7 ] ) ,
ntohs ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_port ) ) ;
}
}
else
strcpy ( buffer , " ? " ) ;
2010-02-15 23:26:55 +00:00
return buffer ;
}
//=============================================================================
2017-09-17 02:12:53 +00:00
int UDP4_StringToAddr ( const char * string , struct qsockaddr * addr )
2010-02-15 23:26:55 +00:00
{
2010-06-20 10:03:05 +00:00
int ha1 , ha2 , ha3 , ha4 , hp , ipaddr ;
2010-02-15 23:26:55 +00:00
sscanf ( string , " %d.%d.%d.%d:%d " , & ha1 , & ha2 , & ha3 , & ha4 , & hp ) ;
ipaddr = ( ha1 < < 24 ) | ( ha2 < < 16 ) | ( ha3 < < 8 ) | ha4 ;
2010-06-21 09:20:32 +00:00
addr - > qsa_family = AF_INET ;
2010-02-15 23:26:55 +00:00
( ( struct sockaddr_in * ) addr ) - > sin_addr . s_addr = htonl ( ipaddr ) ;
2010-06-20 10:03:05 +00:00
( ( struct sockaddr_in * ) addr ) - > sin_port = htons ( ( unsigned short ) hp ) ;
2010-02-15 23:26:55 +00:00
return 0 ;
}
//=============================================================================
2010-06-21 15:24:40 +00:00
int UDP_GetSocketAddr ( sys_socket_t socketid , struct qsockaddr * addr )
2010-02-15 23:26:55 +00:00
{
2010-06-19 17:04:04 +00:00
socklen_t addrlen = sizeof ( struct qsockaddr ) ;
2010-06-21 15:24:40 +00:00
in_addr_t a ;
2010-02-15 23:26:55 +00:00
2010-06-21 15:24:40 +00:00
memset ( addr , 0 , sizeof ( struct qsockaddr ) ) ;
2010-06-19 18:20:22 +00:00
if ( getsockname ( socketid , ( struct sockaddr * ) addr , & addrlen ) ! = 0 )
2010-06-19 16:37:28 +00:00
return - 1 ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
if ( addr - > qsa_family = = AF_INET )
{
a = ( ( struct sockaddr_in * ) addr ) - > sin_addr . s_addr ;
if ( a = = 0 | | a = = htonl ( INADDR_LOOPBACK ) )
( ( struct sockaddr_in * ) addr ) - > sin_addr . s_addr = myAddr4 ;
}
else if ( addr - > qsa_family = = AF_INET6 )
{
static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT ;
if ( ! memcmp ( & ( ( struct sockaddr_in6 * ) addr ) - > sin6_addr , & in6addr_any , sizeof ( in6addr_any ) ) )
memcpy ( & ( ( struct sockaddr_in6 * ) addr ) - > sin6_addr , & myAddrv6 , sizeof ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_addr ) ) ;
}
2010-02-15 23:26:55 +00:00
return 0 ;
}
//=============================================================================
int UDP_GetNameFromAddr ( struct qsockaddr * addr , char * name )
{
2017-09-17 02:12:53 +00:00
if ( addr - > qsa_family = = AF_INET )
{
struct hostent * hostentry ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
hostentry = gethostbyaddr ( ( char * ) & ( ( struct sockaddr_in * ) addr ) - > sin_addr ,
sizeof ( struct in_addr ) , AF_INET ) ;
if ( hostentry )
{
strncpy ( name , ( char * ) hostentry - > h_name , NET_NAMELEN - 1 ) ;
return 0 ;
}
}
else if ( addr - > qsa_family = = AF_INET6 )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
//meh, don't bother, its unreliable anyway.
2010-02-15 23:26:55 +00:00
}
2017-09-17 02:12:53 +00:00
strcpy ( name , UDP_AddrToString ( addr , false ) ) ;
2010-02-15 23:26:55 +00:00
return 0 ;
}
//=============================================================================
2017-09-17 02:12:53 +00:00
int UDP4_GetAddrFromName ( const char * name , struct qsockaddr * addr )
2010-02-15 23:26:55 +00:00
{
struct hostent * hostentry ;
2017-09-17 02:12:53 +00:00
char * colon ;
unsigned short port = net_hostport ;
2010-02-15 23:26:55 +00:00
if ( name [ 0 ] > = ' 0 ' & & name [ 0 ] < = ' 9 ' )
return PartialIPAddress ( name , addr ) ;
2017-09-17 02:12:53 +00:00
colon = strrchr ( name , ' : ' ) ;
if ( colon )
{
char dupe [ MAXHOSTNAMELEN ] ;
if ( colon - name + 1 > MAXHOSTNAMELEN )
return - 1 ;
memcpy ( dupe , name , colon - name ) ;
dupe [ colon - name ] = 0 ;
hostentry = gethostbyname ( dupe ) ;
port = strtoul ( colon + 1 , NULL , 10 ) ;
}
else
hostentry = gethostbyname ( name ) ;
if ( ! hostentry | | hostentry - > h_addrtype ! = AF_INET )
2010-02-15 23:26:55 +00:00
return - 1 ;
2010-06-21 09:20:32 +00:00
addr - > qsa_family = AF_INET ;
2017-09-17 02:12:53 +00:00
( ( struct sockaddr_in * ) addr ) - > sin_port = htons ( port ) ;
2010-06-20 10:03:05 +00:00
( ( struct sockaddr_in * ) addr ) - > sin_addr . s_addr =
* ( in_addr_t * ) hostentry - > h_addr_list [ 0 ] ;
2010-02-15 23:26:55 +00:00
return 0 ;
}
//=============================================================================
int UDP_AddrCompare ( struct qsockaddr * addr1 , struct qsockaddr * addr2 )
{
2010-06-21 09:20:32 +00:00
if ( addr1 - > qsa_family ! = addr2 - > qsa_family )
2010-02-15 23:26:55 +00:00
return - 1 ;
2017-09-17 02:12:53 +00:00
if ( addr1 - > qsa_family = = AF_INET )
{
if ( ( ( struct sockaddr_in * ) addr1 ) - > sin_addr . s_addr ! =
( ( struct sockaddr_in * ) addr2 ) - > sin_addr . s_addr )
return - 1 ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
if ( ( ( struct sockaddr_in * ) addr1 ) - > sin_port ! =
( ( struct sockaddr_in * ) addr2 ) - > sin_port )
return 1 ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
return 0 ;
}
else if ( addr1 - > qsa_family = = AF_INET6 )
{
if ( memcmp ( & ( ( struct sockaddr_in6 * ) addr1 ) - > sin6_addr ,
& ( ( struct sockaddr_in6 * ) addr2 ) - > sin6_addr ,
sizeof ( ( ( struct sockaddr_in6 * ) addr1 ) - > sin6_addr ) ) )
return - 1 ;
if ( ( ( struct sockaddr_in6 * ) addr1 ) - > sin6_port ! =
( ( struct sockaddr_in6 * ) addr2 ) - > sin6_port )
return 1 ;
if ( ( ( struct sockaddr_in6 * ) addr1 ) - > sin6_scope_id & &
( ( struct sockaddr_in6 * ) addr2 ) - > sin6_scope_id & &
( ( struct sockaddr_in6 * ) addr1 ) - > sin6_scope_id ! =
( ( struct sockaddr_in6 * ) addr2 ) - > sin6_scope_id ) //the ipv6 scope id is for use with link-local addresses, to identify the specific interface.
return 1 ;
return 0 ;
}
else
return - 1 ;
2010-02-15 23:26:55 +00:00
}
//=============================================================================
int UDP_GetSocketPort ( struct qsockaddr * addr )
{
2017-09-17 02:12:53 +00:00
if ( addr - > qsa_family = = AF_INET )
return ntohs ( ( ( struct sockaddr_in * ) addr ) - > sin_port ) ;
else if ( addr - > qsa_family = = AF_INET6 )
return ntohs ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_port ) ;
else
return - 1 ;
2010-02-15 23:26:55 +00:00
}
int UDP_SetSocketPort ( struct qsockaddr * addr , int port )
{
2017-09-17 02:12:53 +00:00
if ( addr - > qsa_family = = AF_INET )
( ( struct sockaddr_in * ) addr ) - > sin_port = htons ( ( unsigned short ) port ) ;
else if ( addr - > qsa_family = = AF_INET6 )
( ( struct sockaddr_in6 * ) addr ) - > sin6_port = htons ( ( unsigned short ) port ) ;
else
return - 1 ;
2010-02-15 23:26:55 +00:00
return 0 ;
}
//=============================================================================
2010-06-19 18:20:22 +00:00
2017-09-17 02:12:53 +00:00
sys_socket_t UDP6_Init ( void )
{
char * colon ;
struct qsockaddr addr ;
if ( COM_CheckParm ( " -noudp " ) | | COM_CheckParm ( " -noudp6 " ) )
return INVALID_SOCKET ;
// TODO: determine my name & address
if ( ( net_controlsocket6 = UDP6_OpenSocket ( 0 ) ) = = INVALID_SOCKET )
{
Con_SafePrintf ( " UDP6_Init: Unable to open control socket, UDPv6 disabled \n " ) ;
return INVALID_SOCKET ;
}
UDP_GetSocketAddr ( net_controlsocket6 , & addr ) ;
strcpy ( my_ipv6_address , UDP_AddrToString ( & addr , false ) ) ;
colon = strrchr ( my_ipv6_address , ' : ' ) ;
if ( colon )
* colon = 0 ;
Con_SafePrintf ( " UDPv6 Initialized \n " ) ;
ipv6Available = true ;
return net_controlsocket6 ;
}
//=============================================================================
void UDP6_Shutdown ( void )
{
UDP6_Listen ( false ) ;
UDP_CloseSocket ( net_controlsocket6 ) ;
}
//=============================================================================
sys_socket_t UDP6_Listen ( qboolean state )
{
if ( state )
{
// enable listening
if ( net_acceptsocket6 = = INVALID_SOCKET )
{
if ( ( net_acceptsocket6 = UDP6_OpenSocket ( net_hostport ) ) = = INVALID_SOCKET )
Sys_Error ( " UDP6_Listen: Unable to open accept socket " ) ;
}
}
else
{
// disable listening
if ( net_acceptsocket6 ! = INVALID_SOCKET )
{
UDP_CloseSocket ( net_acceptsocket6 ) ;
net_acceptsocket6 = INVALID_SOCKET ;
}
}
return net_acceptsocket6 ;
}
//=============================================================================
sys_socket_t UDP6_OpenSocket ( int port )
{
sys_socket_t newsocket ;
struct sockaddr_in6 address ;
int _true = 1 ;
int err ;
if ( ( newsocket = socket ( PF_INET6 , SOCK_DGRAM , IPPROTO_UDP ) ) = = INVALID_SOCKET )
{
err = SOCKETERRNO ;
Con_SafePrintf ( " UDP6_OpenSocket: %s \n " , socketerror ( err ) ) ;
return INVALID_SOCKET ;
}
setsockopt ( newsocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( char * ) & _true , sizeof ( _true ) ) ;
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = SOCKET_ERROR )
goto ErrorReturn ;
memset ( & address , 0 , sizeof ( struct sockaddr_in6 ) ) ;
address . sin6_family = AF_INET6 ;
memset ( & address . sin6_addr , 0 , sizeof ( address . sin6_addr ) ) ;
address . sin6_port = htons ( ( unsigned short ) port ) ;
if ( bind ( newsocket , ( struct sockaddr * ) & address , sizeof ( address ) ) = = 0 )
{
//we don't know if we're the server or not. oh well.
struct ipv6_mreq req ;
memset ( & req , 0 , sizeof ( req ) ) ;
req . ipv6mr_multiaddr . s6_addr [ 0 ] = 0xff ;
req . ipv6mr_multiaddr . s6_addr [ 1 ] = 0x03 ;
req . ipv6mr_multiaddr . s6_addr [ 15 ] = 0x01 ;
req . ipv6mr_interface = 0 ;
setsockopt ( newsocket , IPPROTO_IPV6 , IPV6_JOIN_GROUP , ( char * ) & req , sizeof ( req ) ) ;
return newsocket ;
}
ErrorReturn :
err = SOCKETERRNO ;
Con_SafePrintf ( " UDP6_OpenSocket: %s \n " , socketerror ( err ) ) ;
UDP_CloseSocket ( newsocket ) ;
return INVALID_SOCKET ;
}
//=============================================================================
sys_socket_t UDP6_CheckNewConnections ( void )
{
int available ;
struct sockaddr_in from ;
socklen_t fromlen ;
char buff [ 1 ] ;
if ( net_acceptsocket6 = = INVALID_SOCKET )
return INVALID_SOCKET ;
if ( ioctl ( net_acceptsocket6 , FIONREAD , & available ) = = - 1 )
{
int err = SOCKETERRNO ;
Sys_Error ( " UDP6: ioctlsocket (FIONREAD) failed (%s) " , socketerror ( err ) ) ;
}
if ( available )
return net_acceptsocket6 ;
// quietly absorb empty packets
fromlen = sizeof ( from ) ;
recvfrom ( net_acceptsocket6 , buff , 0 , 0 , ( struct sockaddr * ) & from , & fromlen ) ;
return INVALID_SOCKET ;
}
//=============================================================================
int UDP6_Broadcast ( sys_socket_t socketid , byte * buf , int len )
{
struct sockaddr_in6 address ;
memset ( & address , 0 , sizeof ( struct sockaddr_in6 ) ) ;
address . sin6_family = AF_INET6 ;
memset ( & address . sin6_addr , 0 , sizeof ( address . sin6_addr ) ) ;
address . sin6_addr . s6_addr [ 0 ] = 0xff ;
address . sin6_addr . s6_addr [ 1 ] = 0x03 ;
address . sin6_addr . s6_addr [ 15 ] = 0x1 ;
address . sin6_port = htons ( ( unsigned short ) net_hostport ) ;
return UDP_Write ( socketid , buf , len , ( struct qsockaddr * ) & address ) ;
}
//=============================================================================
int UDP6_StringToAddr ( const char * string , struct qsockaddr * addr )
{ //This is never actually called...
Con_SafePrintf ( " UDP6_StringToAddr: %s \n " , string ) ;
return UDP6_GetAddrFromName ( string , addr ) ;
}
//=============================================================================
int UDP6_GetAddrFromName ( const char * name , struct qsockaddr * addr )
{
struct addrinfo * addrinfo = NULL ;
struct addrinfo * pos ;
struct addrinfo udp6hint ;
int error ;
char * port ;
char dupbase [ 256 ] ;
size_t len ;
qboolean success = false ;
memset ( & udp6hint , 0 , sizeof ( udp6hint ) ) ;
udp6hint . ai_family = 0 ; //Any... we check for AF_INET6 or 4
udp6hint . ai_socktype = SOCK_DGRAM ;
udp6hint . ai_protocol = IPPROTO_UDP ;
if ( * name = = ' [ ' )
{
port = strstr ( name , " ] " ) ;
if ( ! port )
error = EAI_NONAME ;
else
{
len = port - ( name + 1 ) ;
if ( len > = sizeof ( dupbase ) )
len = sizeof ( dupbase ) - 1 ;
strncpy ( dupbase , name + 1 , len ) ;
dupbase [ len ] = ' \0 ' ;
error = getaddrinfo ( dupbase , ( port [ 1 ] = = ' : ' ) ? port + 2 : NULL , & udp6hint , & addrinfo ) ;
}
}
else
{
port = strrchr ( name , ' : ' ) ;
if ( port )
{
len = port - name ;
if ( len > = sizeof ( dupbase ) )
len = sizeof ( dupbase ) - 1 ;
strncpy ( dupbase , name , len ) ;
dupbase [ len ] = ' \0 ' ;
error = getaddrinfo ( dupbase , port + 1 , & udp6hint , & addrinfo ) ;
}
else
error = EAI_NONAME ;
if ( error ) //failed, try string with no port.
error = getaddrinfo ( name , NULL , & udp6hint , & addrinfo ) ; //remember, this func will return any address family that could be using the udp protocol... (ip4 or ip6)
}
if ( ! error )
{
( ( struct sockaddr * ) addr ) - > sa_family = 0 ;
for ( pos = addrinfo ; pos ; pos = pos - > ai_next )
{
if ( 0 ) //pos->ai_family == AF_INET)
{
memcpy ( addr , pos - > ai_addr , pos - > ai_addrlen ) ;
success = true ;
break ;
}
if ( pos - > ai_family = = AF_INET6 & & ! success )
{
memcpy ( addr , pos - > ai_addr , pos - > ai_addrlen ) ;
success = true ;
}
}
freeaddrinfo ( addrinfo ) ;
}
if ( success )
{
if ( ( ( struct sockaddr * ) addr ) - > sa_family = = AF_INET )
{
if ( ! ( ( struct sockaddr_in * ) addr ) - > sin_port )
( ( struct sockaddr_in * ) addr ) - > sin_port = htons ( net_hostport ) ;
}
else if ( ( ( struct sockaddr * ) addr ) - > sa_family = = AF_INET6 )
{
if ( ! ( ( struct sockaddr_in6 * ) addr ) - > sin6_port )
( ( struct sockaddr_in6 * ) addr ) - > sin6_port = htons ( net_hostport ) ;
}
return 0 ;
}
return - 1 ;
}
//=============================================================================
2018-12-07 04:14:56 +00:00
# ifdef __linux__ //sadly there is no posix standard for querying all ipv4+ipv6 addresses.
# include <ifaddrs.h>
static struct ifaddrs * iflist ;
2020-07-02 19:05:51 +00:00
static double iftime ; //requery sometimes.
2018-12-07 04:14:56 +00:00
static int UDP_GetAddresses ( qhostaddr_t * addresses , int maxaddresses , int fam )
{
struct ifaddrs * ifa ;
int result = 0 ;
double time = Sys_DoubleTime ( ) ;
2020-07-02 19:05:51 +00:00
size_t l ;
2018-12-07 04:14:56 +00:00
if ( time - iftime > 1 & & iflist )
{
freeifaddrs ( iflist ) ;
iflist = NULL ;
}
if ( ! iflist )
{
iftime = time ;
getifaddrs ( & iflist ) ;
}
for ( ifa = iflist ; ifa & & result < maxaddresses ; ifa = ifa - > ifa_next )
{
//can happen if the interface is not bound.
if ( ifa - > ifa_addr = = NULL )
continue ;
if ( fam = = ifa - > ifa_addr - > sa_family )
2020-07-02 19:05:51 +00:00
{
q_strlcpy ( addresses [ result ] , UDP_AddrToString ( ( struct qsockaddr * ) ifa - > ifa_addr , false ) , sizeof ( addresses [ 0 ] ) ) ;
l = strlen ( addresses [ result ] ) ; //trim any useless :0 port numbers.
if ( l > 2 & & ! strcmp ( addresses [ result ] + l - 2 , " :0 " ) )
addresses [ result ] [ l - 2 ] = 0 ;
result + + ;
}
2018-12-07 04:14:56 +00:00
}
return result ;
}
# else
//for other systems, like macs, where we don't know how to query this stuff properly.
//FIXME: there is a posix standard for ipv4 at least.
static int UDP_GetAddresses ( qhostaddr_t * addresses , int maxaddresses , int fam )
{
return 0 ;
}
# endif
int UDP4_GetAddresses ( qhostaddr_t * addresses , int maxaddresses )
{
return UDP_GetAddresses ( addresses , maxaddresses , AF_INET ) ;
}
int UDP6_GetAddresses ( qhostaddr_t * addresses , int maxaddresses )
{
return UDP_GetAddresses ( addresses , maxaddresses , AF_INET6 ) ;
}