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
2012-10-18 15:20:00 +00:00
# ifdef _WIN32
# define USE_GETHOSTNAME_LOCALLISTING
# endif
2012-04-09 19:12:12 +00:00
2011-10-27 16:16:29 +00:00
netadr_t net_local_cl_ipadr ; //still used to match local ui requests (quake/gamespy), and to generate ip reports for q3 servers (which is probably pointless).
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
2010-08-16 02:03:02 +00:00
qbyte net_message_buffer [ MAX_OVERALLMSGLEN ] ;
2004-08-21 01:25:48 +00:00
# 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
2013-03-31 04:21:08 +00:00
# if defined(HAVE_IPV4) && !defined(CLIENTONLY)
# define HAVE_NATPMP
2012-04-09 19:12:12 +00:00
# endif
2013-03-31 04:21:08 +00:00
void NET_GetLocalAddress ( int socket , netadr_t * out ) ;
//int TCP_OpenListenSocket (const char *localip, int port);
2006-05-09 00:02:05 +00:00
# ifdef IPPROTO_IPV6
int UDP6_OpenSocket ( int port , qboolean bcast ) ;
# endif
# ifdef USEIPX
void IPX_CloseSocket ( int socket ) ;
# endif
2011-12-05 15:23:40 +00:00
cvar_t net_hybriddualstack = CVAR ( " net_hybriddualstack " , " 1 " ) ;
2012-02-12 05:18:31 +00:00
cvar_t net_fakeloss = CVARFD ( " net_fakeloss " , " 0 " , CVAR_CHEAT , " Simulates packetloss in both receiving and sending, on a scale from 0 to 1. " ) ;
2004-08-21 01:25:48 +00:00
2008-11-09 22:29:28 +00:00
extern cvar_t sv_public , sv_listen_qw , sv_listen_nq , sv_listen_dp , sv_listen_q3 ;
2004-08-21 01:25:48 +00:00
2006-05-09 00:02:05 +00:00
static qboolean allowconnects = false ;
2004-08-21 01:25:48 +00:00
2013-03-31 04:21:08 +00:00
# define FTENET_ADDRTYPES 2
typedef struct ftenet_generic_connection_s {
char name [ MAX_QPATH ] ;
int ( * GetLocalAddress ) ( struct ftenet_generic_connection_s * con , netadr_t * local , int adridx ) ;
qboolean ( * ChangeLocalAddress ) ( struct ftenet_generic_connection_s * con , const char * newaddress ) ;
qboolean ( * GetPacket ) ( struct ftenet_generic_connection_s * con ) ;
qboolean ( * SendPacket ) ( struct ftenet_generic_connection_s * con , int length , void * data , netadr_t to ) ;
void ( * Close ) ( struct ftenet_generic_connection_s * con ) ;
# ifdef HAVE_PACKET
int ( * SetReceiveFDSet ) ( struct ftenet_generic_connection_s * con , fd_set * fdset ) ; /*set for connections which have multiple sockets (ie: listening tcp connections)*/
# endif
netadrtype_t addrtype [ FTENET_ADDRTYPES ] ;
qboolean islisten ;
int thesocket ;
} ftenet_generic_connection_t ;
2012-05-09 15:30:53 +00:00
# define MAX_LOOPBACK 8
2004-08-21 01:25:48 +00:00
typedef struct
{
2013-03-12 23:24:15 +00:00
qbyte data [ MAX_OVERALLMSGLEN ] ;
2004-08-21 01:25:48 +00:00
int datalen ;
} loopmsg_t ;
typedef struct
{
2013-03-31 04:21:08 +00:00
qboolean inited ;
2004-08-21 01:25:48 +00:00
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 )
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_WEBSOCKCL
case NA_WEBSOCKET :
memset ( s , 0 , sizeof ( struct sockaddr_websocket ) ) ;
( ( struct sockaddr_websocket * ) s ) - > sws_family = AF_WEBSOCK ;
memcpy ( ( ( struct sockaddr_websocket * ) s ) - > url , a - > address . websocketurl , sizeof ( ( ( struct sockaddr_websocket * ) s ) - > url ) ) ;
return sizeof ( struct sockaddr_websocket ) ;
# endif
# ifdef HAVE_IPV4
2004-08-21 01:25:48 +00:00
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
2009-06-10 22:36:53 +00:00
case NA_TCP :
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 ) ;
2012-04-09 19:12:12 +00:00
# endif
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
2009-06-10 22:36:53 +00:00
case NA_TCPV6 :
2004-08-21 01:25:48 +00:00
case NA_IPV6 :
2008-05-25 01:07:53 +00:00
memset ( s , 0 , sizeof ( struct sockaddr_in6 ) ) ;
2004-08-21 01:25:48 +00:00
( ( 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 )
{
2008-11-09 22:29:28 +00:00
a - > connum = 0 ;
2005-01-29 02:26:42 +00:00
switch ( ( ( struct sockaddr * ) s ) - > sa_family )
2004-08-21 01:25:48 +00:00
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_WEBSOCKCL
case AF_WEBSOCK :
a - > type = NA_WEBSOCKET ;
memcpy ( a - > address . websocketurl , ( ( struct sockaddr_websocket * ) s ) - > url , sizeof ( a - > address . websocketurl ) ) ;
a - > port = 0 ;
break ;
# endif
# ifdef HAVE_IPV4
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 ;
2012-04-09 19:12:12 +00:00
# endif
2004-08-21 01:25:48 +00:00
# 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
2012-03-19 06:30:41 +00:00
default :
Con_Printf ( " SockadrToNetadr: bad socket family - %i " , ( ( struct sockaddr * ) s ) - > sa_family ) ;
2004-08-21 01:25:48 +00:00
case AF_UNSPEC :
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_INVALID ;
break ;
}
}
qboolean NET_CompareAdr ( netadr_t a , netadr_t b )
{
if ( a . type ! = b . type )
2013-03-31 04:21:08 +00:00
{
int i ;
if ( a . type = = NA_IP & & b . type = = NA_IPV6 )
{
for ( i = 0 ; i < 10 ; i + + )
if ( b . address . ip6 [ i ] ! = 0 )
return false ; //only matches if they're 0s, otherwise its not an ipv4 address there
for ( ; i < 12 ; i + + )
if ( b . address . ip6 [ i ] ! = 0xff & & b . address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
return false ; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there
for ( i = 0 ; i < 4 ; i + + )
{
if ( a . address . ip [ i ] ! = b . address . ip6 [ 12 + i ] )
return false ; //mask doesn't match
}
return true ; //its an ipv4 address in there, the mask matched the whole way through
}
if ( a . type = = NA_IPV6 & & b . type = = NA_IP )
{
for ( i = 0 ; i < 10 ; i + + )
if ( a . address . ip6 [ i ] ! = 0 )
return false ; //only matches if they're 0s, otherwise its not an ipv4 address there
for ( ; i < 12 ; i + + )
if ( a . address . ip6 [ i ] ! = 0xff & & a . address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
return false ; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there
for ( i = 0 ; i < 4 ; i + + )
{
if ( a . address . ip6 [ 12 + i ] ! = b . address . ip [ i ] )
return false ; //mask doesn't match
}
return true ; //its an ipv4 address in there, the mask matched the whole way through
}
2004-08-21 01:25:48 +00:00
return false ;
2013-03-31 04:21:08 +00:00
}
2004-08-21 01:25:48 +00:00
if ( a . type = = NA_LOOPBACK )
return true ;
2012-04-09 19:12:12 +00:00
# ifdef HAVE_WEBSOCKCL
if ( a . type = = NA_WEBSOCKET )
{
if ( ! strcmp ( a . address . websocketurl , a . address . websocketurl ) & & a . port = = b . port )
return true ;
return false ;
}
# endif
# ifdef HAVE_IPV4
2009-06-10 22:36:53 +00:00
if ( a . type = = NA_IP | | a . type = = NA_BROADCAST_IP | | a . type = = NA_TCP )
2004-08-21 01:25:48 +00:00
{
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 ;
}
2012-04-09 19:12:12 +00:00
# endif
2004-08-21 01:25:48 +00:00
# ifdef IPPROTO_IPV6
2009-06-10 22:36:53 +00:00
if ( a . type = = NA_IPV6 | | a . type = = NA_BROADCAST_IP6 | | a . type = = NA_TCPV6 )
2004-08-21 01:25:48 +00:00
{
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
2008-11-13 08:55:41 +00:00
# ifdef USEIPX
2004-08-21 01:25:48 +00:00
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 ;
}
2008-11-13 08:55:41 +00:00
# endif
2004-08-21 01:25:48 +00:00
2008-11-09 22:29:28 +00:00
# ifdef IRCCONNECT
if ( a . type = = NA_IRC )
{
if ( ! strcmp ( a . address . irc . user , b . address . irc . user ) )
return true ;
return false ;
}
# endif
2004-08-21 01:25:48 +00:00
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 ;
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2012-01-17 07:57:46 +00:00
if ( a . type = = NA_IP | | a . type = = NA_TCP )
2004-08-21 01:25:48 +00:00
{
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 ;
}
2012-04-09 19:12:12 +00:00
# endif
2004-08-21 01:25:48 +00:00
# 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
2008-11-13 08:55:41 +00:00
# ifdef USEIPX
2004-08-21 01:25:48 +00:00
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 ;
}
2008-11-13 08:55:41 +00:00
# endif
2008-11-09 22:29:28 +00:00
# ifdef IRCCONNECT
if ( a . type = = NA_IRC )
{
if ( ! strcmp ( a . address . irc . user , b . address . irc . user ) )
return true ;
return false ;
}
# endif
2004-08-21 01:25:48 +00:00
Sys_Error ( " NET_CompareBaseAdr: Bad address type " ) ;
return false ;
}
2008-05-25 01:07:53 +00:00
qboolean NET_AddressSmellsFunny ( netadr_t a )
{
2012-03-19 06:30:41 +00:00
# ifdef IPPROTO_IPV6
2008-05-25 01:07:53 +00:00
int i ;
2012-03-19 06:30:41 +00:00
# endif
2008-05-25 01:07:53 +00:00
//rejects certain blacklisted addresses
switch ( a . type )
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2008-05-25 01:07:53 +00:00
case NA_BROADCAST_IP :
case NA_IP :
//reject localhost
if ( a . address . ip [ 0 ] = = 127 ) // && a.address.ip[1] == 0 && a.address.ip[2] == 0 && a.address.ip[3] == 1 )
return true ;
//'this' network (not an issue, but lets reject it anyway)
if ( a . address . ip [ 0 ] = = 0 & & a . address . ip [ 1 ] = = 0 & & a . address . ip [ 2 ] = = 0 & & a . address . ip [ 3 ] = = 0 )
return true ;
//reject any broadcasts
if ( a . address . ip [ 0 ] = = 255 & & a . address . ip [ 1 ] = = 255 & & a . address . ip [ 2 ] = = 255 & & a . address . ip [ 3 ] = = 0 )
return true ;
//not much else I can reject
return false ;
2012-04-09 19:12:12 +00:00
# endif
2008-05-25 01:07:53 +00:00
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
//reject [::XXXX] (this includes obsolete ipv4-compatible (not ipv4 mapped), and localhost)
for ( i = 0 ; i < 12 ; i + + )
if ( a . address . ip6 [ i ] )
break ;
if ( i = = 12 )
return true ;
return false ;
# endif
# ifdef USEIPX
//no idea how this protocol's addresses work
case NA_BROADCAST_IPX :
case NA_IPX :
return false ;
# endif
2011-05-15 13:23:13 +00:00
2008-05-25 01:07:53 +00:00
case NA_LOOPBACK :
return false ;
default :
return true ;
}
}
2008-06-08 14:37:57 +00:00
char * NET_AdrToString ( char * s , int len , netadr_t a )
2004-08-21 01:25:48 +00:00
{
2009-06-10 22:36:53 +00:00
char * rs = s ;
2008-05-25 01:07:53 +00:00
char * p ;
int i ;
2012-03-19 06:30:41 +00:00
# ifdef IPPROTO_IPV6
qboolean doneblank ;
# endif
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
switch ( a . type )
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_WEBSOCKCL
case NA_WEBSOCKET :
Q_strncpyz ( s , a . address . websocketurl , len ) ;
break ;
# endif
2008-11-09 22:29:28 +00:00
# ifdef TCPCONNECT
case NA_TCP :
if ( len < 7 )
return " ? " ;
snprintf ( s , len , " tcp:// " ) ;
s + = 6 ;
len - = 6 ;
//fallthrough
# endif
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2004-08-21 01:25:48 +00:00
case NA_BROADCAST_IP :
case NA_IP :
2010-11-28 19:15:37 +00:00
if ( a . port )
{
2011-05-15 13:23:13 +00:00
snprintf ( s , len , " %i.%i.%i.%i:%i " ,
a . address . ip [ 0 ] ,
a . address . ip [ 1 ] ,
a . address . ip [ 2 ] ,
a . address . ip [ 3 ] ,
2010-11-28 19:15:37 +00:00
ntohs ( a . port ) ) ;
}
else
{
2011-05-15 13:23:13 +00:00
snprintf ( s , len , " %i.%i.%i.%i " ,
a . address . ip [ 0 ] ,
a . address . ip [ 1 ] ,
a . address . ip [ 2 ] ,
2010-11-28 19:15:37 +00:00
a . address . ip [ 3 ] ) ;
}
2004-08-21 01:25:48 +00:00
break ;
2012-04-09 19:12:12 +00:00
# endif
2008-11-09 22:29:28 +00:00
# ifdef TCPCONNECT
case NA_TCPV6 :
if ( len < 7 )
return " ? " ;
snprintf ( s , len , " tcp:// " ) ;
s + = 6 ;
len - = 6 ;
//fallthrough
# endif
2004-08-21 01:25:48 +00:00
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
2011-12-05 15:23:40 +00:00
if ( ! * ( int * ) & a . address . ip6 [ 0 ] & &
! * ( int * ) & a . address . ip6 [ 4 ] & &
! * ( short * ) & a . address . ip6 [ 8 ] & &
* ( short * ) & a . address . ip6 [ 10 ] = = ( short ) 0xffff )
{
if ( a . port )
snprintf ( s , len , " %i.%i.%i.%i:%i " ,
a . address . ip6 [ 12 ] ,
a . address . ip6 [ 13 ] ,
a . address . ip6 [ 14 ] ,
a . address . ip6 [ 15 ] ,
ntohs ( a . port ) ) ;
else
snprintf ( s , len , " %i.%i.%i.%i " ,
a . address . ip6 [ 12 ] ,
a . address . ip6 [ 13 ] ,
a . address . ip6 [ 14 ] ,
a . address . ip6 [ 15 ] ) ;
break ;
}
2008-06-08 20:41:22 +00:00
* s = 0 ;
2008-05-25 01:07:53 +00:00
doneblank = false ;
p = s ;
2008-06-08 20:20:11 +00:00
snprintf ( s , len - strlen ( s ) , " [ " ) ;
2008-05-25 01:07:53 +00:00
p + = strlen ( p ) ;
for ( i = 0 ; i < 16 ; i + = 2 )
{
if ( doneblank ! = true & & a . address . ip6 [ i ] = = 0 & & a . address . ip6 [ i + 1 ] = = 0 )
{
if ( ! doneblank )
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " :: " ) ;
2008-05-25 01:07:53 +00:00
p + = strlen ( p ) ;
doneblank = 2 ;
}
}
else
{
if ( doneblank = = 2 )
doneblank = true ;
else if ( i ! = 0 )
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " : " ) ;
2008-05-25 01:07:53 +00:00
p + = strlen ( p ) ;
}
if ( a . address . ip6 [ i + 0 ] )
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x%02x " ,
2008-05-25 01:07:53 +00:00
a . address . ip6 [ i + 0 ] ,
a . address . ip6 [ i + 1 ] ) ;
}
else
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x " ,
2008-05-25 01:07:53 +00:00
a . address . ip6 [ i + 1 ] ) ;
}
p + = strlen ( p ) ;
}
}
2011-05-15 13:23:13 +00:00
snprintf ( p , len - strlen ( s ) , " ]:%i " ,
2006-02-17 02:51:59 +00:00
ntohs ( a . port ) ) ;
2004-08-21 01:25:48 +00:00
break ;
# endif
# ifdef USEIPX
case NA_BROADCAST_IPX :
case NA_IPX :
2008-06-08 20:20:11 +00:00
snprintf ( s , len , " %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i " ,
2006-02-17 02:51:59 +00:00
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 :
2011-12-05 15:23:40 +00:00
snprintf ( s , len , " QLoopBack " ) ;
2004-08-21 01:25:48 +00:00
break ;
2008-11-09 22:29:28 +00:00
# ifdef IRCCONNECT
case NA_IRC :
if ( * a . address . irc . channel )
2008-12-03 01:25:03 +00:00
snprintf ( s , len , " irc://%s@%s " , a . address . irc . user , a . address . irc . channel ) ;
2008-11-09 22:29:28 +00:00
else
snprintf ( s , len , " irc://%s " , a . address . irc . user ) ;
break ;
# endif
2004-08-21 01:25:48 +00:00
default :
2008-06-08 20:20:11 +00:00
snprintf ( s , len , " invalid netadr_t type " ) ;
2004-08-21 01:25:48 +00:00
// Sys_Error("NET_AdrToString: Bad netadr_t type");
}
2009-06-10 22:36:53 +00:00
return rs ;
2004-08-21 01:25:48 +00:00
}
2008-06-08 14:37:57 +00:00
char * NET_BaseAdrToString ( char * s , int len , netadr_t a )
2004-08-21 01:25:48 +00:00
{
2008-05-25 01:07:53 +00:00
int i , doneblank ;
char * p ;
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 :
2011-05-15 13:23:13 +00:00
snprintf ( s , len , " %i.%i.%i.%i " ,
a . address . ip [ 0 ] ,
2006-02-17 02:51:59 +00:00
a . address . ip [ 1 ] ,
a . address . ip [ 2 ] ,
a . address . ip [ 3 ] ) ;
2004-08-21 01:25:48 +00:00
break ;
2012-01-17 07:57:46 +00:00
case NA_TCP :
snprintf ( s , len , " tcp://%i.%i.%i.%i " ,
a . address . ip [ 0 ] ,
a . address . ip [ 1 ] ,
a . address . ip [ 2 ] ,
a . address . ip [ 3 ] ) ;
break ;
2004-08-21 01:25:48 +00:00
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
2011-12-05 15:23:40 +00:00
if ( ! * ( int * ) & a . address . ip6 [ 0 ] & &
! * ( int * ) & a . address . ip6 [ 4 ] & &
! * ( short * ) & a . address . ip6 [ 8 ] & &
* ( short * ) & a . address . ip6 [ 10 ] = = ( short ) 0xffff )
{
snprintf ( s , len , " %i.%i.%i.%i " ,
a . address . ip6 [ 12 ] ,
a . address . ip6 [ 13 ] ,
a . address . ip6 [ 14 ] ,
a . address . ip6 [ 15 ] ) ;
break ;
}
2008-06-08 20:41:22 +00:00
* s = 0 ;
2008-05-25 01:07:53 +00:00
doneblank = false ;
p = s ;
for ( i = 0 ; i < 16 ; i + = 2 )
{
if ( doneblank ! = true & & a . address . ip6 [ i ] = = 0 & & a . address . ip6 [ i + 1 ] = = 0 )
{
if ( ! doneblank )
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " :: " ) ;
2008-05-25 01:07:53 +00:00
p + = strlen ( p ) ;
doneblank = 2 ;
}
}
else
{
if ( doneblank = = 2 )
doneblank = true ;
else if ( i ! = 0 )
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " : " ) ;
2008-05-25 01:07:53 +00:00
p + = strlen ( p ) ;
}
if ( a . address . ip6 [ i + 0 ] )
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x%02x " ,
2008-05-25 01:07:53 +00:00
a . address . ip6 [ i + 0 ] ,
a . address . ip6 [ i + 1 ] ) ;
}
else
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x " ,
2008-05-25 01:07:53 +00:00
a . address . ip6 [ i + 1 ] ) ;
}
p + = strlen ( p ) ;
}
}
2004-08-21 01:25:48 +00:00
break ;
# endif
# ifdef USEIPX
case NA_BROADCAST_IPX :
case NA_IPX :
2011-05-15 13:23:13 +00:00
snprintf ( s , len , " %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x " ,
2006-02-17 02:51:59 +00:00
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 :
2008-06-08 20:20:11 +00:00
snprintf ( s , len , " LocalHost " ) ;
2004-08-21 01:25:48 +00:00
break ;
2008-11-09 22:29:28 +00:00
# ifdef IRCCONNECT
case NA_IRC :
snprintf ( s , len , " irc://%s " , a . address . irc . user ) ;
break ;
# endif
2004-08-21 01:25:48 +00:00
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 .
= = = = = = = = = = = = =
*/
2012-11-27 03:23:19 +00:00
qboolean NET_StringToSockaddr ( const char * s , int defaultport , struct sockaddr_qstorage * sadr , int * addrfamily , int * addrsize )
2004-08-21 01:25:48 +00:00
{
struct hostent * h ;
char * colon ;
char copy [ 128 ] ;
2005-07-03 15:16:20 +00:00
2006-06-17 06:22:48 +00:00
if ( ! ( * s ) )
return false ;
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 ;
2012-11-27 03:23:19 +00:00
# define DO(src,dest) \
copy [ 0 ] = s [ src ] ; \
copy [ 1 ] = s [ src + 1 ] ; \
sscanf ( copy , " %x " , & val ) ; \
( ( struct sockaddr_ipx * ) sadr ) - > dest = val
2004-08-21 01:25:48 +00:00
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 ) ;
2012-11-27 03:23:19 +00:00
# undef DO
2004-08-21 01:25:48 +00:00
( ( struct sockaddr_ipx * ) sadr ) - > sa_socket = htons ( ( unsigned short ) val ) ;
2012-11-27 03:23:19 +00:00
if ( addrfamily )
* addrfamily = AF_IPX ;
if ( addrsize )
* addrsize = sizeof ( struct sockaddr_ipx ) ;
2004-08-21 01:25:48 +00:00
}
else
# endif
# ifdef IPPROTO_IPV6
2006-06-30 15:45:16 +00:00
if ( pgetaddrinfo )
2004-08-21 01:25:48 +00:00
{
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 ;
2011-05-15 13:23:13 +00:00
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
{
2012-11-27 03:23:19 +00:00
port = strstr ( s , " ] " ) ;
2005-11-30 01:20:53 +00:00
if ( ! port )
error = EAI_NONAME ;
else
{
2009-04-01 22:03:56 +00:00
len = port - ( s + 1 ) ;
if ( len > = sizeof ( dupbase ) )
len = sizeof ( dupbase ) - 1 ;
strncpy ( dupbase , s + 1 , len ) ;
dupbase [ len ] = ' \0 ' ;
2012-11-27 03:23:19 +00:00
error = pgetaddrinfo ( dupbase , ( port [ 1 ] = = ' : ' ) ? port + 2 : NULL , & 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
{
2008-11-09 22:29:28 +00:00
port = strrchr ( s , ' : ' ) ;
2005-11-30 01:20:53 +00:00
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.
2012-11-27 03:23:19 +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
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2004-08-21 01:25:48 +00:00
case AF_INET :
2008-11-09 22:29:28 +00:00
memcpy ( sadr , pos - > ai_addr , pos - > ai_addrlen ) ;
2004-08-21 01:25:48 +00:00
if ( pos - > ai_family = = AF_INET )
goto dblbreak ; //don't try finding any more, this is quake, they probably prefer ip4...
break ;
2012-04-09 19:12:12 +00:00
# else
memcpy ( sadr , pos - > ai_addr , pos - > ai_addrlen ) ;
goto dblbreak ;
# endif
2004-08-21 01:25:48 +00:00
}
}
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 ;
2012-11-27 03:23:19 +00:00
if ( addrfamily )
* addrfamily = ( ( struct sockaddr * ) sadr ) - > sa_family ;
if ( ( ( struct sockaddr * ) sadr ) - > sa_family = = AF_INET )
{
if ( ! ( ( struct sockaddr_in * ) sadr ) - > sin_port )
( ( struct sockaddr_in * ) sadr ) - > sin_port = htons ( defaultport ) ;
if ( addrsize )
* addrsize = sizeof ( struct sockaddr_in ) ;
}
else
{
if ( ! ( ( struct sockaddr_in6 * ) sadr ) - > sin6_port )
( ( struct sockaddr_in6 * ) sadr ) - > sin6_port = htons ( defaultport ) ;
if ( addrsize )
* addrsize = sizeof ( struct sockaddr_in6 ) ;
}
2004-08-21 01:25:48 +00:00
}
else
# endif
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2004-08-21 01:25:48 +00:00
( ( struct sockaddr_in * ) sadr ) - > sin_family = AF_INET ;
( ( struct sockaddr_in * ) sadr ) - > sin_port = 0 ;
2006-06-30 15:45:16 +00:00
if ( strlen ( s ) > = sizeof ( copy ) - 1 )
return false ;
2011-05-15 13:23:13 +00:00
2012-11-27 03:23:19 +00:00
( ( struct sockaddr_in * ) sadr ) - > sin_port = htons ( defaultport ) ;
2004-08-21 01:25:48 +00:00
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 ) ) )
2006-06-17 06:22:48 +00:00
return false ;
2004-08-21 01:25:48 +00:00
if ( h - > h_addrtype ! = AF_INET )
2006-06-17 06:22:48 +00:00
return false ;
2004-08-21 01:25:48 +00:00
* ( int * ) & ( ( struct sockaddr_in * ) sadr ) - > sin_addr = * ( int * ) h - > h_addr_list [ 0 ] ;
}
2012-11-27 03:23:19 +00:00
if ( addrfamily )
* addrfamily = AF_INET ;
if ( addrsize )
* addrsize = sizeof ( struct sockaddr_in ) ;
2012-04-09 19:12:12 +00:00
# else
return false ;
# endif
2004-08-21 01:25:48 +00:00
}
return true ;
}
2008-11-09 22:29:28 +00:00
/*
accepts anything that NET_StringToSockaddr accepts plus certain url schemes
including : tcp , irc
*/
2013-03-12 22:53:23 +00:00
qboolean NET_StringToAdr ( const char * s , int defaultport , netadr_t * a )
2004-08-21 01:25:48 +00:00
{
struct sockaddr_qstorage sadr ;
2009-02-22 13:51:52 +00:00
Con_DPrintf ( " Resolving address: %s \n " , s ) ;
2012-04-09 19:12:12 +00:00
if ( ! strcmp ( s , " internalserver " ) )
{
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_LOOPBACK ;
return true ;
}
# ifdef HAVE_WEBSOCKCL
if ( ! strncmp ( s , " ws:// " , 5 ) | | ! strncmp ( s , " wss:// " , 6 ) )
{
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_WEBSOCKET ;
Q_strncpyz ( a - > address . websocketurl , s , sizeof ( a - > address . websocketurl ) ) ;
return true ;
}
else
{
/*code for convienience - no other protocols work anyway*/
2013-03-12 23:09:25 +00:00
static float warned ;
if ( warned < realtime )
2012-04-09 19:12:12 +00:00
{
2013-03-12 23:09:25 +00:00
Con_Printf ( " Note: Assuming ws:// prefix \n " ) ;
warned = realtime + 1 ;
2012-04-09 19:12:12 +00:00
}
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_WEBSOCKET ;
memcpy ( a - > address . websocketurl , " ws:// " , 5 ) ;
Q_strncpyz ( a - > address . websocketurl + 5 , s , sizeof ( a - > address . websocketurl ) - 5 ) ;
return true ;
}
# endif
2008-11-09 22:29:28 +00:00
# ifdef TCPCONNECT
if ( ! strncmp ( s , " tcp:// " , 6 ) )
{
//make sure that the rest of the address is a valid ip address (4 or 6)
2012-11-27 03:23:19 +00:00
if ( ! NET_StringToSockaddr ( s + 6 , 0 , & sadr , NULL , NULL ) )
2009-03-03 01:53:19 +00:00
{
a - > type = NA_INVALID ;
2008-11-09 22:29:28 +00:00
return false ;
2009-03-03 01:53:19 +00:00
}
2008-11-09 22:29:28 +00:00
SockadrToNetadr ( & sadr , a ) ;
if ( a - > type = = NA_IP )
{
a - > type = NA_TCP ;
return true ;
}
if ( a - > type = = NA_IPV6 )
{
a - > type = NA_TCPV6 ;
return true ;
}
return false ;
}
# endif
# ifdef IRCCONNECT
if ( ! strncmp ( s , " irc:// " , 6 ) )
{
char * at ;
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_IRC ;
s + = 6 ;
at = strchr ( s , ' @ ' ) ;
if ( at )
{
if ( at - s + 1 > = sizeof ( a - > address . irc . user ) )
return false ;
Q_strncpyz ( a - > address . irc . user , s , at - s + 1 ) ;
Q_strncpyz ( a - > address . irc . channel , at + 1 , sizeof ( a - > address . irc . channel ) ) ;
}
else
{
//just a user.
Q_strncpyz ( a - > address . irc . user , s , sizeof ( a - > address . irc . user ) ) ;
}
return true ;
}
# endif
2013-03-31 04:21:08 +00:00
# ifdef HAVE_NATPMP
if ( ! strncmp ( s , " natpmp:// " , 9 ) )
{
NET_PortToAdr ( NA_NATPMP , s + 9 , a ) ;
if ( a - > type = = NA_IP )
a - > type = NA_NATPMP ;
if ( a - > type ! = NA_NATPMP )
return false ;
return true ;
}
# endif
2008-11-09 22:29:28 +00:00
2013-03-12 23:03:04 +00:00
if ( ! NET_StringToSockaddr ( s , defaultport , & sadr , NULL , NULL ) )
2009-03-03 01:53:19 +00:00
{
a - > type = NA_INVALID ;
2004-08-21 01:25:48 +00:00
return false ;
2009-03-03 01:53:19 +00:00
}
2005-07-03 15:16:20 +00:00
2004-08-21 01:25:48 +00:00
SockadrToNetadr ( & sadr , a ) ;
return true ;
}
2006-05-22 22:51:14 +00:00
// NET_IntegerToMask: given a source address pointer, a mask address pointer, and
2011-05-15 13:23:13 +00:00
// desired number of bits, fills the mask pointer with given bits
2006-05-22 22:51:14 +00:00
// (bits < 0 will always fill all bits)
void NET_IntegerToMask ( netadr_t * a , netadr_t * amask , int bits )
{
2006-05-25 04:47:03 +00:00
unsigned int i ;
2006-05-22 22:51:14 +00:00
qbyte * n ;
memset ( amask , 0 , sizeof ( * amask ) ) ;
amask - > type = a - > type ;
if ( bits < 0 )
i = 8000 ; // fill all bits
else
i = bits ;
switch ( amask - > type )
{
2007-08-07 19:16:32 +00:00
case NA_INVALID :
break ;
case NA_IP :
case NA_BROADCAST_IP :
n = amask - > address . ip ;
if ( i > 32 )
i = 32 ;
2006-05-22 22:51:14 +00:00
for ( ; i > = 8 ; i - = 8 )
{
* n = 0xFF ;
n + + ;
}
// fill last bit
if ( i )
{
2006-05-25 04:47:03 +00:00
i = 8 - i ;
i = 255 - ( ( 1 < < i ) - 1 ) ;
2006-05-22 22:51:14 +00:00
* n = i ;
}
break ;
case NA_IPV6 :
case NA_BROADCAST_IP6 :
2007-08-07 19:16:32 +00:00
# ifdef IPPROTO_IPV6
2006-05-22 22:51:14 +00:00
n = amask - > address . ip6 ;
if ( i > 128 )
i = 128 ;
for ( ; i > = 8 ; i - = 8 )
{
* n = 0xFF ;
n + + ;
}
// fill last bit
if ( i )
{
2006-05-25 04:47:03 +00:00
i = 8 - i ;
i = 255 - ( ( 1 < < i ) - 1 ) ;
2006-05-22 22:51:14 +00:00
* n = i ;
}
# endif
2007-08-07 19:16:32 +00:00
break ;
case NA_IPX :
case NA_BROADCAST_IPX :
2011-05-15 13:23:13 +00:00
# ifdef USEIPX
2007-08-07 19:16:32 +00:00
n = amask - > address . ipx ;
if ( i > 80 )
i = 80 ;
2006-05-22 22:51:14 +00:00
for ( ; i > = 8 ; i - = 8 )
{
* n = 0xFF ;
n + + ;
}
// fill last bit
if ( i )
{
2006-05-25 04:47:03 +00:00
i = 8 - i ;
i = 255 - ( ( 1 < < i ) - 1 ) ;
2006-05-22 22:51:14 +00:00
* n = i ;
}
2007-08-07 19:16:32 +00:00
# endif
break ;
case NA_LOOPBACK :
2006-05-22 22:51:14 +00:00
break ;
2011-05-15 13:23:13 +00:00
// warning: enumeration value <20> NA_*<2A> not handled in switch
2012-07-14 17:25:21 +00:00
case NA_WEBSOCKET :
2011-05-15 13:23:13 +00:00
case NA_TCP :
case NA_TCPV6 :
case NA_IRC :
break ;
2006-05-22 22:51:14 +00:00
}
}
2006-05-25 04:47:03 +00:00
// ParsePartialIPv4: check string to see if it is a partial IPv4 address and
// return bits to mask and set netadr_t or 0 if not an address
2009-04-01 22:03:56 +00:00
int ParsePartialIPv4 ( const char * s , netadr_t * a )
2006-05-25 04:47:03 +00:00
{
2009-04-01 22:03:56 +00:00
const char * colon = NULL ;
2006-05-25 04:47:03 +00:00
char * address = a - > address . ip ;
int bits = 8 ;
if ( ! * s )
return 0 ;
memset ( a , 0 , sizeof ( * a ) ) ;
while ( * s )
{
if ( * s = = ' : ' )
{
if ( colon ) // only 1 colon
return 0 ;
colon = s + 1 ;
}
else if ( * s = = ' . ' )
{
if ( colon ) // no colons before periods (probably invalid anyway)
return 0 ;
else if ( bits > = 32 ) // only 32 bits in ipv4
2011-05-15 13:23:13 +00:00
return 0 ;
else if ( * ( s + 1 ) = = ' . ' )
2006-05-25 04:47:03 +00:00
return 0 ;
else if ( * ( s + 1 ) = = ' \0 ' )
break ; // don't add more bits to the mask for x.x., etc
bits + = 8 ;
address + + ;
}
else if ( * s > = ' 0 ' & & * s < = ' 9 ' )
* address = ( ( * address ) * 10 ) + ( * s - ' 0 ' ) ;
else
return 0 ; // invalid character
s + + ;
}
a - > type = NA_IP ;
if ( colon )
a - > port = atoi ( colon ) ;
return bits ;
}
2006-05-22 22:51:14 +00:00
// NET_StringToAdrMasked: extension to NET_StringToAdr to handle IP addresses
// with masks or integers representing the bit masks
2009-04-01 22:03:56 +00:00
qboolean NET_StringToAdrMasked ( const char * s , netadr_t * a , netadr_t * amask )
2006-05-22 22:51:14 +00:00
{
char t [ 64 ] ;
char * spoint ;
int i ;
spoint = strchr ( s , ' / ' ) ;
if ( spoint )
{
// we have a slash in the address so split and resolve separately
char * c ;
2006-05-25 04:47:03 +00:00
i = ( int ) ( spoint - s ) + 1 ;
if ( i > sizeof ( t ) )
2006-05-22 22:51:14 +00:00
i = sizeof ( t ) ;
Q_strncpyz ( t , s , i ) ;
2013-03-12 22:53:23 +00:00
if ( ! ParsePartialIPv4 ( t , a ) & & ! NET_StringToAdr ( t , 0 , a ) )
2006-05-22 22:51:14 +00:00
return false ;
spoint + + ;
2011-05-15 13:23:13 +00:00
2006-05-22 22:51:14 +00:00
c = spoint ;
if ( ! * c )
return false ;
while ( * c ) // check for non-numeric characters
{
if ( * c < ' 0 ' | | * c > ' 9 ' )
{
c = NULL ;
break ;
}
c + + ;
}
if ( c = = NULL ) // we have an address so resolve it and return
2013-03-12 22:53:23 +00:00
return ParsePartialIPv4 ( spoint , amask ) | | NET_StringToAdr ( spoint , 0 , amask ) ;
2006-05-22 22:51:14 +00:00
// otherwise generate mask for given bits
i = atoi ( spoint ) ;
NET_IntegerToMask ( a , amask , i ) ;
}
else
{
// we don't have a slash, resolve and fill with a full mask
2006-05-25 04:47:03 +00:00
i = ParsePartialIPv4 ( s , a ) ;
2013-03-12 22:53:23 +00:00
if ( ! i & & ! NET_StringToAdr ( s , 0 , a ) )
2006-05-22 22:51:14 +00:00
return false ;
memset ( amask , 0 , sizeof ( * amask ) ) ;
amask - > type = a - > type ;
2006-05-25 04:47:03 +00:00
if ( i )
NET_IntegerToMask ( a , amask , i ) ;
else
NET_IntegerToMask ( a , amask , - 1 ) ;
2006-05-22 22:51:14 +00:00
}
return true ;
}
// NET_CompareAdrMasked: given 3 addresses, 2 to compare with a complimentary mask,
// returns true or false if they match
qboolean NET_CompareAdrMasked ( netadr_t a , netadr_t b , netadr_t mask )
{
int i ;
2008-05-25 01:07:53 +00:00
//make sure the address being checked against matches the mask
if ( b . type ! = mask . type )
2006-05-22 22:51:14 +00:00
return false ;
// check port if both are non-zero
if ( a . port & & b . port & & a . port ! = b . port )
return false ;
2008-05-25 01:07:53 +00:00
// check to make sure all types match
if ( a . type ! = b . type )
{
2011-10-27 16:16:29 +00:00
if ( a . type = = NA_IP & & b . type = = NA_IPV6 & & mask . type = = NA_IP )
2008-05-25 01:07:53 +00:00
{
2011-10-27 16:16:29 +00:00
for ( i = 0 ; i < 10 ; i + + )
if ( b . address . ip6 [ i ] ! = 0 )
return false ; //only matches if they're 0s, otherwise its not an ipv4 address there
2008-05-25 01:07:53 +00:00
for ( ; i < 12 ; i + + )
2011-10-27 16:16:29 +00:00
if ( b . address . ip6 [ i ] ! = 0xff & & b . address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
return false ; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there
for ( i = 0 ; i < 4 ; i + + )
2008-05-25 01:07:53 +00:00
{
2011-10-27 16:16:29 +00:00
if ( ( a . address . ip [ i ] & mask . address . ip [ i ] ) ! = ( b . address . ip6 [ 12 + i ] & mask . address . ip [ i ] ) )
return false ; //mask doesn't match
2008-05-25 01:07:53 +00:00
}
2011-10-27 16:16:29 +00:00
return true ; //its an ipv4 address in there, the mask matched the whole way through
2008-05-25 01:07:53 +00:00
}
2011-10-27 16:16:29 +00:00
if ( a . type = = NA_IPV6 & & b . type = = NA_IP & & mask . type = = NA_IP )
2008-05-25 01:07:53 +00:00
{
for ( i = 0 ; i < 10 ; i + + )
2011-01-29 21:01:40 +00:00
if ( a . address . ip6 [ i ] ! = 0 )
2008-05-25 01:07:53 +00:00
return false ; //only matches if they're 0s, otherwise its not an ipv4 address there
for ( ; i < 12 ; i + + )
2011-01-29 21:01:40 +00:00
if ( a . address . ip6 [ i ] ! = 0xff & & a . address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
return false ; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there
2008-05-25 01:07:53 +00:00
for ( i = 0 ; i < 4 ; i + + )
{
if ( ( a . address . ip6 [ 12 + i ] & mask . address . ip [ i ] ) ! = ( b . address . ip [ i ] & mask . address . ip [ i ] ) )
return false ; //mask doesn't match
}
return true ; //its an ipv4 address in there, the mask matched the whole way through
}
return false ;
}
2006-05-22 22:51:14 +00:00
// match on protocol type and compare address
switch ( a . type )
{
case NA_LOOPBACK :
return true ;
case NA_BROADCAST_IP :
case NA_IP :
for ( i = 0 ; i < 4 ; i + + )
{
if ( ( a . address . ip [ i ] & mask . address . ip [ i ] ) ! = ( b . address . ip [ i ] & mask . address . ip [ i ] ) )
return false ;
}
break ;
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
for ( i = 0 ; i < 16 ; i + + )
{
if ( ( a . address . ip6 [ i ] & mask . address . ip6 [ i ] ) ! = ( b . address . ip6 [ i ] & mask . address . ip6 [ i ] ) )
return false ;
}
break ;
# endif
# ifdef USEIPX
case NA_BROADCAST_IPX :
case NA_IPX :
for ( i = 0 ; i < 10 ; i + + )
{
if ( ( a . address . ipx [ i ] & mask . address . ipx [ i ] ) ! = ( b . address . ipx [ i ] & mask . address . ipx [ i ] ) )
return false ;
}
break ;
# endif
2008-11-09 22:29:28 +00:00
# ifdef IRCCONNECT
case NA_IRC :
2011-05-15 13:23:13 +00:00
//masks are not supported, match explicitly
2008-11-09 22:29:28 +00:00
if ( strcmp ( a . address . irc . user , b . address . irc . user ) )
return false ;
break ;
# endif
2006-05-22 22:51:14 +00:00
default :
return false ; // invalid protocol
}
return true ; // all checks passed
}
// UniformMaskedBits: counts number of bits in an assumed uniform mask, returns
// -1 if not uniform
int UniformMaskedBits ( netadr_t mask )
{
int bits ;
int b ;
2006-05-25 04:47:03 +00:00
unsigned int bs ;
2006-05-22 22:51:14 +00:00
qboolean bitenc = false ;
switch ( mask . type )
{
case NA_BROADCAST_IP :
case NA_IP :
bits = 32 ;
for ( b = 3 ; b > = 0 ; b - - )
{
if ( mask . address . ip [ b ] = = 0xFF )
bitenc = true ;
else if ( mask . address . ip [ b ] )
{
2006-05-25 04:47:03 +00:00
bs = ( ~ mask . address . ip [ b ] ) & 0xFF ;
2006-05-22 22:51:14 +00:00
while ( bs )
{
if ( bs & 1 )
{
bits - = 1 ;
if ( bitenc )
return - 1 ;
}
else
bitenc = true ;
bs > > = 1 ;
}
}
else if ( bitenc )
return - 1 ;
else
bits - = 8 ;
}
break ;
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
bits = 128 ;
for ( b = 15 ; b > = 0 ; b - - )
{
if ( mask . address . ip6 [ b ] = = 0xFF )
bitenc = true ;
else if ( mask . address . ip6 [ b ] )
{
2006-05-25 04:47:03 +00:00
bs = ( ~ mask . address . ip6 [ b ] ) & 0xFF ;
2006-05-22 22:51:14 +00:00
while ( bs )
{
if ( bs & 1 )
{
bits - = 1 ;
if ( bitenc )
return - 1 ;
}
else
bitenc = true ;
bs > > = 1 ;
}
}
else if ( bitenc )
return - 1 ;
else
bits - = 8 ;
}
break ;
# endif
# ifdef USEIPX
case NA_BROADCAST_IPX :
case NA_IPX :
bits = 80 ;
for ( b = 9 ; b > = 0 ; b - - )
{
if ( mask . address . ipx [ b ] = = 0xFF )
bitenc = true ;
else if ( mask . address . ipx [ b ] )
{
2006-05-25 04:47:03 +00:00
bs = ( ~ mask . address . ipx [ b ] ) & 0xFF ;
2006-05-22 22:51:14 +00:00
while ( bs )
{
if ( bs & 1 )
{
bits - = 1 ;
if ( bitenc )
return - 1 ;
}
else
bitenc = true ;
bs > > = 1 ;
}
}
else if ( bitenc )
return - 1 ;
else
bits - = 8 ;
}
break ;
# endif
default :
return - 1 ; // invalid protocol
}
return bits ; // all checks passed
}
2008-06-08 14:37:57 +00:00
char * NET_AdrToStringMasked ( char * s , int len , netadr_t a , netadr_t amask )
2006-05-22 22:51:14 +00:00
{
int i ;
2008-06-08 14:37:57 +00:00
char adr [ MAX_ADR_SIZE ] , mask [ MAX_ADR_SIZE ] ;
2006-05-22 22:51:14 +00:00
i = UniformMaskedBits ( amask ) ;
if ( i > = 0 )
2008-06-08 20:20:11 +00:00
snprintf ( s , len , " %s/%i " , NET_AdrToString ( adr , sizeof ( adr ) , a ) , i ) ;
2006-05-22 22:51:14 +00:00
else
2008-06-08 20:20:11 +00:00
snprintf ( s , len , " %s/%s " , NET_AdrToString ( adr , sizeof ( adr ) , a ) , NET_AdrToString ( mask , sizeof ( mask ) , amask ) ) ;
2006-05-22 22:51:14 +00:00
return s ;
}
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 ) ;
2011-12-23 03:12:29 +00:00
if ( ( newsocket = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ) ) = = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
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
2013-03-31 04:21:08 +00:00
# if !defined(CLIENTONLY) && !defined(SERVERONLY)
qboolean NET_GetLoopPacket ( int sock , netadr_t * from , sizebuf_t * message )
2004-08-21 01:25:48 +00:00
{
int i ;
loopback_t * loop ;
2013-03-31 04:21:08 +00:00
sock & = 1 ;
2004-08-21 01:25:48 +00:00
loop = & loopbacks [ sock ] ;
if ( loop - > send - loop - > get > MAX_LOOPBACK )
2012-05-09 15:30:53 +00:00
{
extern cvar_t showdrop ;
if ( showdrop . ival )
Con_Printf ( " loopback dropping %i packets \n " , ( loop - > send - MAX_LOOPBACK ) - loop - > get ) ;
2004-08-21 01:25:48 +00:00
loop - > get = loop - > send - MAX_LOOPBACK ;
2012-05-09 15:30:53 +00:00
}
2004-08-21 01:25:48 +00:00
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 ;
}
2013-03-31 04:21:08 +00:00
void NET_SendLoopPacket ( int sock , int length , void * data , netadr_t to )
2004-08-21 01:25:48 +00:00
{
int i ;
loopback_t * loop ;
2013-03-31 04:21:08 +00:00
sock & = 1 ;
2004-08-21 01:25:48 +00:00
loop = & loopbacks [ sock ^ 1 ] ;
2013-03-12 23:24:15 +00:00
if ( length > sizeof ( loop - > msgs [ i ] . data ) )
{
Con_Printf ( " NET_SendLoopPacket: Loopback buffer is too small " ) ;
return ;
}
2004-08-21 01:25:48 +00:00
i = loop - > send & ( MAX_LOOPBACK - 1 ) ;
loop - > send + + ;
memcpy ( loop - > msgs [ i ] . data , data , length ) ;
loop - > msgs [ i ] . datalen = length ;
}
2013-03-31 04:21:08 +00:00
int FTENET_Loop_GetLocalAddress ( ftenet_generic_connection_t * con , netadr_t * out , int adrnum )
{
if ( adrnum = = 0 )
{
out - > type = NA_LOOPBACK ;
out - > port = con - > thesocket + 1 ;
}
return 1 ;
}
2008-11-09 22:29:28 +00:00
2013-03-31 04:21:08 +00:00
qboolean FTENET_Loop_GetPacket ( ftenet_generic_connection_t * con )
{
return NET_GetLoopPacket ( con - > thesocket , & net_from , & net_message ) ;
}
2008-11-09 22:29:28 +00:00
2013-03-31 04:21:08 +00:00
qboolean FTENET_Loop_SendPacket ( ftenet_generic_connection_t * con , int length , void * data , netadr_t to )
{
if ( to . type = = NA_LOOPBACK )
{
NET_SendLoopPacket ( con - > thesocket , length , data , to ) ;
return true ;
}
return false ;
}
void FTENET_Loop_Close ( ftenet_generic_connection_t * con )
{
int sock = con - > thesocket ;
sock & = 1 ;
loopbacks [ sock ] . inited = false ;
Z_Free ( con ) ;
}
static ftenet_generic_connection_t * FTENET_Loop_EstablishConnection ( qboolean isserver , const char * address )
{
ftenet_generic_connection_t * newcon ;
int sock ;
for ( sock = 0 ; sock < 2 ; sock + + )
if ( ! loopbacks [ sock ] . inited )
break ;
if ( sock = = 2 )
return NULL ;
newcon = Z_Malloc ( sizeof ( * newcon ) ) ;
if ( newcon )
{
loopbacks [ sock ] . inited = true ;
newcon - > GetLocalAddress = FTENET_Loop_GetLocalAddress ;
newcon - > GetPacket = FTENET_Loop_GetPacket ;
newcon - > SendPacket = FTENET_Loop_SendPacket ;
newcon - > Close = FTENET_Loop_Close ;
newcon - > islisten = isserver ;
newcon - > addrtype [ 0 ] = NA_LOOPBACK ;
newcon - > addrtype [ 1 ] = NA_INVALID ;
newcon - > thesocket = sock ;
}
return newcon ;
}
# endif
//=============================================================================
2008-11-09 22:29:28 +00:00
# define MAX_CONNECTIONS 8
2013-03-31 04:21:08 +00:00
typedef struct ftenet_connections_s
{
2008-11-09 22:29:28 +00:00
qboolean islisten ;
ftenet_generic_connection_t * conn [ MAX_CONNECTIONS ] ;
} ftenet_connections_t ;
ftenet_connections_t * FTENET_CreateCollection ( qboolean listen )
2006-05-07 05:31:01 +00:00
{
2008-11-09 22:29:28 +00:00
ftenet_connections_t * col ;
col = Z_Malloc ( sizeof ( * col ) ) ;
col - > islisten = listen ;
return col ;
}
2013-03-31 04:21:08 +00:00
static ftenet_generic_connection_t * FTENET_Loop_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_UDP4_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_UDP6_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_TCP4Connect_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_TCP6Connect_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_IPX_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_WebSocket_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_IRCConnect_EstablishConnection ( qboolean isserver , const char * address ) ;
static ftenet_generic_connection_t * FTENET_NATPMP_EstablishConnection ( qboolean isserver , const char * address ) ;
# ifdef HAVE_NATPMP
typedef struct
{
ftenet_generic_connection_t pub ;
ftenet_connections_t * col ;
netadr_t reqpmpaddr ;
netadr_t pmpaddr ;
netadr_t natadr ;
unsigned int refreshtime ;
} pmpcon_t ;
int FTENET_NATPMP_GetLocalAddress ( struct ftenet_generic_connection_s * con , netadr_t * local , int adridx ) ;
static qboolean NET_Was_NATPMP ( ftenet_connections_t * collection )
{
pmpcon_t * pmp ;
struct
{
qbyte ver ; qbyte op ; short resultcode ;
int age ;
union
{
struct
{
short privport ; short pubport ;
int mapping_expectancy ;
} ;
qbyte ipv4 [ 4 ] ;
} ;
} * pmpreqrep ;
int i ;
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( ! collection - > conn [ i ] )
continue ;
if ( collection - > conn [ i ] - > GetLocalAddress = = FTENET_NATPMP_GetLocalAddress )
{
pmp = ( pmpcon_t * ) collection - > conn [ i ] ;
if ( NET_CompareAdr ( pmp - > pmpaddr , net_from ) )
{
pmpreqrep = ( void * ) net_message . data ;
if ( pmpreqrep - > ver ! = 0 )
return false ;
if ( net_message . cursize = = 12 & & pmpreqrep - > op = = 128 )
{
char adrbuf [ 256 ] ;
pmp - > natadr . type = NA_IP ;
pmp - > natadr . port = 0 ;
memcpy ( pmp - > natadr . address . ip , pmpreqrep - > ipv4 , sizeof ( pmp - > natadr . address . ip ) ) ;
NET_AdrToString ( adrbuf , sizeof ( adrbuf ) , pmp - > natadr ) ;
// Con_Printf("Public ip is %s\n", adrbuf);
return true ;
}
if ( net_message . cursize = = 16 & & pmpreqrep - > op = = 129 )
{
switch ( BigShort ( pmpreqrep - > resultcode ) )
{
case 0 :
break ;
case 1 :
Con_Printf ( " NAT-PMP: unsupported version \n " ) ;
return true ;
case 2 :
Con_Printf ( " NAT-PMP: refused - please reconfigure router \n " ) ;
return true ;
case 3 :
Con_Printf ( " NAT-PMP: network failure \n " ) ;
return true ;
case 4 :
Con_Printf ( " NAT-PMP: out of resources \n " ) ;
return true ;
case 5 :
Con_Printf ( " NAT-PMP: unsupported opcode \n " ) ;
return true ;
default :
return false ;
}
// Con_Printf("Local port %u publically available on port %u\n", (unsigned short)BigShort(pmpreqrep->privport), (unsigned short)BigShort(pmpreqrep->pubport));
pmp - > natadr . port = pmpreqrep - > pubport ;
return true ;
}
return false ;
}
}
}
return false ;
}
static void FTENET_NATPMP_Refresh ( pmpcon_t * pmp , short oldport , ftenet_connections_t * collection )
{
int i ;
int adrno , adrcount = 1 ;
netadr_t adr ;
struct
{
qbyte ver ; qbyte op ; short reserved1 ;
short privport ; short pubport ;
int mapping_expectancy ;
} pmpreqmsg ;
pmpreqmsg . ver = 0 ;
pmpreqmsg . op = 1 ;
pmpreqmsg . reserved1 = BigShort ( 0 ) ;
pmpreqmsg . privport = BigShort ( 0 ) ;
pmpreqmsg . pubport = BigShort ( 0 ) ;
pmpreqmsg . mapping_expectancy = BigLong ( 60 * 5 ) ;
if ( ! collection )
return ;
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( ! collection - > conn [ i ] )
continue ;
if ( collection - > conn [ i ] - > GetLocalAddress & & collection - > conn [ i ] - > GetLocalAddress ! = FTENET_NATPMP_GetLocalAddress )
{
for ( adrno = 0 , adrcount = 1 ; ( adrcount = collection - > conn [ i ] - > GetLocalAddress ( collection - > conn [ i ] , & adr , adrno ) ) & & adrno < adrcount ; adrno + + )
{
// Con_Printf("net address (%s): %s\n", collection->conn[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), adr));
//unipv6ify it if its a hybrid socket.
if ( adr . type = = NA_IPV6 & &
! * ( int * ) & adr . address . ip6 [ 0 ] & &
! * ( int * ) & adr . address . ip6 [ 4 ] & &
! * ( short * ) & adr . address . ip6 [ 8 ] & &
* ( short * ) & adr . address . ip6 [ 10 ] = = ( short ) 0xffff & &
! * ( int * ) & adr . address . ip6 [ 12 ] )
{
* ( int * ) adr . address . ip = * ( int * ) & adr . address . ip6 [ 12 ] ;
adr . type = NA_IP ;
}
if ( adr . type = = NA_IP )
{
if ( adr . address . ip [ 0 ] = = 127 ) //yes. loopback has a lot of ip addresses. wasteful but whatever.
continue ;
//assume a netmask of 255.255.255.0
adr . address . ip [ 3 ] = 1 ;
}
// else if (adr.type == NA_IPV6)
// {
// }
else
continue ;
pmpreqmsg . privport = adr . port ;
pmpreqmsg . pubport = oldport ? oldport : adr . port ;
if ( * ( int * ) pmp - > reqpmpaddr . address . ip = = INADDR_ANY )
{
pmp - > pmpaddr = adr ;
pmp - > pmpaddr . port = pmp - > reqpmpaddr . port ;
}
else
pmp - > pmpaddr = pmp - > reqpmpaddr ;
//get the public ip.
pmpreqmsg . op = 0 ;
NET_SendPacket ( NS_SERVER , 2 , & pmpreqmsg , pmp - > pmpaddr ) ;
//open the firewall/nat.
pmpreqmsg . op = 1 ;
NET_SendPacket ( NS_SERVER , sizeof ( pmpreqmsg ) , & pmpreqmsg , pmp - > pmpaddr ) ;
}
}
}
}
# define PMP_POLL_TIME (1000*30) //every 30 seconds
int FTENET_NATPMP_GetLocalAddress ( struct ftenet_generic_connection_s * con , netadr_t * local , int adridx )
{
pmpcon_t * pmp = ( pmpcon_t * ) con ;
local - > type = NA_INVALID ;
if ( adridx = = 0 )
* local = pmp - > natadr ;
return ( pmp - > natadr . type ! = NA_INVALID ) & & ( pmp - > natadr . port ! = 0 ) ;
}
qboolean FTENET_NATPMP_GetPacket ( struct ftenet_generic_connection_s * con )
{
pmpcon_t * pmp = ( pmpcon_t * ) con ;
unsigned int now = Sys_Milliseconds ( ) ;
if ( now - pmp - > refreshtime > PMP_POLL_TIME ) //weird logic to cope with wrapping
{
pmp - > refreshtime = now ;
FTENET_NATPMP_Refresh ( pmp , pmp - > natadr . port , pmp - > col ) ;
}
return false ;
}
qboolean FTENET_NATPMP_SendPacket ( struct ftenet_generic_connection_s * con , int length , void * data , netadr_t to )
{
return false ;
}
qboolean FTENET_NATPMP_Close ( struct ftenet_generic_connection_s * con )
{
//FIXME: we should send a packet to close the port
Z_Free ( con ) ;
return true ;
}
ftenet_generic_connection_t * FTENET_NATPMP_EstablishConnection ( qboolean isserver , const char * address )
{
pmpcon_t * pmp ;
netadr_t pmpadr ;
NET_PortToAdr ( NA_IP , address , & pmpadr ) ;
if ( pmpadr . type = = NA_NATPMP )
pmpadr . type = NA_IP ;
if ( pmpadr . type ! = NA_IP )
return NULL ;
pmp = Z_Malloc ( sizeof ( * pmp ) ) ;
pmp - > col = svs . sockets ;
Q_strncpyz ( pmp - > pub . name , " natpmp " , sizeof ( pmp - > pub . name ) ) ;
pmp - > reqpmpaddr = pmpadr ;
pmp - > pub . GetLocalAddress = FTENET_NATPMP_GetLocalAddress ;
pmp - > pub . GetPacket = FTENET_NATPMP_GetPacket ;
//qboolean (*ChangeLocalAddress)(struct ftenet_generic_connection_s *con, const char *newaddress);
pmp - > pub . SendPacket = FTENET_NATPMP_SendPacket ;
pmp - > pub . Close = FTENET_NATPMP_Close ;
pmp - > pub . thesocket = INVALID_SOCKET ;
pmp - > refreshtime = Sys_Milliseconds ( ) + PMP_POLL_TIME * 64 ;
return & pmp - > pub ;
}
# endif
2006-05-09 00:02:05 +00:00
2013-03-31 04:21:08 +00:00
qboolean FTENET_AddToCollection ( ftenet_connections_t * col , const char * name , const char * address , netadrtype_t addrtype , qboolean islisten )
2008-11-09 22:29:28 +00:00
{
2012-01-01 06:25:51 +00:00
int count = 0 ;
2008-11-09 22:29:28 +00:00
int i ;
2013-03-31 04:21:08 +00:00
netadr_t adr ;
ftenet_generic_connection_t * ( * establish ) ( qboolean isserver , const char * address ) = NULL ;
2008-11-09 22:29:28 +00:00
if ( ! col )
return false ;
2013-03-31 04:21:08 +00:00
if ( ! address | | ! * address )
adr . type = NA_INVALID ;
else if ( islisten )
NET_PortToAdr ( addrtype , address , & adr ) ;
else
NET_StringToAdr ( address , 0 , & adr ) ;
switch ( adr . type )
{
default : establish = NULL ; break ;
# ifdef HAVE_NATPMP
case NA_NATPMP : establish = FTENET_NATPMP_EstablishConnection ; break ;
# endif
# if !defined(CLIENTONLY) && !defined(SERVERONLY)
case NA_LOOPBACK : establish = FTENET_Loop_EstablishConnection ; break ;
# endif
# ifdef HAVE_IPV4
case NA_IP : establish = FTENET_UDP4_EstablishConnection ; break ;
# endif
# ifdef IPPROTO_IPV6
case NA_IPV6 : establish = FTENET_UDP6_EstablishConnection ; break ;
# endif
# ifdef USEIPX
case NA_IPX : establish = FTENET_IPX_EstablishConnection ; break ;
# endif
case NA_WEBSOCKET :
# ifdef HAVE_WEBSOCKCL
if ( ! islisten )
establish = FTENET_WebSocket_EstablishConnection ;
# endif
# ifdef TCPCONNECT
establish = FTENET_TCP4Connect_EstablishConnection ;
# endif
break ;
# ifdef IRCCONNECT
case NA_IRC : establish = FTENET_IRCConnect_EstablishConnection ; break ;
# endif
# ifdef TCPCONNECT
case NA_TCP : establish = FTENET_TCP4Connect_EstablishConnection ; break ;
# endif
# if defined(TCPCONNECT) && defined(IPPROTO_IPV6)
case NA_TCPV6 : establish = FTENET_TCP6Connect_EstablishConnection ; break ;
# endif
}
2008-11-09 22:29:28 +00:00
if ( name )
2006-05-07 05:31:01 +00:00
{
2008-11-09 22:29:28 +00:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
2006-05-09 00:02:05 +00:00
{
2008-11-09 22:29:28 +00:00
if ( col - > conn [ i ] )
if ( col - > conn [ i ] - > name & & ! strcmp ( col - > conn [ i ] - > name , name ) )
{
if ( address & & * address )
if ( col - > conn [ i ] - > ChangeLocalAddress )
{
if ( col - > conn [ i ] - > ChangeLocalAddress ( col - > conn [ i ] , address ) )
return true ;
}
2011-05-15 13:23:13 +00:00
2008-11-09 22:29:28 +00:00
col - > conn [ i ] - > Close ( col - > conn [ i ] ) ;
col - > conn [ i ] = NULL ;
}
2006-05-09 00:02:05 +00:00
}
}
2013-03-31 04:21:08 +00:00
if ( address & & * address & & establish )
2006-05-07 05:31:01 +00:00
{
2012-01-01 06:25:51 +00:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
2006-05-09 00:02:05 +00:00
{
2008-11-09 22:29:28 +00:00
if ( ! col - > conn [ i ] )
2012-01-01 06:25:51 +00:00
{
address = COM_Parse ( address ) ;
col - > conn [ i ] = establish ( islisten , com_token ) ;
if ( ! col - > conn [ i ] )
break ;
2013-03-31 04:21:08 +00:00
if ( name )
Q_strncpyz ( col - > conn [ i ] - > name , name , sizeof ( col - > conn [ i ] - > name ) ) ;
2012-01-01 06:25:51 +00:00
count + + ;
if ( address & & * address )
continue ;
break ;
}
2006-05-09 00:02:05 +00:00
}
}
2012-01-01 06:25:51 +00:00
return count > 0 ;
2006-05-09 00:02:05 +00:00
}
2008-11-09 22:29:28 +00:00
void FTENET_CloseCollection ( ftenet_connections_t * col )
2006-05-09 00:02:05 +00:00
{
2008-12-02 21:54:10 +00:00
int i ;
2008-12-03 01:57:02 +00:00
if ( ! col )
return ;
2008-12-02 21:54:10 +00:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( col - > conn [ i ] )
{
col - > conn [ i ] - > Close ( col - > conn [ i ] ) ;
}
}
2008-11-09 22:29:28 +00:00
Z_Free ( col ) ;
}
2006-05-09 00:02:05 +00:00
2008-11-09 22:29:28 +00:00
void FTENET_Generic_Close ( ftenet_generic_connection_t * con )
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_PACKET
2008-11-09 22:29:28 +00:00
if ( con - > thesocket ! = INVALID_SOCKET )
closesocket ( con - > thesocket ) ;
2012-04-09 19:12:12 +00:00
# endif
2008-11-09 22:29:28 +00:00
Z_Free ( con ) ;
}
int FTENET_Generic_GetLocalAddress ( ftenet_generic_connection_t * con , netadr_t * out , int count )
2004-08-21 01:25:48 +00:00
{
2012-04-09 19:12:12 +00:00
# ifndef HAVE_PACKET
return 0 ;
# else
2004-08-21 01:25:48 +00:00
struct sockaddr_qstorage from ;
2008-11-09 22:29:28 +00:00
int fromsize = sizeof ( from ) ;
netadr_t adr ;
char adrs [ MAX_ADR_SIZE ] ;
int b ;
int idx = 0 ;
2004-08-21 01:25:48 +00:00
2008-11-09 22:29:28 +00:00
if ( getsockname ( con - > thesocket , ( struct sockaddr * ) & from , & fromsize ) ! = - 1 )
2004-08-21 01:25:48 +00:00
{
2008-11-09 22:29:28 +00:00
memset ( & adr , 0 , sizeof ( adr ) ) ;
SockadrToNetadr ( & from , & adr ) ;
2004-08-21 01:25:48 +00:00
2012-10-18 15:20:00 +00:00
# ifdef USE_GETHOSTNAME_LOCALLISTING
2011-12-05 15:23:40 +00:00
if ( adr . type = = NA_IPV6 & &
! * ( int * ) & adr . address . ip6 [ 0 ] & &
! * ( int * ) & adr . address . ip6 [ 4 ] & &
! * ( short * ) & adr . address . ip6 [ 8 ] & &
* ( short * ) & adr . address . ip6 [ 10 ] = = ( short ) 0xffff & &
! * ( int * ) & adr . address . ip6 [ 12 ] )
{
/*ipv4-mapped address ANY, pretend we read blank*/
b = sizeof ( adr . address ) ;
}
else
{
for ( b = 0 ; b < sizeof ( adr . address ) ; b + + )
if ( ( ( unsigned char * ) & adr . address ) [ b ] ! = 0 )
break ;
}
2008-11-09 22:29:28 +00:00
if ( b = = sizeof ( adr . address ) )
2004-08-21 01:25:48 +00:00
{
2008-11-09 22:29:28 +00:00
gethostname ( adrs , sizeof ( adrs ) ) ;
2011-12-05 15:23:40 +00:00
# ifdef IPPROTO_IPV6
if ( pgetaddrinfo )
2004-08-21 01:25:48 +00:00
{
2011-12-05 15:23:40 +00:00
struct addrinfo hints , * result , * itr ;
memset ( & hints , 0 , sizeof ( struct addrinfo ) ) ;
2012-01-01 06:25:51 +00:00
hints . ai_family = 0 ; /* Allow IPv4 or IPv6 */
2011-12-05 15:23:40 +00:00
hints . ai_socktype = SOCK_DGRAM ; /* Datagram socket */
hints . ai_flags = 0 ;
hints . ai_protocol = 0 ; /* Any protocol */
if ( pgetaddrinfo ( adrs , NULL , & hints , & result ) ! = 0 )
2008-11-09 22:29:28 +00:00
{
if ( idx + + = = count )
* out = adr ;
}
2011-12-05 15:23:40 +00:00
else
2004-08-21 01:25:48 +00:00
{
2011-12-05 15:23:40 +00:00
for ( itr = result ; itr ; itr = itr - > ai_next )
{
2012-01-01 06:25:51 +00:00
if ( itr - > ai_addr - > sa_family ! = ( ( struct sockaddr_in * ) & from ) - > sin_family )
{
# ifdef IPV6_V6ONLY
if ( ( ( struct sockaddr_in * ) & from ) - > sin_family = = AF_INET6 & & itr - > ai_addr - > sa_family = = AF_INET )
{
int ipv6only = true ;
int optlen = sizeof ( ipv6only ) ;
getsockopt ( con - > thesocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( char * ) & ipv6only , & optlen ) ;
if ( ipv6only )
continue ;
}
else
# endif
continue ;
}
2012-03-19 06:30:41 +00:00
if ( itr - > ai_addr - > sa_family = = AF_INET
| | itr - > ai_addr - > sa_family = = AF_INET6
# ifdef USEIPX
| | itr - > ai_addr - > sa_family = = AF_IPX
# endif
)
2011-12-05 15:23:40 +00:00
if ( idx + + = = count )
{
SockadrToNetadr ( ( struct sockaddr_qstorage * ) itr - > ai_addr , out ) ;
out - > port = ( ( struct sockaddr_in * ) & from ) - > sin_port ;
}
}
pfreeaddrinfo ( result ) ;
/*if none found, fill in the 0.0.0.0 or whatever*/
if ( ! idx )
{
idx + + ;
2008-11-09 22:29:28 +00:00
* out = adr ;
2011-12-05 15:23:40 +00:00
}
2004-08-21 01:25:48 +00:00
}
}
2011-12-05 15:23:40 +00:00
else
2008-12-01 02:10:35 +00:00
# endif
2008-11-09 22:29:28 +00:00
{
2013-03-12 22:47:42 +00:00
struct hostent * h ;
2011-12-05 15:23:40 +00:00
h = gethostbyname ( adrs ) ;
b = 0 ;
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2011-12-05 15:23:40 +00:00
if ( h & & h - > h_addrtype = = AF_INET )
{
for ( b = 0 ; h - > h_addr_list [ b ] ; b + + )
{
( ( struct sockaddr_in * ) & from ) - > sin_family = AF_INET ;
memcpy ( & ( ( struct sockaddr_in * ) & from ) - > sin_addr , h - > h_addr_list [ b ] , sizeof ( ( ( struct sockaddr_in * ) & from ) - > sin_addr ) ) ;
SockadrToNetadr ( & from , & adr ) ;
if ( idx + + = = count )
* out = adr ;
}
}
2012-04-09 19:12:12 +00:00
# endif
# ifdef IPPROTO_IPV6
if ( h & & h - > h_addrtype = = AF_INET6 )
2011-12-05 15:23:40 +00:00
{
for ( b = 0 ; h - > h_addr_list [ b ] ; b + + )
{
( ( struct sockaddr_in * ) & from ) - > sin_family = AF_INET6 ;
memcpy ( & ( ( struct sockaddr_in6 * ) & from ) - > sin6_addr , h - > h_addr_list [ b ] , sizeof ( ( ( struct sockaddr_in6 * ) & from ) - > sin6_addr ) ) ;
SockadrToNetadr ( & from , & adr ) ;
if ( idx + + = = count )
* out = adr ;
}
}
2012-04-09 19:12:12 +00:00
# endif
2011-12-05 15:23:40 +00:00
if ( b = = 0 )
{
if ( idx + + = = count )
* out = adr ;
}
2008-11-09 22:29:28 +00:00
}
2004-08-21 01:25:48 +00:00
}
2008-11-09 22:29:28 +00:00
else
2012-10-18 15:20:00 +00:00
# endif
2004-08-21 01:25:48 +00:00
{
2012-10-18 15:20:00 +00:00
if ( adr . type = = NA_IPV6 & &
! * ( int * ) & adr . address . ip6 [ 0 ] & &
! * ( int * ) & adr . address . ip6 [ 4 ] & &
! * ( int * ) & adr . address . ip6 [ 8 ] & &
! * ( int * ) & adr . address . ip6 [ 12 ] )
{
if ( idx + + = = count )
{
* out = adr ;
out - > type = NA_IP ;
}
}
2008-11-09 22:29:28 +00:00
if ( idx + + = = count )
* out = adr ;
2004-08-21 01:25:48 +00:00
}
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
return idx ;
2012-04-09 19:12:12 +00:00
# endif
2008-11-09 22:29:28 +00:00
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
qboolean FTENET_Generic_GetPacket ( ftenet_generic_connection_t * con )
{
2012-04-09 19:12:12 +00:00
# ifndef HAVE_PACKET
return false ;
# else
2008-11-09 22:29:28 +00:00
struct sockaddr_qstorage from ;
int fromlen ;
int ret ;
int err ;
char adr [ MAX_ADR_SIZE ] ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
if ( con - > thesocket = = INVALID_SOCKET )
return false ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
fromlen = sizeof ( from ) ;
ret = recvfrom ( con - > thesocket , ( char * ) net_message_buffer , sizeof ( net_message_buffer ) , 0 , ( struct sockaddr * ) & from , & fromlen ) ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
if ( ret = = - 1 )
{
err = qerrno ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
if ( err = = EWOULDBLOCK )
return false ;
if ( err = = EMSGSIZE )
{
SockadrToNetadr ( & from , & net_from ) ;
Con_TPrintf ( TL_OVERSIZEPACKETFROM ,
NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
return false ;
}
if ( err = = ECONNABORTED | | err = = ECONNRESET )
{
Con_TPrintf ( TL_CONNECTIONLOSTORABORTED ) ; //server died/connection lost.
# ifndef SERVERONLY
if ( cls . state ! = ca_disconnected & & ! con - > islisten )
2005-11-30 01:20:53 +00:00
{
2008-11-09 22:29:28 +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 " ) ;
2005-11-30 01:20:53 +00:00
return false ;
}
# endif
2008-11-09 22:29:28 +00:00
return false ;
2005-11-30 01:20:53 +00:00
}
2008-11-09 22:29:28 +00:00
Con_Printf ( " NET_GetPacket: Error (%i): %s \n " , err , strerror ( err ) ) ;
return false ;
}
SockadrToNetadr ( & from , & net_from ) ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
net_message . cursize = ret ;
if ( net_message . cursize = = sizeof ( net_message_buffer ) )
{
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
return false ;
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
return true ;
2012-04-09 19:12:12 +00:00
# endif
2008-11-09 22:29:28 +00:00
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
qboolean FTENET_Generic_SendPacket ( ftenet_generic_connection_t * con , int length , void * data , netadr_t to )
{
2012-04-09 19:12:12 +00:00
# ifndef HAVE_PACKET
return false ;
# else
2008-11-09 22:29:28 +00:00
struct sockaddr_qstorage addr ;
int size ;
int ret ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
for ( size = 0 ; size < FTENET_ADDRTYPES ; size + + )
if ( to . type = = con - > addrtype [ size ] )
break ;
if ( size = = FTENET_ADDRTYPES )
return false ;
2005-11-30 01:20:53 +00:00
2011-12-05 15:23:40 +00:00
# ifdef IPPROTO_IPV6
/*special code to handle sending to hybrid sockets*/
if ( con - > addrtype [ 1 ] = = NA_IPV6 & & to . type = = NA_IP )
{
memset ( & addr , 0 , sizeof ( struct sockaddr_in6 ) ) ;
( ( struct sockaddr_in6 * ) & addr ) - > sin6_family = AF_INET6 ;
* ( short * ) & ( ( struct sockaddr_in6 * ) & addr ) - > sin6_addr . s6_addr [ 10 ] = 0xffff ;
* ( int * ) & ( ( struct sockaddr_in6 * ) & addr ) - > sin6_addr . s6_addr [ 12 ] = * ( int * ) & to . address . ip ;
( ( struct sockaddr_in6 * ) & addr ) - > sin6_port = to . port ;
size = sizeof ( struct sockaddr_in6 ) ;
}
else
# endif
2008-11-09 22:29:28 +00:00
{
2011-12-05 15:23:40 +00:00
NetadrToSockadr ( & to , & addr ) ;
switch ( to . type )
{
default :
Con_Printf ( " Bad address type \n " ) ;
break ;
2008-11-09 22:29:28 +00:00
# ifdef USEIPX //who uses ipx nowadays anyway?
2011-12-05 15:23:40 +00:00
case NA_BROADCAST_IPX :
case NA_IPX :
size = sizeof ( struct sockaddr_ipx ) ;
break ;
2008-11-09 22:29:28 +00:00
# endif
2011-12-05 15:23:40 +00:00
case NA_BROADCAST_IP :
case NA_IP :
size = sizeof ( struct sockaddr_in ) ;
break ;
2008-11-09 22:29:28 +00:00
# ifdef IPPROTO_IPV6
2011-12-05 15:23:40 +00:00
case NA_BROADCAST_IP6 :
case NA_IPV6 :
size = sizeof ( struct sockaddr_in6 ) ;
break ;
2008-11-09 22:29:28 +00:00
# endif
}
2011-12-05 15:23:40 +00:00
}
2008-11-09 22:29:28 +00:00
ret = sendto ( con - > thesocket , data , length , 0 , ( struct sockaddr * ) & addr , size ) ;
if ( ret = = - 1 )
{
2011-12-05 15:23:40 +00:00
int ecode = qerrno ;
2008-11-09 22:29:28 +00:00
// wouldblock is silent
2011-12-05 15:23:40 +00:00
if ( ecode = = EWOULDBLOCK )
2008-11-09 22:29:28 +00:00
return true ;
2011-12-05 15:23:40 +00:00
if ( ecode = = ECONNREFUSED )
2008-11-09 22:29:28 +00:00
return true ;
# ifndef SERVERONLY
2011-12-05 15:23:40 +00:00
if ( ecode = = EADDRNOTAVAIL )
Con_DPrintf ( " NET_SendPacket Warning: %i \n " , ecode ) ;
2008-11-09 22:29:28 +00:00
else
# endif
2011-12-05 15:23:40 +00:00
Con_TPrintf ( TL_NETSENDERROR , ecode ) ;
2008-11-09 22:29:28 +00:00
}
return true ;
2012-04-09 19:12:12 +00:00
# endif
2008-11-09 22:29:28 +00:00
}
2009-04-01 22:03:56 +00:00
qboolean NET_PortToAdr ( int adrfamily , const char * s , netadr_t * a )
2008-11-09 22:29:28 +00:00
{
char * e ;
int port ;
port = strtoul ( s , & e , 10 ) ;
2013-03-12 22:53:23 +00:00
if ( * e ) //if *e then its not just a single number in there, so treat it as a proper address.
return NET_StringToAdr ( s , 0 , a ) ;
2008-11-09 22:29:28 +00:00
else if ( port )
{
memset ( a , 0 , sizeof ( * a ) ) ;
a - > port = htons ( ( unsigned short ) port ) ;
2013-03-31 04:21:08 +00:00
a - > type = adrfamily ;
return a - > type ! = NA_INVALID ;
2008-11-09 22:29:28 +00:00
}
2009-03-03 01:53:19 +00:00
a - > type = NA_INVALID ;
2008-11-09 22:29:28 +00:00
return false ;
}
2009-04-01 22:03:56 +00:00
ftenet_generic_connection_t * FTENET_Generic_EstablishConnection ( int adrfamily , int protocol , qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
2012-04-09 19:12:12 +00:00
# ifndef HAVE_PACKET
return NULL ;
# else
2008-11-09 22:29:28 +00:00
//this is written to support either ipv4 or ipv6, depending on the remote addr.
ftenet_generic_connection_t * newcon ;
unsigned long _true = true ;
2011-12-23 03:12:29 +00:00
SOCKET newsocket = INVALID_SOCKET ;
2008-11-09 22:29:28 +00:00
int temp ;
netadr_t adr ;
struct sockaddr_qstorage qs ;
int family ;
int port ;
int bindtries ;
2011-10-27 16:16:29 +00:00
int bufsz ;
2011-12-05 15:23:40 +00:00
qboolean hybrid = false ;
2008-11-09 22:29:28 +00:00
if ( ! NET_PortToAdr ( adrfamily , address , & adr ) )
{
Con_Printf ( " unable to resolve local address %s \n " , address ) ;
return NULL ; //couldn't resolve the name
}
temp = NetadrToSockadr ( & adr , & qs ) ;
2011-12-05 15:23:40 +00:00
family = ( ( struct sockaddr * ) & qs ) - > sa_family ;
2008-11-09 22:29:28 +00:00
2012-03-19 06:30:41 +00:00
# if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
2011-12-05 15:23:40 +00:00
if ( isserver & & family = = AF_INET & & net_hybriddualstack . ival & & ! ( ( struct sockaddr_in * ) & qs ) - > sin_addr . s_addr )
2008-11-09 22:29:28 +00:00
{
2011-12-05 15:23:40 +00:00
unsigned long _false = false ;
if ( ( newsocket = socket ( AF_INET6 , SOCK_DGRAM , protocol ) ) ! = INVALID_SOCKET )
{
if ( 0 = = setsockopt ( newsocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( char * ) & _false , sizeof ( _false ) ) )
{
int ip = ( ( struct sockaddr_in * ) & qs ) - > sin_addr . s_addr ;
int port = ( ( struct sockaddr_in * ) & qs ) - > sin_port ;
ip = ( ( struct sockaddr_in * ) & qs ) - > sin_addr . s_addr ;
memset ( & qs , 0 , sizeof ( struct sockaddr_in6 ) ) ;
( ( struct sockaddr_in6 * ) & qs ) - > sin6_family = AF_INET6 ;
/*
if ( ( ( struct sockaddr_in * ) & qs ) - > sin_addr . s_addr )
{
( ( struct sockaddr_in6 * ) & qs ) - > sin6_addr . s6_addr [ 10 ] = 0xff ;
( ( struct sockaddr_in6 * ) & qs ) - > sin6_addr . s6_addr [ 11 ] = 0xff ;
( ( struct sockaddr_in6 * ) & qs ) - > sin6_addr . s6_addr [ 12 ] = ( ( qbyte * ) & ip ) [ 0 ] ;
( ( struct sockaddr_in6 * ) & qs ) - > sin6_addr . s6_addr [ 13 ] = ( ( qbyte * ) & ip ) [ 1 ] ;
( ( struct sockaddr_in6 * ) & qs ) - > sin6_addr . s6_addr [ 14 ] = ( ( qbyte * ) & ip ) [ 2 ] ;
( ( struct sockaddr_in6 * ) & qs ) - > sin6_addr . s6_addr [ 15 ] = ( ( qbyte * ) & ip ) [ 3 ] ;
}
*/
( ( struct sockaddr_in6 * ) & qs ) - > sin6_port = port ;
temp = sizeof ( struct sockaddr_in6 ) ;
hybrid = true ;
}
else
{
/*v6only failed... if the option doesn't exist, chances are this is a hybrid system which doesn't support both simultaneously anyway*/
closesocket ( newsocket ) ;
newsocket = INVALID_SOCKET ;
}
}
2008-11-09 22:29:28 +00:00
}
2011-12-05 15:23:40 +00:00
# endif
if ( newsocket = = INVALID_SOCKET )
if ( ( newsocket = socket ( family , SOCK_DGRAM , protocol ) ) = = INVALID_SOCKET )
{
return NULL ;
}
2012-03-19 06:30:41 +00:00
# if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
2011-12-23 03:12:29 +00:00
if ( family = = AF_INET6 )
2011-12-05 15:23:40 +00:00
setsockopt ( newsocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( char * ) & _true , sizeof ( _true ) ) ;
2011-12-23 03:12:29 +00:00
# endif
2008-11-09 22:29:28 +00:00
2011-10-27 16:16:29 +00:00
bufsz = 1 < < 18 ;
setsockopt ( newsocket , SOL_SOCKET , SO_RCVBUF , ( void * ) & bufsz , sizeof ( bufsz ) ) ;
2008-11-09 22:29:28 +00:00
//try and find an unused port.
port = ntohs ( ( ( struct sockaddr_in * ) & qs ) - > sin_port ) ;
for ( bindtries = 100 ; bindtries > 0 ; bindtries - - )
{
( ( struct sockaddr_in * ) & qs ) - > sin_port = htons ( ( unsigned short ) ( port + 100 - bindtries ) ) ;
if ( ( bind ( newsocket , ( struct sockaddr * ) & qs , temp ) = = INVALID_SOCKET ) )
{
continue ;
}
break ;
}
if ( ! bindtries )
{
SockadrToNetadr ( & qs , & adr ) ;
//mneh, reuse qs.
NET_AdrToString ( ( char * ) & qs , sizeof ( qs ) , adr ) ;
Con_Printf ( " Unable to listen at %s \n " , ( char * ) & qs ) ;
closesocket ( newsocket ) ;
return NULL ;
}
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " UDP_OpenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
2011-10-27 16:16:29 +00:00
//
// determine my name & address if we don't already know it
//
if ( ! net_local_cl_ipadr . type = = NA_INVALID )
NET_GetLocalAddress ( newsocket , & net_local_cl_ipadr ) ;
2008-11-09 22:29:28 +00:00
newcon = Z_Malloc ( sizeof ( * newcon ) ) ;
if ( newcon )
{
newcon - > GetLocalAddress = FTENET_Generic_GetLocalAddress ;
newcon - > GetPacket = FTENET_Generic_GetPacket ;
newcon - > SendPacket = FTENET_Generic_SendPacket ;
newcon - > Close = FTENET_Generic_Close ;
newcon - > islisten = isserver ;
2011-12-05 15:23:40 +00:00
if ( hybrid )
{
newcon - > addrtype [ 0 ] = NA_IP ;
newcon - > addrtype [ 1 ] = NA_IPV6 ;
}
else
{
newcon - > addrtype [ 0 ] = adr . type ;
newcon - > addrtype [ 1 ] = NA_INVALID ;
}
2008-11-09 22:29:28 +00:00
newcon - > thesocket = newsocket ;
return newcon ;
}
else
{
closesocket ( newsocket ) ;
return NULL ;
}
2012-04-09 19:12:12 +00:00
# endif
2008-11-09 22:29:28 +00:00
}
2008-12-01 02:10:35 +00:00
# ifdef IPPROTO_IPV6
2009-04-01 22:03:56 +00:00
ftenet_generic_connection_t * FTENET_UDP6_EstablishConnection ( qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
2013-03-31 04:21:08 +00:00
return FTENET_Generic_EstablishConnection ( NA_IPV6 , IPPROTO_UDP , isserver , address ) ;
2008-11-09 22:29:28 +00:00
}
2008-12-01 02:10:35 +00:00
# endif
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2009-04-01 22:03:56 +00:00
ftenet_generic_connection_t * FTENET_UDP4_EstablishConnection ( qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
2013-03-31 04:21:08 +00:00
return FTENET_Generic_EstablishConnection ( NA_IP , IPPROTO_UDP , isserver , address ) ;
2008-11-09 22:29:28 +00:00
}
2012-04-09 19:12:12 +00:00
# endif
2008-11-13 08:55:41 +00:00
# ifdef USEIPX
2009-04-01 22:03:56 +00:00
ftenet_generic_connection_t * FTENET_IPX_EstablishConnection ( qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
2013-03-31 04:21:08 +00:00
return FTENET_Generic_EstablishConnection ( NA_IPX , NSPROTO_IPX , isserver , address ) ;
2008-11-09 22:29:28 +00:00
}
2008-11-13 08:55:41 +00:00
# endif
2008-11-09 22:29:28 +00:00
# ifdef TCPCONNECT
typedef struct ftenet_tcpconnect_stream_s {
int socketnum ;
int inlen ;
2012-04-09 19:12:12 +00:00
int outlen ;
enum
{
TCPC_UNKNOWN ,
TCPC_QIZMO ,
TCPC_WEBSOCKET
} clienttype ;
char inbuffer [ 3000 ] ;
char outbuffer [ 3000 ] ;
2008-11-09 22:29:28 +00:00
float timeouttime ;
netadr_t remoteaddr ;
struct ftenet_tcpconnect_stream_s * next ;
} ftenet_tcpconnect_stream_t ;
typedef struct {
ftenet_generic_connection_t generic ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
int active ;
ftenet_tcpconnect_stream_t * tcpstreams ;
} ftenet_tcpconnect_connection_t ;
2012-04-09 19:12:12 +00:00
void tobase64 ( unsigned char * out , int outlen , unsigned char * in , int inlen )
{
2012-07-14 17:25:21 +00:00
static unsigned char tab [ 64 ] =
2012-04-09 19:12:12 +00:00
{
' A ' , ' B ' , ' C ' , ' D ' , ' E ' , ' F ' , ' G ' , ' H ' , ' I ' , ' J ' , ' K ' , ' L ' , ' M ' , ' N ' , ' O ' , ' P ' ,
' Q ' , ' R ' , ' S ' , ' T ' , ' U ' , ' V ' , ' W ' , ' X ' , ' Y ' , ' Z ' , ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' ,
' g ' , ' h ' , ' i ' , ' j ' , ' k ' , ' l ' , ' m ' , ' n ' , ' o ' , ' p ' , ' q ' , ' r ' , ' s ' , ' t ' , ' u ' , ' v ' ,
' w ' , ' x ' , ' y ' , ' z ' , ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' , ' + ' , ' / '
} ;
unsigned int usedbits = 0 ;
unsigned int val = 0 ;
outlen - - ;
while ( inlen )
{
while ( usedbits < 24 & & inlen )
{
val < < = 8 ;
val | = ( * in + + ) ;
inlen - - ;
usedbits + = 8 ;
}
if ( outlen < 4 )
return ;
val < < = 24 - usedbits ;
* out + + = ( usedbits > 0 ) ? tab [ ( val > > 18 ) & 0x3f ] : ' = ' ;
* out + + = ( usedbits > 6 ) ? tab [ ( val > > 12 ) & 0x3f ] : ' = ' ;
* out + + = ( usedbits > 12 ) ? tab [ ( val > > 6 ) & 0x3f ] : ' = ' ;
* out + + = ( usedbits > 18 ) ? tab [ ( val > > 0 ) & 0x3f ] : ' = ' ;
val = 0 ;
usedbits = 0 ;
}
* out = 0 ;
}
int SHA1 ( char * digest , int maxdigestsize , char * string ) ;
2008-11-09 22:29:28 +00:00
qboolean FTENET_TCPConnect_GetPacket ( ftenet_generic_connection_t * gcon )
{
ftenet_tcpconnect_connection_t * con = ( ftenet_tcpconnect_connection_t * ) gcon ;
int ret ;
int err ;
char adr [ MAX_ADR_SIZE ] ;
struct sockaddr_qstorage from ;
int fromlen ;
float timeval = Sys_DoubleTime ( ) ;
ftenet_tcpconnect_stream_t * st ;
st = con - > tcpstreams ;
//remove any stale ones
while ( con - > tcpstreams & & con - > tcpstreams - > socketnum = = INVALID_SOCKET )
{
st = con - > tcpstreams ;
con - > tcpstreams = con - > tcpstreams - > next ;
BZ_Free ( st ) ;
}
for ( st = con - > tcpstreams ; st ; st = st - > next )
{ //client receiving only via tcp
while ( st - > next & & st - > next - > socketnum = = INVALID_SOCKET )
{
ftenet_tcpconnect_stream_t * temp ;
temp = st - > next ;
st - > next = st - > next - > next ;
BZ_Free ( temp ) ;
con - > active - - ;
}
//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 )
2005-11-30 01:20:53 +00:00
{
2008-11-09 22:29:28 +00:00
Con_TPrintf ( TL_CONNECTIONLOSTORABORTED ) ; //server died/connection lost.
2005-11-30 01:20:53 +00:00
}
2008-11-09 22:29:28 +00:00
else
Con_Printf ( " TCPConnect_GetPacket: Error (%i): %s \n " , err , strerror ( err ) ) ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
closesvstream :
closesocket ( st - > socketnum ) ;
st - > socketnum = INVALID_SOCKET ;
continue ;
2005-11-30 01:20:53 +00:00
}
2008-11-09 22:29:28 +00:00
}
st - > inlen + = ret ;
2005-11-30 01:20:53 +00:00
2012-04-09 19:12:12 +00:00
switch ( st - > clienttype )
2008-11-09 22:29:28 +00:00
{
2012-04-09 19:12:12 +00:00
case TCPC_UNKNOWN :
2008-11-09 22:29:28 +00:00
if ( st - > inlen < 6 )
2005-11-30 01:20:53 +00:00
continue ;
2012-04-09 19:12:12 +00:00
if ( ! strncmp ( st - > inbuffer , " qizmo \n " , 6 ) )
{
memmove ( st - > inbuffer , st - > inbuffer + 6 , st - > inlen - ( 6 ) ) ;
st - > inlen - = 6 ;
st - > clienttype = TCPC_QIZMO ;
if ( con - > generic . islisten )
{
//send the qizmo handshake response.
send ( st - > socketnum , " qizmo \n " , 6 , 0 ) ;
}
}
else if ( con - > generic . islisten & & ! strncmp ( st - > inbuffer , " GET " , 4 ) )
{
int i , j ;
int attr = 0 ;
int alen = 0 ;
qboolean headerscomplete = false ;
enum
{
WCATTR_METHOD ,
WCATTR_URL ,
WCATTR_HTTP ,
WCATTR_HOST ,
WCATTR_UPGRADE ,
WCATTR_CONNECTION ,
WCATTR_WSKEY ,
WCATTR_WSVER ,
//WCATTR_ORIGIN,
WCATTR_WSPROTO ,
//WCATTR_WSEXT,
WCATTR_COUNT
} ;
char arg [ WCATTR_COUNT ] [ 64 ] ;
for ( i = 0 ; i < WCATTR_COUNT ; i + + )
arg [ i ] [ 0 ] = 0 ;
for ( i = 0 ; i < st - > inlen ; i + + )
{
if ( alen = = 63 )
goto handshakeerror ;
if ( st - > inbuffer [ i ] = = ' ' | | st - > inbuffer [ i ] = = ' \t ' )
{
arg [ attr ] [ alen + + ] = 0 ;
alen = 0 ;
if ( attr + + = = WCATTR_HTTP )
break ;
for ( ; i < st - > inlen & & ( st - > inbuffer [ i ] = = ' ' | | st - > inbuffer [ i ] = = ' \t ' ) ; i + + )
;
if ( i = = st - > inlen )
break ;
}
arg [ attr ] [ alen + + ] = st - > inbuffer [ i ] ;
if ( st - > inbuffer [ i ] = = ' \n ' )
{
arg [ attr ] [ alen + + ] = 0 ;
alen = 0 ;
break ;
}
}
i + + ;
attr = 0 ;
j = i ;
for ( ; i < st - > inlen ; i + + )
{
if ( ( i + 1 < st - > inlen & & st - > inbuffer [ i ] = = ' \r ' & & st - > inbuffer [ i + 1 ] = = ' \n ' ) | |
( i < st - > inlen & & st - > inbuffer [ i ] = = ' \n ' ) )
{
i + = 2 ;
headerscomplete = true ;
break ;
}
for ( ; i < st - > inlen & & ( st - > inbuffer [ i ] = = ' ' | | st - > inbuffer [ i ] = = ' \t ' ) ; i + + )
;
if ( i = = st - > inlen )
break ;
for ( j = i ; j < st - > inlen ; j + + )
{
if ( st - > inbuffer [ j ] = = ' : ' | | st - > inbuffer [ j ] = = ' \n ' )
{
/*set j to the end of the word, going back past whitespace*/
while ( j > i & & ( st - > inbuffer [ j - 1 ] = = ' ' | | st - > inbuffer [ i - 1 ] = = ' \t ' ) )
j - - ;
break ;
}
}
if ( ! strnicmp ( & st - > inbuffer [ i ] , " Host " , j - i ) )
attr = WCATTR_HOST ;
else if ( ! strnicmp ( & st - > inbuffer [ i ] , " Upgrade " , j - i ) )
attr = WCATTR_UPGRADE ;
else if ( ! strnicmp ( & st - > inbuffer [ i ] , " Connection " , j - i ) )
attr = WCATTR_CONNECTION ;
else if ( ! strnicmp ( & st - > inbuffer [ i ] , " Sec-WebSocket-Key " , j - i ) )
attr = WCATTR_WSKEY ;
else if ( ! strnicmp ( & st - > inbuffer [ i ] , " Sec-WebSocket-Version " , j - i ) )
attr = WCATTR_WSVER ;
// else if (!strnicmp(&st->inbuffer[i], "Origin", j-i))
// attr = WCATTR_ORIGIN;
else if ( ! strnicmp ( & st - > inbuffer [ i ] , " Sec-WebSocket-Protocol " , j - i ) )
attr = WCATTR_WSPROTO ;
// else if (!strnicmp(&st->inbuffer[i], "Sec-WebSocket-Extensions", j-i))
// attr = WCATTR_WSEXT;
else
attr = 0 ;
i = j ;
/*skip over the whitespace at the end*/
for ( ; i < st - > inlen & & ( st - > inbuffer [ i ] = = ' ' | | st - > inbuffer [ i ] = = ' \t ' ) ; i + + )
;
if ( i < st - > inlen & & st - > inbuffer [ i ] = = ' : ' )
{
i + + ;
for ( ; i < st - > inlen & & ( st - > inbuffer [ i ] = = ' ' | | st - > inbuffer [ i ] = = ' \t ' ) ; i + + )
;
j = i ;
for ( ; i < st - > inlen & & st - > inbuffer [ i ] ! = ' \n ' ; i + + )
;
if ( i > j & & st - > inbuffer [ i - 1 ] = = ' \r ' )
i - - ;
if ( attr )
Q_strncpyz ( arg [ attr ] , & st - > inbuffer [ j ] , ( i - j > 63 ) ? 64 : ( i - j + 1 ) ) ;
if ( i < st - > inlen & & st - > inbuffer [ i ] = = ' \r ' )
i + + ;
}
else
{
/*just a word on the line on its own*/
goto handshakeerror ;
}
}
if ( headerscomplete )
{
char * resp ;
//must be a Host, Upgrade=websocket, Connection=Upgrade, Sec-WebSocket-Key=base64(randbytes(16)), Sec-WebSocket-Version=13
//optionally will be Origin=url, Sec-WebSocket-Protocol=FTEWebSocket, Sec-WebSocket-Extensions
//other fields will be ignored.
//FIXME: reply with 426 Upgrade Required if wsversion is not supported
if ( ! stricmp ( arg [ WCATTR_UPGRADE ] , " websocket " ) & & ! stricmp ( arg [ WCATTR_CONNECTION ] , " Upgrade " ) )
{
if ( atoi ( arg [ WCATTR_WSVER ] ) ! = 13 )
{
memmove ( st - > inbuffer , st - > inbuffer + i , st - > inlen - ( i ) ) ;
st - > inlen - = i ;
resp = va ( " HTTP/1.1 426 Upgrade Required \r \n "
" Sec-WebSocket-Version: 13 \r \n "
" \r \n " ) ;
//send the websocket handshake rejection.
send ( st - > socketnum , resp , strlen ( resp ) , 0 ) ;
goto closesvstream ;
}
else
{
char acceptkey [ 20 * 2 ] ;
unsigned char sha1digest [ 20 ] ;
memmove ( st - > inbuffer , st - > inbuffer + i , st - > inlen - ( i ) ) ;
st - > inlen - = i ;
tobase64 ( acceptkey , sizeof ( acceptkey ) , sha1digest , SHA1 ( sha1digest , sizeof ( sha1digest ) , va ( " %s258EAFA5-E914-47DA-95CA-C5AB0DC85B11 " , arg [ WCATTR_WSKEY ] ) ) ) ;
resp = va ( " HTTP/1.1 101 Switching Protocols \r \n "
" Upgrade: websocket \r \n "
" Connection: Upgrade \r \n "
" Sec-WebSocket-Accept: %s \r \n "
// "Sec-WebSocket-Protocol: FTEWebSocket\r\n"
" \r \n " , acceptkey ) ;
//send the websocket handshake response.
send ( st - > socketnum , resp , strlen ( resp ) , 0 ) ;
//and the connection is okay
st - > clienttype = TCPC_WEBSOCKET ;
}
}
else
{
memmove ( st - > inbuffer , st - > inbuffer + i , st - > inlen - ( i ) ) ;
st - > inlen - = i ;
2013-03-12 23:09:25 +00:00
if ( ! strcmp ( arg [ WCATTR_URL ] , " /live.html " ) )
{
resp = va ( " HTTP/1.1 200 Ok \r \n "
" Connection: Close \r \n "
" Content-Type: text/html \r \n "
" \r \n "
" <!DOCTYPE HTML> "
" <html> "
" <style> "
" html, body { height: 100%%; width: 100%%; margin: 0; padding: 0;} "
" div { height: 100%%; width: 100%%; } "
" </style> "
" <div> "
" <object name= \" ieplug \" type= \" application/x-fteplugin \" classid= \" clsid:7d676c9f-fb84-40b6-b3ff-e10831557eeb \" width= \" 100%% \" height= \" 100%% \" > "
" <param name= \" game \" value= \" q1 \" > "
" <object name= \" npplug \" type= \" application/x-fteplugin \" width= \" 100%% \" height= \" 100%% \" > "
" <param name= \" game \" value= \" q1 \" > "
" Please install a plugin first.<br/> "
" </object> "
" </object> "
" </div> "
" </html> "
) ;
}
/*else if (!strcmp(arg[WCATTR_URL], "/index.html") || !strcmp(arg[WCATTR_URL], "/"))
{
resp = va ( " HTTP/1.1 200 Ok \r \n "
" Connection: Close \r \n "
" Content-Type: text/html \r \n "
" \r \n "
" This is a Quake WebSocket server, not an http server.<br/> \r \n "
" <a href=' " ENGINEWEBSITE " '> " FULLENGINENAME " </a> "
) ;
} */
else
{
resp = va ( " HTTP/1.1 404 Ok \r \n "
" Connection: Close \r \n "
" Content-Type: text/html \r \n "
" \r \n "
" This is a Quake WebSocket server, not an http server.<br/> \r \n "
" <a href=' " ENGINEWEBSITE " '> " FULLENGINENAME " </a> "
) ;
}
2012-04-09 19:12:12 +00:00
//send the websocket handshake rejection.
send ( st - > socketnum , resp , strlen ( resp ) , 0 ) ;
goto closesvstream ;
}
}
}
else
{
handshakeerror :
Con_Printf ( " Unknown TCP handshake from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
goto closesvstream ;
}
break ;
case TCPC_QIZMO :
if ( st - > inlen < 2 )
continue ;
net_message . cursize = BigShort ( * ( short * ) st - > inbuffer ) ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
2005-11-30 01:20:53 +00:00
{
2012-04-24 07:59:11 +00:00
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
2005-11-30 01:20:53 +00:00
goto closesvstream ;
}
2012-04-09 19:12:12 +00:00
if ( net_message . cursize + 2 > st - > inlen )
{ //not enough buffered to read a packet out of it.
continue ;
}
2008-11-09 22:29:28 +00:00
2012-04-09 19:12:12 +00:00
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 ;
2008-11-09 22:29:28 +00:00
2012-04-09 19:12:12 +00:00
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
net_from = st - > remoteaddr ;
2008-11-09 22:29:28 +00:00
2012-04-09 19:12:12 +00:00
return true ;
case TCPC_WEBSOCKET :
while ( st - > inlen > = 2 )
{
unsigned short ctrl = ( ( unsigned char * ) st - > inbuffer ) [ 0 ] < < 8 | ( ( unsigned char * ) st - > inbuffer ) [ 1 ] ;
unsigned long paylen ;
unsigned int payoffs = 2 ;
unsigned int mask = 0 ;
st - > inbuffer [ st - > inlen ] = 0 ;
if ( ( ctrl & 0x7f ) = = 127 )
{
//as a payload is not allowed to be encoded as too large a type, and quakeworld never used packets larger than 1450 bytes anyway, this code isn't needed (65k is the max even without this)
// if (sizeof(paylen) < 8)
{
Con_Printf ( " %s: payload frame too large \n " , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
goto closesvstream ;
}
/* else
{
if ( payoffs + 8 > st - > inlen )
break ;
paylen =
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 0 ] < < 56 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 1 ] < < 48 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 2 ] < < 40 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 3 ] < < 32 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 4 ] < < 24 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 5 ] < < 16 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 6 ] < < 8 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 7 ] < < 0 ;
if ( paylen < 0x10000 )
{
Con_Printf ( " %s: payload size encoded badly \n " , NET_AdrToString ( st - > remoteaddr , sizeof ( st - > remoteaddr ) , net_from ) ) ;
goto closesvstream ;
}
payoffs + = 8 ;
}
*/ }
else if ( ( ctrl & 0x7f ) = = 126 )
{
if ( payoffs + 2 > st - > inlen )
break ;
paylen =
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 0 ] < < 8 |
( ( unsigned char * ) st - > inbuffer ) [ payoffs + 1 ] < < 0 ;
if ( paylen < 126 )
{
Con_Printf ( " %s: payload size encoded badly \n " , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
goto closesvstream ;
}
payoffs + = 2 ;
}
else
{
paylen = ctrl & 0x7f ;
}
if ( ctrl & 0x80 )
{
if ( payoffs + 4 > st - > inlen )
break ;
/*this might read data that isn't set yet, but should be safe*/
( ( unsigned char * ) & mask ) [ 0 ] = ( ( unsigned char * ) st - > inbuffer ) [ payoffs + 0 ] ;
( ( unsigned char * ) & mask ) [ 1 ] = ( ( unsigned char * ) st - > inbuffer ) [ payoffs + 1 ] ;
( ( unsigned char * ) & mask ) [ 2 ] = ( ( unsigned char * ) st - > inbuffer ) [ payoffs + 2 ] ;
( ( unsigned char * ) & mask ) [ 3 ] = ( ( unsigned char * ) st - > inbuffer ) [ payoffs + 3 ] ;
payoffs + = 4 ;
}
/*if there isn't space, try again next time around*/
if ( payoffs + paylen > st - > inlen )
break ;
2008-11-09 22:29:28 +00:00
2012-04-09 19:12:12 +00:00
if ( mask )
{
int i ;
for ( i = 0 ; i < paylen ; i + + )
{
( ( unsigned char * ) st - > inbuffer ) [ i + payoffs ] ^ = ( ( unsigned char * ) & mask ) [ i & 3 ] ;
}
}
2008-11-09 22:29:28 +00:00
2012-04-09 19:12:12 +00:00
net_message . cursize = 0 ;
2008-11-09 22:29:28 +00:00
2012-04-09 19:12:12 +00:00
switch ( ( ctrl > > 8 ) & 0xf )
{
case 0 : /*continuation*/
Con_Printf ( " websocket continuation frame from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
goto closesvstream ;
case 1 : /*text frame*/
// Con_Printf ("websocket text frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr));
{
/*text frames are pure utf-8 chars, no dodgy encodings or anything, all pre-checked...
except we ' re trying to send binary data .
so we need to unmask things ( char 0 is encoded as 0x100 - truncate it )
*/
unsigned char * in = st - > inbuffer + payoffs , * out = net_message_buffer ;
int len = paylen ;
while ( len & & out < net_message_buffer + sizeof ( net_message_buffer ) )
{
if ( ( * in & 0xe0 ) = = 0xc0 & & len > 1 )
{
* out = ( ( in [ 0 ] & 0x1f ) < < 6 ) | ( ( in [ 1 ] & 0x3f ) < < 0 ) ;
in + = 2 ;
len - = 2 ;
}
else if ( * in & 0x80 )
{
* out = ' ? ' ;
in + + ;
len - = 1 ;
}
else
{
* out = in [ 0 ] ;
in + + ;
len - = 1 ;
}
out + + ;
}
net_message . cursize = out - net_message_buffer ;
}
break ;
case 2 : /*binary frame*/
Con_Printf ( " websocket binary frame from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
net_message . cursize = paylen ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
{
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
goto closesvstream ;
}
memcpy ( net_message_buffer , st - > inbuffer + payoffs , paylen ) ;
break ;
case 8 : /*connection close*/
Con_Printf ( " websocket closure %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
goto closesvstream ;
case 9 : /*ping*/
Con_Printf ( " websocket ping from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
goto closesvstream ;
case 10 : /*pong*/
Con_Printf ( " websocket pong from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
goto closesvstream ;
default :
Con_Printf ( " Unsupported websocket opcode (%i) from %s \n " , ( ctrl > > 8 ) & 0xf , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
goto closesvstream ;
}
// memcpy(net_message_buffer, st->inbuffer+2, net_message.cursize);
memmove ( st - > inbuffer , st - > inbuffer + payoffs + paylen , st - > inlen - ( payoffs + paylen ) ) ;
st - > inlen - = payoffs + paylen ;
if ( net_message . cursize )
{
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
net_from = st - > remoteaddr ;
return true ;
}
}
break ;
}
2008-11-09 22:29:28 +00:00
}
if ( con - > generic . thesocket ! = INVALID_SOCKET & & con - > active < 256 )
{
int newsock ;
2012-01-17 07:57:46 +00:00
fromlen = sizeof ( from ) ;
2008-11-09 22:29:28 +00:00
newsock = accept ( con - > generic . thesocket , ( struct sockaddr * ) & from , & fromlen ) ;
if ( newsock ! = INVALID_SOCKET )
{
int _true = true ;
2011-05-19 13:34:07 +00:00
ioctlsocket ( newsock , FIONBIO , ( u_long * ) & _true ) ;
2008-11-09 22:29:28 +00:00
setsockopt ( newsock , IPPROTO_TCP , TCP_NODELAY , ( char * ) & _true , sizeof ( _true ) ) ;
con - > active + + ;
st = Z_Malloc ( sizeof ( * con - > tcpstreams ) ) ;
2012-04-09 19:12:12 +00:00
st - > clienttype = TCPC_UNKNOWN ;
2008-11-09 22:29:28 +00:00
st - > next = con - > tcpstreams ;
con - > tcpstreams = st ;
st - > socketnum = newsock ;
st - > inlen = 0 ;
2009-06-10 22:36:53 +00:00
/*grab the net address*/
2008-11-09 22:29:28 +00:00
SockadrToNetadr ( & from , & st - > remoteaddr ) ;
2009-06-10 22:36:53 +00:00
/*sockadr doesn't contain transport info, so fix that up here*/
if ( st - > remoteaddr . type = = NA_IP )
st - > remoteaddr . type = NA_TCP ;
else if ( st - > remoteaddr . type = = NA_IPV6 )
st - > remoteaddr . type = NA_TCPV6 ;
2008-11-09 22:29:28 +00:00
st - > timeouttime = timeval + 30 ;
}
}
return false ;
}
qboolean FTENET_TCPConnect_SendPacket ( ftenet_generic_connection_t * gcon , int length , void * data , netadr_t to )
{
ftenet_tcpconnect_connection_t * con = ( ftenet_tcpconnect_connection_t * ) gcon ;
ftenet_tcpconnect_stream_t * st ;
for ( st = con - > tcpstreams ; st ; st = st - > next )
{
if ( st - > socketnum = = INVALID_SOCKET )
continue ;
if ( NET_CompareAdr ( to , st - > remoteaddr ) )
{
2012-04-09 19:12:12 +00:00
if ( ! st - > outlen )
{
switch ( st - > clienttype )
{
case TCPC_QIZMO :
{
unsigned short slen = BigShort ( ( unsigned short ) length ) ;
2012-09-30 05:52:03 +00:00
if ( st - > outlen + sizeof ( slen ) + length > sizeof ( st - > outbuffer ) )
{
Con_DPrintf ( " FTENET_TCPConnect_SendPacket: outgoing overflow \n " ) ;
}
else
{
memcpy ( st - > outbuffer + st - > outlen , & slen , sizeof ( slen ) ) ;
memcpy ( st - > outbuffer + st - > outlen + sizeof ( slen ) , data , length ) ;
st - > outlen + = sizeof ( slen ) + length ;
}
2012-04-09 19:12:12 +00:00
}
break ;
case TCPC_WEBSOCKET :
{
/*as a server, we don't need the mask stuff*/
unsigned short ctrl = 0x8100 ;
unsigned int paylen = 0 ;
unsigned int payoffs = 2 ;
int i ;
for ( i = 0 ; i < length ; i + + )
{
paylen + = ( ( ( char * ) data ) [ i ] = = 0 | | ( ( unsigned char * ) data ) [ i ] > = 0x80 ) ? 2 : 1 ;
}
if ( paylen > = 126 )
{
ctrl | = 126 ;
payoffs + = 2 ;
}
else
ctrl | = paylen ;
st - > outbuffer [ 0 ] = ctrl > > 8 ;
st - > outbuffer [ 1 ] = ctrl & 0xff ;
if ( paylen > = 126 )
{
st - > outbuffer [ 2 ] = paylen > > 8 ;
st - > outbuffer [ 3 ] = paylen & 0xff ;
}
/*utf8ify the data*/
for ( i = 0 ; i < length ; i + + )
{
if ( ! ( ( unsigned char * ) data ) [ i ] )
{ /*0 is encoded as 0x100 to avoid safety checks*/
st - > outbuffer [ payoffs + + ] = 0xc0 | ( 0x100 > > 6 ) ;
st - > outbuffer [ payoffs + + ] = 0x80 | ( 0x100 & 0x3f ) ;
}
else if ( ( ( unsigned char * ) data ) [ i ] > = 0x80 )
{ /*larger bytes require markup*/
st - > outbuffer [ payoffs + + ] = 0xc0 | ( ( ( unsigned char * ) data ) [ i ] > > 6 ) ;
st - > outbuffer [ payoffs + + ] = 0x80 | ( ( ( unsigned char * ) data ) [ i ] & 0x3f ) ;
}
else
{ /*lower 7 bits are as-is*/
st - > outbuffer [ payoffs + + ] = ( ( char * ) data ) [ i ] ;
}
}
st - > outlen = payoffs ;
}
break ;
default :
break ;
}
}
if ( st - > outlen )
{ /*try and flush the old data*/
int done ;
done = send ( st - > socketnum , st - > outbuffer , st - > outlen , 0 ) ;
if ( done > 0 )
{
memmove ( st - > outbuffer , st - > outbuffer + done , st - > outlen - done ) ;
st - > outlen - = done ;
}
}
2008-11-09 22:29:28 +00:00
st - > timeouttime = Sys_DoubleTime ( ) + 20 ;
return true ;
}
}
return false ;
}
void FTENET_TCPConnect_Close ( ftenet_generic_connection_t * gcon )
{
ftenet_tcpconnect_connection_t * con = ( ftenet_tcpconnect_connection_t * ) gcon ;
ftenet_tcpconnect_stream_t * st ;
st = con - > tcpstreams ;
while ( con - > tcpstreams )
{
st = con - > tcpstreams ;
con - > tcpstreams = st - > next ;
if ( st - > socketnum ! = INVALID_SOCKET )
closesocket ( st - > socketnum ) ;
BZ_Free ( st ) ;
}
FTENET_Generic_Close ( gcon ) ;
}
2012-04-09 19:12:12 +00:00
int FTENET_TCPConnect_SetReceiveFDSet ( ftenet_generic_connection_t * gcon , fd_set * fdset )
{
int maxfd = 0 ;
ftenet_tcpconnect_connection_t * con = ( ftenet_tcpconnect_connection_t * ) gcon ;
ftenet_tcpconnect_stream_t * st ;
for ( st = con - > tcpstreams ; st ; st = st - > next )
{
if ( st - > socketnum = = INVALID_SOCKET )
continue ;
FD_SET ( st - > socketnum , fdset ) ; // network socket
if ( maxfd < st - > socketnum )
maxfd = st - > socketnum ;
}
if ( con - > generic . thesocket ! = INVALID_SOCKET )
{
FD_SET ( con - > generic . thesocket , fdset ) ; // network socket
if ( maxfd < con - > generic . thesocket )
maxfd = con - > generic . thesocket ;
}
return maxfd ;
}
2009-04-01 22:03:56 +00:00
ftenet_generic_connection_t * FTENET_TCPConnect_EstablishConnection ( int affamily , qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
//this is written to support either ipv4 or ipv6, depending on the remote addr.
ftenet_tcpconnect_connection_t * newcon ;
unsigned long _true = true ;
int newsocket ;
int temp ;
netadr_t adr ;
struct sockaddr_qstorage qs ;
int family ;
2012-01-17 07:57:46 +00:00
if ( ! strncmp ( address , " tcp:// " , 6 ) )
address + = 6 ;
2008-11-09 22:29:28 +00:00
if ( isserver )
{
if ( ! NET_PortToAdr ( affamily , address , & adr ) )
return NULL ; //couldn't resolve the name
2012-01-17 07:57:46 +00:00
if ( adr . type = = NA_IP )
adr . type = NA_TCP ;
2008-11-09 22:29:28 +00:00
temp = NetadrToSockadr ( & adr , & qs ) ;
family = ( ( struct sockaddr_in * ) & qs ) - > sin_family ;
if ( ( newsocket = socket ( family , SOCK_STREAM , IPPROTO_TCP ) ) = = INVALID_SOCKET )
{
Con_Printf ( " operating system doesn't support that \n " ) ;
return NULL ;
}
if ( ( bind ( newsocket , ( struct sockaddr * ) & qs , temp ) = = INVALID_SOCKET ) | |
( listen ( newsocket , 2 ) = = INVALID_SOCKET ) )
{
SockadrToNetadr ( & qs , & adr ) ;
//mneh, reuse qs.
NET_AdrToString ( ( char * ) & qs , sizeof ( qs ) , adr ) ;
Con_Printf ( " Unable to listen at %s \n " , ( char * ) & qs ) ;
closesocket ( newsocket ) ;
return NULL ;
}
2009-07-05 18:45:53 +00:00
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " UDP_OpenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
2008-11-09 22:29:28 +00:00
}
else
{
2009-07-05 18:45:53 +00:00
if ( ! NET_PortToAdr ( affamily , address , & adr ) )
2008-11-09 22:29:28 +00:00
return NULL ; //couldn't resolve the name
2012-01-17 07:57:46 +00:00
if ( adr . type = = NA_IP )
adr . type = NA_TCP ;
2009-07-05 18:45:53 +00:00
newsocket = TCP_OpenStream ( adr ) ;
if ( newsocket = = INVALID_SOCKET )
2008-11-09 22:29:28 +00:00
return NULL ;
}
//this isn't fatal
setsockopt ( newsocket , IPPROTO_TCP , TCP_NODELAY , ( char * ) & _true , sizeof ( _true ) ) ;
newcon = Z_Malloc ( sizeof ( * newcon ) ) ;
if ( newcon )
{
if ( isserver )
newcon - > generic . GetLocalAddress = FTENET_Generic_GetLocalAddress ;
newcon - > generic . GetPacket = FTENET_TCPConnect_GetPacket ;
newcon - > generic . SendPacket = FTENET_TCPConnect_SendPacket ;
newcon - > generic . Close = FTENET_TCPConnect_Close ;
2012-04-09 19:12:12 +00:00
newcon - > generic . SetReceiveFDSet = FTENET_TCPConnect_SetReceiveFDSet ;
2008-11-09 22:29:28 +00:00
2012-01-17 07:57:46 +00:00
newcon - > generic . islisten = isserver ;
2008-11-09 22:29:28 +00:00
newcon - > generic . addrtype [ 0 ] = adr . type ;
newcon - > generic . addrtype [ 1 ] = NA_INVALID ;
newcon - > active = 0 ;
if ( ! isserver )
{
newcon - > generic . thesocket = INVALID_SOCKET ;
newcon - > active + + ;
newcon - > tcpstreams = Z_Malloc ( sizeof ( * newcon - > tcpstreams ) ) ;
2012-04-09 19:12:12 +00:00
newcon - > tcpstreams - > clienttype = TCPC_UNKNOWN ;
2008-11-09 22:29:28 +00:00
newcon - > tcpstreams - > next = NULL ;
newcon - > tcpstreams - > socketnum = newsocket ;
newcon - > tcpstreams - > inlen = 0 ;
2009-06-10 22:36:53 +00:00
newcon - > tcpstreams - > remoteaddr = adr ;
2008-11-09 22:29:28 +00:00
//send the qizmo greeting.
send ( newsocket , " qizmo \n " , 6 , 0 ) ;
newcon - > tcpstreams - > timeouttime = Sys_DoubleTime ( ) + 30 ;
}
else
{
newcon - > tcpstreams = NULL ;
newcon - > generic . thesocket = newsocket ;
}
return & newcon - > generic ;
}
else
{
closesocket ( newsocket ) ;
return NULL ;
}
}
2008-12-03 01:25:03 +00:00
# ifdef IPPROTO_IPV6
2009-04-01 22:03:56 +00:00
ftenet_generic_connection_t * FTENET_TCP6Connect_EstablishConnection ( qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
2013-03-31 04:21:08 +00:00
return FTENET_TCPConnect_EstablishConnection ( NA_TCPV6 , isserver , address ) ;
2008-11-09 22:29:28 +00:00
}
2008-12-03 01:25:03 +00:00
# endif
2008-11-09 22:29:28 +00:00
2009-04-01 22:03:56 +00:00
ftenet_generic_connection_t * FTENET_TCP4Connect_EstablishConnection ( qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
2013-03-31 04:21:08 +00:00
return FTENET_TCPConnect_EstablishConnection ( NA_TCP , isserver , address ) ;
2008-11-09 22:29:28 +00:00
}
# endif
# ifdef IRCCONNECT
typedef struct ftenet_ircconnect_stream_s {
char theiruser [ 16 ] ;
int inlen ;
char inbuffer [ 1500 ] ;
float timeouttime ;
netadr_t remoteaddr ;
struct ftenet_ircconnect_stream_s * next ;
} ftenet_ircconnect_stream_t ;
typedef struct {
ftenet_generic_connection_t generic ;
netadr_t ircserver ;
char incoming [ 512 + 1 ] ;
int income ;
char ourusername [ 16 ] ;
char usechannel [ 16 ] ;
char outbuf [ 8192 ] ;
unsigned int outbufcount ;
ftenet_ircconnect_stream_t * streams ;
} ftenet_ircconnect_connection_t ;
qboolean FTENET_IRCConnect_GetPacket ( ftenet_generic_connection_t * gcon )
{
unsigned char * s , * start , * end , * endl ;
int read ;
unsigned char * from ;
int fromlen ;
int code ;
char adr [ 128 ] ;
ftenet_ircconnect_connection_t * con = ( ftenet_ircconnect_connection_t * ) gcon ;
if ( con - > generic . thesocket = = INVALID_SOCKET )
{
if ( con - > income = = 0 )
{
cvar_t * ircuser = Cvar_Get ( " ircuser " , " none " , 0 , " IRC Connect " ) ;
cvar_t * irchost = Cvar_Get ( " irchost " , " none " , 0 , " IRC Connect " ) ;
cvar_t * ircnick = Cvar_Get ( " ircnick " , " ftesv " , 0 , " IRC Connect " ) ;
2011-05-15 13:23:13 +00:00
//cvar_t *ircchannel = Cvar_Get("ircchannel", "#ftetest", 0, "IRC Connect"); //warning: unused variable <20> ircchannel<65>
2008-11-09 22:29:28 +00:00
cvar_t * ircsomething = Cvar_Get ( " ircsomething " , " moo " , 0 , " IRC Connect " ) ;
cvar_t * ircclientaddr = Cvar_Get ( " ircclientaddr " , " 127.0.0.1 " , 0 , " IRC Connect " ) ;
con - > generic . thesocket = TCP_OpenStream ( con - > ircserver ) ;
Q_strncpyz ( con - > ourusername , ircnick - > string , sizeof ( con - > ourusername ) ) ;
send ( con - > generic . thesocket , " USER " , 5 , 0 ) ;
send ( con - > generic . thesocket , ircuser - > string , strlen ( ircuser - > string ) , 0 ) ;
send ( con - > generic . thesocket , " " , 1 , 0 ) ;
send ( con - > generic . thesocket , irchost - > string , strlen ( irchost - > string ) , 0 ) ;
send ( con - > generic . thesocket , " " , 1 , 0 ) ;
send ( con - > generic . thesocket , ircclientaddr - > string , strlen ( ircclientaddr - > string ) , 0 ) ;
send ( con - > generic . thesocket , " : " , 2 , 0 ) ;
send ( con - > generic . thesocket , ircsomething - > string , strlen ( ircsomething - > string ) , 0 ) ;
send ( con - > generic . thesocket , " \r \n " , 2 , 0 ) ;
send ( con - > generic . thesocket , " NICK " , 5 , 0 ) ;
send ( con - > generic . thesocket , con - > ourusername , strlen ( con - > ourusername ) , 0 ) ;
send ( con - > generic . thesocket , " \r \n " , 2 , 0 ) ;
}
}
else
{
read = recv ( con - > generic . thesocket , con - > incoming + con - > income , sizeof ( con - > incoming ) - 1 - con - > income , 0 ) ;
if ( read < 0 )
{
read = qerrno ;
switch ( read )
{
case ECONNABORTED :
case ECONNRESET :
closesocket ( con - > generic . thesocket ) ;
con - > generic . thesocket = INVALID_SOCKET ;
break ;
default :
break ;
}
read = 0 ; //return false;
}
else if ( read = = 0 ) //they disconnected.
{
closesocket ( con - > generic . thesocket ) ;
con - > generic . thesocket = INVALID_SOCKET ;
}
con - > income + = read ;
con - > incoming [ con - > income ] = 0 ;
}
start = con - > incoming ;
end = start + con - > income ;
while ( start < end )
{
endl = NULL ;
for ( s = start ; s < end ; s + + )
{
if ( * s = = ' \n ' )
{
endl = s ;
break ;
}
}
if ( endl = = NULL )
//not got a complete command.
break ;
s = start ;
while ( * s = = ' ' )
s + + ;
if ( * s = = ' : ' )
{
s + + ;
from = s ;
while ( s < endl & & * s ! = ' ' & & * s ! = ' \n ' )
{
s + + ;
}
fromlen = s - from ;
}
else
{
from = NULL ;
fromlen = 0 ;
}
while ( * s = = ' ' )
s + + ;
if ( ! strncmp ( s , " PRIVMSG " , 8 ) )
{
2008-11-13 05:39:50 +00:00
unsigned char * dest ;
2008-11-09 22:29:28 +00:00
s + = 8 ;
while ( * s = = ' ' )
s + + ;
//cap the length
if ( fromlen > sizeof ( net_from . address . irc . user ) - 1 )
fromlen = sizeof ( net_from . address . irc . user ) - 1 ;
for ( code = 0 ; code < fromlen ; code + + )
if ( from [ code ] = = ' ! ' )
{
fromlen = code ;
break ;
}
net_from . type = NA_IRC ;
memcpy ( net_from . address . irc . user , from , fromlen ) ;
net_from . address . irc . user [ fromlen ] = 0 ;
dest = s ;
//discard the destination name
while ( s < endl & & * s ! = ' ' & & * s ! = ' \n ' )
{
s + + ;
}
if ( s - dest > = sizeof ( net_from . address . irc . channel ) )
{ //no space, just pretend it was direct.
net_from . address . irc . channel [ 0 ] = 0 ;
2005-11-30 01:20:53 +00:00
}
2008-11-09 22:29:28 +00:00
else
{
memcpy ( net_from . address . irc . channel , dest , s - dest ) ;
net_from . address . irc . channel [ s - dest ] = 0 ;
if ( ! strcmp ( net_from . address . irc . channel , con - > ourusername ) )
{ //this was aimed at us. clear the channel.
net_from . address . irc . channel [ 0 ] = 0 ;
}
}
2011-05-15 13:23:13 +00:00
2008-11-09 22:29:28 +00:00
while ( * s = = ' ' )
s + + ;
if ( * s = = ' : ' )
{
s + + ;
if ( * s = = ' ! ' )
{
s + + ;
/*interpret as a connectionless packet*/
net_message . cursize = 4 + endl - s ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
{
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
break ;
}
* ( unsigned int * ) net_message_buffer = ~ 0 ;
memcpy ( net_message_buffer + 4 , s , net_message . cursize ) ;
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
//clean up the incoming data
memmove ( con - > incoming , start , end - ( endl + 1 ) ) ;
con - > income = end - ( endl + 1 ) ;
con - > incoming [ con - > income ] = 0 ;
return true ;
}
if ( * s = = ' $ ' )
{
2008-11-14 16:49:26 +00:00
unsigned char * nstart = s ;
2008-11-09 22:29:28 +00:00
while ( * s ! = ' \r ' & & * s ! = ' \n ' & & * s ! = ' # ' & & * s ! = ' ' & & * s ! = ' : ' )
s + + ;
if ( * s = = ' # ' )
{
if ( strncmp ( nstart , con - > ourusername , strlen ( con - > ourusername ) ) | | strlen ( con - > ourusername ) ! = s - nstart )
while ( * s = = ' # ' )
s + + ;
}
}
if ( * s = = ' # ' )
{
ftenet_ircconnect_stream_t * st ;
int psize ;
for ( st = con - > streams ; st ; st = st - > next )
{
if ( ! strncmp ( st - > remoteaddr . address . irc . user , from , fromlen ) & & st - > remoteaddr . address . irc . user [ fromlen ] = = 0 )
break ;
}
if ( ! st )
{
st = Z_Malloc ( sizeof ( * st ) ) ;
st - > remoteaddr = net_from ;
st - > next = con - > streams ;
con - > streams = st ;
}
//skip over the hash
s + + ;
psize = 0 ;
if ( * s > = ' a ' & & * s < = ' f ' )
psize + = * s - ' a ' + 10 ;
else if ( * s > = ' 0 ' & & * s < = ' 9 ' )
psize + = * s - ' 0 ' ;
s + + ;
2011-05-15 13:23:13 +00:00
2008-11-09 22:29:28 +00:00
psize * = 16 ;
if ( * s > = ' a ' & & * s < = ' f ' )
psize + = * s - ' a ' + 10 ;
else if ( * s > = ' 0 ' & & * s < = ' 9 ' )
psize + = * s - ' 0 ' ;
s + + ;
psize * = 16 ;
if ( * s > = ' a ' & & * s < = ' f ' )
psize + = * s - ' a ' + 10 ;
else if ( * s > = ' 0 ' & & * s < = ' 9 ' )
psize + = * s - ' 0 ' ;
s + + ;
while ( s < endl & & st - > inlen < sizeof ( st - > inbuffer ) )
{
switch ( * s )
{
//handle markup
case ' \\ ' :
s + + ;
if ( s < endl )
{
switch ( * s )
{
case ' \\ ' :
st - > inbuffer [ st - > inlen + + ] = * s ;
break ;
case ' n ' :
st - > inbuffer [ st - > inlen + + ] = ' \n ' ;
break ;
case ' r ' :
st - > inbuffer [ st - > inlen + + ] = ' \r ' ;
break ;
case ' 0 ' :
st - > inbuffer [ st - > inlen + + ] = 0 ;
break ;
default :
st - > inbuffer [ st - > inlen + + ] = ' ? ' ;
break ;
}
}
break ;
//ignore these
2011-05-15 13:23:13 +00:00
case ' \n ' :
2008-11-09 22:29:28 +00:00
case ' \r ' :
case ' \0 ' : //this one doesn't have to be ignored.
break ;
//handle normal char
default :
st - > inbuffer [ st - > inlen + + ] = * s ;
break ;
}
s + + ;
}
2011-05-15 13:23:13 +00:00
2008-11-09 22:29:28 +00:00
if ( st - > inlen > psize | | psize > = sizeof ( net_message_buffer ) )
{
st - > inlen = 0 ;
Con_Printf ( " Corrupt packet from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
}
else if ( st - > inlen = = psize )
{
/*interpret as a connectionless packet*/
net_message . cursize = st - > inlen ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
{
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
break ;
}
memcpy ( net_message_buffer , st - > inbuffer , net_message . cursize ) ;
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
st - > inlen = 0 ;
//clean up the incoming data
memmove ( con - > incoming , start , end - ( endl + 1 ) ) ;
con - > income = end - ( endl + 1 ) ;
con - > incoming [ con - > income ] = 0 ;
return true ;
}
}
}
}
else if ( ! strncmp ( s , " PING " , 5 ) )
{
send ( con - > generic . thesocket , " PONG " , 5 , 0 ) ;
send ( con - > generic . thesocket , s + 5 , endl - s - 5 , 0 ) ;
send ( con - > generic . thesocket , " \r \n " , 2 , 0 ) ;
}
else
{
2011-05-19 13:55:05 +00:00
code = strtoul ( s , ( char * * ) & s , 10 ) ;
2008-11-09 22:29:28 +00:00
switch ( code )
{
case 001 :
{
cvar_t * ircchannel = Cvar_Get ( " ircchannel " , " " , 0 , " IRC Connect " ) ;
if ( * ircchannel - > string )
{
send ( con - > generic . thesocket , " JOIN " , 5 , 0 ) ;
send ( con - > generic . thesocket , ircchannel - > string , strlen ( ircchannel - > string ) , 0 ) ;
send ( con - > generic . thesocket , " \r \n " , 2 , 0 ) ;
}
}
break ;
case 433 :
//nick already in use
send ( con - > generic . thesocket , " NICK " , 5 , 0 ) ;
{
cvar_t * ircnick2 = Cvar_Get ( " ircnick2 " , " YIBBLE " , 0 , " IRC Connect " ) ;
Q_strncpyz ( con - > ourusername , ircnick2 - > string , sizeof ( con - > ourusername ) ) ;
send ( con - > generic . thesocket , con - > ourusername , strlen ( con - > ourusername ) , 0 ) ;
}
send ( con - > generic . thesocket , " \r \n " , 2 , 0 ) ;
break ;
2011-05-15 13:23:13 +00:00
case 0 :
2008-11-09 22:29:28 +00:00
//non-numerical event.
break ;
}
}
while ( * s = = ' ' )
s + + ;
start = s = endl + 1 ;
}
memmove ( con - > incoming , start , end - start ) ;
con - > income = end - start ;
con - > incoming [ con - > income ] = 0 ;
if ( con - > generic . thesocket = = INVALID_SOCKET )
con - > income = 0 ;
return false ;
}
qboolean FTENET_IRCConnect_SendPacket ( ftenet_generic_connection_t * gcon , int length , void * data , netadr_t to )
{
ftenet_ircconnect_connection_t * con = ( ftenet_ircconnect_connection_t * ) gcon ;
unsigned char * buffer ;
unsigned char * lenofs ;
int packed ;
int fulllen = length ;
int newoutcount ;
for ( packed = 0 ; packed < FTENET_ADDRTYPES ; packed + + )
if ( to . type = = con - > generic . addrtype [ packed ] )
break ;
if ( packed = = FTENET_ADDRTYPES )
return false ;
packed = 0 ;
if ( con - > generic . thesocket = = INVALID_SOCKET )
return true ;
/*
if ( * ( unsigned int * ) data = = ~ 0 & & ! strchr ( data , ' \n ' ) & & ! strchr ( data , ' \r ' ) & & strlen ( data ) = = length )
{
if ( send ( con - > generic . thesocket , va ( " PRIVMSG %s :! " , to . address . irc . user ) , 15 , 0 ) ! = 15 )
Con_Printf ( " bad send \n " ) ;
else if ( send ( con - > generic . thesocket , ( char * ) data + 4 , length - 4 , 0 ) ! = length - 4 )
Con_Printf ( " bad send \n " ) ;
else if ( send ( con - > generic . thesocket , " \r \n " , 2 , 0 ) ! = 2 )
Con_Printf ( " bad send \n " ) ;
return true ;
}
*/
newoutcount = con - > outbufcount ;
if ( ! con - > outbufcount )
while ( length )
{
buffer = con - > outbuf + newoutcount ;
if ( * to . address . irc . channel )
{
int unamelen ;
int chanlen ;
unamelen = strlen ( to . address . irc . user ) ;
chanlen = strlen ( to . address . irc . channel ) ;
packed = 8 + chanlen + 3 + unamelen + 1 + 3 ;
if ( packed + 1 + newoutcount > sizeof ( con - > outbuf ) )
break ;
memcpy ( buffer , " PRIVMSG " , 8 ) ;
memcpy ( buffer + 8 , to . address . irc . channel , chanlen ) ;
memcpy ( buffer + 8 + chanlen , " :$ " , 3 ) ;
memcpy ( buffer + 8 + chanlen + 3 , to . address . irc . user , unamelen ) ;
memcpy ( buffer + 8 + chanlen + 3 + unamelen , " # " , 1 ) ;
lenofs = buffer + 8 + chanlen + 3 + unamelen + 1 ;
sprintf ( lenofs , " %03x " , fulllen ) ;
}
else
{
int unamelen ;
unamelen = strlen ( to . address . irc . user ) ;
packed = 8 + unamelen + 3 + 3 ;
if ( packed + 1 + newoutcount > sizeof ( con - > outbuf ) )
break ;
memcpy ( buffer , " PRIVMSG " , 8 ) ;
memcpy ( buffer + 8 , to . address . irc . user , unamelen ) ;
memcpy ( buffer + 8 + unamelen , " :# " , 3 ) ;
lenofs = buffer + 8 + unamelen + 3 ;
sprintf ( lenofs , " %03x " , fulllen ) ;
}
while ( length & & packed < 400 & & packed + newoutcount < sizeof ( con - > outbuf ) - 2 ) //make sure there's always space
{
switch ( * ( unsigned char * ) data )
{
case ' \\ ' :
buffer [ packed + + ] = ' \\ ' ;
buffer [ packed + + ] = ' \\ ' ;
break ;
case ' \n ' :
buffer [ packed + + ] = ' \\ ' ;
buffer [ packed + + ] = ' n ' ;
break ;
case ' \r ' :
buffer [ packed + + ] = ' \\ ' ;
buffer [ packed + + ] = ' r ' ;
break ;
case ' \0 ' :
buffer [ packed + + ] = ' \\ ' ;
buffer [ packed + + ] = ' 0 ' ;
break ;
default :
buffer [ packed + + ] = * ( unsigned char * ) data ;
break ;
}
length - - ;
data = ( char * ) data + 1 ;
}
buffer [ packed + + ] = ' \r ' ;
buffer [ packed + + ] = ' \n ' ;
newoutcount + = packed ;
packed = 0 ;
}
if ( ! length )
{
//only if we flushed all
con - > outbufcount = newoutcount ;
}
//try and flush it
length = send ( con - > generic . thesocket , con - > outbuf , con - > outbufcount , 0 ) ;
if ( length > 0 )
{
memmove ( con - > outbuf , con - > outbuf + length , con - > outbufcount - length ) ;
con - > outbufcount - = length ;
}
return true ;
}
void FTENET_IRCConnect_Close ( ftenet_generic_connection_t * gcon )
{
ftenet_ircconnect_connection_t * con = ( ftenet_ircconnect_connection_t * ) gcon ;
ftenet_ircconnect_stream_t * st ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
while ( con - > streams )
{
st = con - > streams ;
con - > streams = st - > next ;
Z_Free ( st ) ;
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
FTENET_Generic_Close ( gcon ) ;
}
2005-11-30 01:20:53 +00:00
2009-11-04 21:16:50 +00:00
struct ftenet_generic_connection_s * FTENET_IRCConnect_EstablishConnection ( qboolean isserver , const char * address )
2008-11-09 22:29:28 +00:00
{
//this is written to support either ipv4 or ipv6, depending on the remote addr.
ftenet_ircconnect_connection_t * newcon ;
netadr_t adr ;
2005-11-30 01:20:53 +00:00
2013-03-12 22:53:23 +00:00
if ( ! NET_StringToAdr ( address , 6667 , & adr ) )
2008-11-09 22:29:28 +00:00
return NULL ; //couldn't resolve the name
2005-11-30 01:20:53 +00:00
2011-05-15 13:23:13 +00:00
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
newcon = Z_Malloc ( sizeof ( * newcon ) ) ;
if ( newcon )
{
newcon - > generic . GetPacket = FTENET_IRCConnect_GetPacket ;
newcon - > generic . SendPacket = FTENET_IRCConnect_SendPacket ;
newcon - > generic . Close = FTENET_IRCConnect_Close ;
2005-11-30 01:20:53 +00:00
2009-07-05 18:45:53 +00:00
newcon - > generic . islisten = isserver ;
2008-11-09 22:29:28 +00:00
newcon - > generic . addrtype [ 0 ] = NA_IRC ;
newcon - > generic . addrtype [ 1 ] = NA_INVALID ;
2007-09-04 20:54:24 +00:00
2008-11-09 22:29:28 +00:00
newcon - > generic . thesocket = INVALID_SOCKET ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
newcon - > ircserver = adr ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
return & newcon - > generic ;
}
else
{
return NULL ;
}
2004-08-21 01:25:48 +00:00
}
2008-11-09 22:29:28 +00:00
# endif
2004-08-21 01:25:48 +00:00
2012-04-09 19:12:12 +00:00
# ifdef HAVE_WEBSOCKCL
# include <ppapi/c/pp_errors.h>
# include <ppapi/c/pp_resource.h>
# include <ppapi/c/ppb_core.h>
# include <ppapi/c/ppb_websocket.h>
# include <ppapi/c/ppb_var.h>
# include <ppapi/c/ppb_instance.h>
extern PPB_Core * ppb_core ;
extern PPB_WebSocket * ppb_websocket_interface ;
extern PPB_Var * ppb_var_interface ;
extern PP_Instance pp_instance ;
typedef struct
{
ftenet_generic_connection_t generic ;
PP_Resource sock ;
netadr_t remoteadr ;
qboolean havepacket ;
struct PP_Var incomingpacket ;
qboolean failed ;
} ftenet_websocket_connection_t ;
static void websocketgot ( void * user_data , int32_t result )
{
ftenet_websocket_connection_t * wsc = user_data ;
if ( result = = PP_OK )
{
wsc - > havepacket = true ;
}
else
{
Sys_Printf ( " %s: %i \n " , __func__ , result ) ;
wsc - > failed = true ;
}
}
static void websocketconnected ( void * user_data , int32_t result )
{
ftenet_websocket_connection_t * wsc = user_data ;
if ( result = = PP_OK )
{
int res ;
//we got a successful connection, enable reception.
struct PP_CompletionCallback ccb = { websocketgot , wsc , PP_COMPLETIONCALLBACK_FLAG_OPTIONAL } ;
res = ppb_websocket_interface - > ReceiveMessage ( wsc - > sock , & wsc - > incomingpacket , ccb ) ;
if ( res ! = PP_OK_COMPLETIONPENDING )
websocketgot ( wsc , res ) ;
}
else
{
Sys_Printf ( " %s: %i \n " , __func__ , result ) ;
//some sort of error connecting, make it timeout now
wsc - > failed = true ;
}
}
static void websocketclosed ( void * user_data , int32_t result )
{
ftenet_websocket_connection_t * wsc = user_data ;
if ( wsc - > havepacket )
{
wsc - > havepacket = false ;
ppb_var_interface - > Release ( wsc - > incomingpacket ) ;
}
ppb_core - > ReleaseResource ( wsc - > sock ) ;
// Z_Free(wsc);
}
static void FTENET_WebSocket_Close ( ftenet_generic_connection_t * gcon )
{
int res ;
/*meant to free the memory too, in this case we get the callback to do it*/
ftenet_websocket_connection_t * wsc = ( void * ) gcon ;
struct PP_CompletionCallback ccb = { websocketclosed , wsc , PP_COMPLETIONCALLBACK_FLAG_NONE } ;
ppb_websocket_interface - > Close ( wsc - > sock , PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE , PP_MakeUndefined ( ) , ccb ) ;
}
static qboolean FTENET_WebSocket_GetPacket ( ftenet_generic_connection_t * gcon )
{
ftenet_websocket_connection_t * wsc = ( void * ) gcon ;
int res ;
int len = 0 ;
if ( wsc - > havepacket )
{
unsigned char * utf8 = ( unsigned char * ) ppb_var_interface - > VarToUtf8 ( wsc - > incomingpacket , & len ) ;
unsigned char * out = ( unsigned char * ) net_message_buffer ;
wsc - > havepacket = false ;
memcpy ( & net_from , & wsc - > remoteadr , sizeof ( net_from ) ) ;
while ( len & & out < net_message_buffer + sizeof ( net_message_buffer ) )
{
if ( ( * utf8 & 0xe0 ) = = 0xc0 & & len > 1 )
{
* out = ( ( utf8 [ 0 ] & 0x1f ) < < 6 ) | ( ( utf8 [ 1 ] & 0x3f ) < < 0 ) ;
utf8 + = 2 ;
len - = 2 ;
}
else if ( * utf8 & 0x80 )
{
* out = ' ? ' ;
utf8 + + ;
len - = 1 ;
}
else
{
* out = utf8 [ 0 ] ;
utf8 + + ;
len - = 1 ;
}
out + + ;
}
net_message . cursize = out - net_message_buffer ;
ppb_var_interface - > Release ( wsc - > incomingpacket ) ;
if ( ! wsc - > failed )
{
//get the next one
struct PP_CompletionCallback ccb = { websocketgot , wsc , PP_COMPLETIONCALLBACK_FLAG_OPTIONAL } ;
res = ppb_websocket_interface - > ReceiveMessage ( wsc - > sock , & wsc - > incomingpacket , ccb ) ;
if ( res ! = PP_OK_COMPLETIONPENDING )
websocketgot ( wsc , res ) ;
}
if ( len )
{
char adr [ 64 ] ;
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
return false ;
}
return true ;
}
return false ;
}
static qboolean FTENET_WebSocket_SendPacket ( ftenet_generic_connection_t * gcon , int length , void * data , netadr_t to )
{
ftenet_websocket_connection_t * wsc = ( void * ) gcon ;
int res ;
int outchars = 0 ;
unsigned char outdata [ length * 2 + 1 ] ;
unsigned char * out = outdata , * in = data ;
if ( wsc - > failed )
return false ;
while ( length - - > 0 )
{
if ( ! * in )
{
2013-03-12 23:09:25 +00:00
//sends 256 instead of 0
2012-04-09 19:12:12 +00:00
* out + + = 0xc0 | ( 0x100 > > 6 ) ;
* out + + = 0x80 | ( 0x100 & 0x3f ) ;
}
else if ( * in > = 0x80 )
{
* out + + = 0xc0 | ( * in > > 6 ) ;
* out + + = 0x80 | ( * in & 0x3f ) ;
}
else
* out + + = * in ;
in + + ;
outchars + + ;
}
* out = 0 ;
struct PP_Var str = ppb_var_interface - > VarFromUtf8 ( outdata , out - outdata ) ;
res = ppb_websocket_interface - > SendMessage ( wsc - > sock , str ) ;
// Sys_Printf("FTENET_WebSocket_SendPacket: result %i\n", res);
ppb_var_interface - > Release ( str ) ;
return true ;
}
/*nacl websockets implementation...*/
static ftenet_generic_connection_t * FTENET_WebSocket_EstablishConnection ( qboolean isserver , const char * address )
{
ftenet_websocket_connection_t * newcon ;
netadr_t adr ;
PP_Resource newsocket ;
if ( isserver | | ! ppb_websocket_interface )
{
return NULL ;
}
2013-03-12 23:09:25 +00:00
if ( ! NET_StringToAdr ( address , 80 , & adr ) )
2012-04-09 19:12:12 +00:00
return NULL ; //couldn't resolve the name
newcon = Z_Malloc ( sizeof ( * newcon ) ) ;
if ( newcon )
{
struct PP_CompletionCallback ccb = { websocketconnected , newcon , PP_COMPLETIONCALLBACK_FLAG_NONE } ;
newsocket = ppb_websocket_interface - > Create ( pp_instance ) ;
struct PP_Var str = ppb_var_interface - > VarFromUtf8 ( adr . address . websocketurl , strlen ( adr . address . websocketurl ) ) ;
ppb_websocket_interface - > Connect ( newsocket , str , NULL , 0 , ccb ) ;
ppb_var_interface - > Release ( str ) ;
2013-03-31 04:21:08 +00:00
Q_strncpyz ( newcon - > generic . name , " WebSocket " , sizeof ( newcon - > generic . name ) ) ;
2012-04-09 19:12:12 +00:00
newcon - > generic . GetPacket = FTENET_WebSocket_GetPacket ;
newcon - > generic . SendPacket = FTENET_WebSocket_SendPacket ;
newcon - > generic . Close = FTENET_WebSocket_Close ;
newcon - > generic . islisten = isserver ;
newcon - > generic . addrtype [ 0 ] = NA_WEBSOCKET ;
newcon - > generic . addrtype [ 1 ] = NA_INVALID ;
newcon - > generic . thesocket = INVALID_SOCKET ;
newcon - > sock = newsocket ;
newcon - > remoteadr = adr ;
return & newcon - > generic ;
}
return NULL ;
}
# endif
2011-10-27 16:16:29 +00:00
/*firstsock is a cookie*/
int NET_GetPacket ( netsrc_t netsrc , int firstsock )
2008-11-09 22:29:28 +00:00
{
ftenet_connections_t * collection ;
2004-08-21 01:25:48 +00:00
if ( netsrc = = NS_SERVER )
{
# ifdef CLIENTONLY
2008-11-09 22:29:28 +00:00
Sys_Error ( " NET_GetPacket: Bad netsrc " ) ;
collection = NULL ;
# else
collection = svs . sockets ;
# endif
}
else
{
# ifdef SERVERONLY
Sys_Error ( " NET_GetPacket: Bad netsrc " ) ;
collection = NULL ;
2004-08-21 01:25:48 +00:00
# else
2008-11-09 22:29:28 +00:00
collection = cls . sockets ;
# endif
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
if ( ! collection )
2011-10-27 16:16:29 +00:00
return - 1 ;
2008-11-09 22:29:28 +00:00
2012-02-12 05:18:31 +00:00
while ( firstsock < MAX_CONNECTIONS )
2008-11-09 22:29:28 +00:00
{
2011-10-27 16:16:29 +00:00
if ( ! collection - > conn [ firstsock ] )
2008-11-09 22:29:28 +00:00
break ;
2011-10-27 16:16:29 +00:00
if ( collection - > conn [ firstsock ] - > GetPacket ( collection - > conn [ firstsock ] ) )
2005-11-30 01:20:53 +00:00
{
2012-02-12 05:18:31 +00:00
if ( net_fakeloss . value )
{
if ( frandom ( ) < net_fakeloss . value )
continue ;
}
2011-10-27 16:16:29 +00:00
net_from . connum = firstsock + 1 ;
return firstsock ;
2008-11-09 22:29:28 +00:00
}
2012-02-12 05:18:31 +00:00
firstsock + = 1 ;
2008-11-09 22:29:28 +00:00
}
2005-11-30 01:20:53 +00:00
2011-10-27 16:16:29 +00:00
return - 1 ;
2008-11-09 22:29:28 +00:00
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
int NET_LocalAddressForRemote ( ftenet_connections_t * collection , netadr_t * remote , netadr_t * local , int idx )
{
if ( ! remote - > connum )
return 0 ;
2005-11-30 01:20:53 +00:00
2011-05-15 13:23:13 +00:00
if ( ! collection - > conn [ remote - > connum - 1 ] )
2008-11-09 22:29:28 +00:00
return 0 ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
if ( ! collection - > conn [ remote - > connum - 1 ] - > GetLocalAddress )
return 0 ;
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
return collection - > conn [ remote - > connum - 1 ] - > GetLocalAddress ( collection - > conn [ remote - > connum - 1 ] , local , idx ) ;
}
void NET_SendPacket ( netsrc_t netsrc , int length , void * data , netadr_t to )
{
2012-02-27 12:23:15 +00:00
char buffer [ 64 ] ;
2008-11-09 22:29:28 +00:00
ftenet_connections_t * collection ;
int i ;
if ( netsrc = = NS_SERVER )
{
# ifdef CLIENTONLY
Sys_Error ( " NET_GetPacket: Bad netsrc " ) ;
2008-11-28 20:34:51 +00:00
return ;
2008-11-09 22:29:28 +00:00
# else
collection = svs . sockets ;
2004-08-21 01:25:48 +00:00
# endif
}
else
{
# ifdef SERVERONLY
2008-11-09 22:29:28 +00:00
Sys_Error ( " NET_GetPacket: Bad netsrc " ) ;
2008-11-28 20:34:51 +00:00
return ;
2004-08-21 01:25:48 +00:00
# else
2008-11-09 22:29:28 +00:00
collection = cls . sockets ;
2005-11-30 01:20:53 +00:00
# endif
2008-11-09 22:29:28 +00:00
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
if ( ! collection )
return ;
2005-11-30 01:20:53 +00:00
2012-02-12 05:18:31 +00:00
if ( net_fakeloss . value )
{
if ( frandom ( ) < net_fakeloss . value )
return ;
}
2008-11-09 22:29:28 +00:00
if ( to . connum )
{
if ( collection - > conn [ to . connum - 1 ] )
if ( collection - > conn [ to . connum - 1 ] - > SendPacket ( collection - > conn [ to . connum - 1 ] , length , data , to ) )
return ;
}
2005-11-30 01:20:53 +00:00
2008-11-09 22:29:28 +00:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( ! collection - > conn [ i ] )
continue ;
if ( collection - > conn [ i ] - > SendPacket ( collection - > conn [ i ] , length , data , to ) )
return ;
2004-08-21 01:25:48 +00:00
}
2005-07-03 15:16:20 +00:00
2012-04-09 19:12:12 +00:00
Con_Printf ( " No route to %s - try reconnecting \n " , NET_AdrToString ( buffer , sizeof ( buffer ) , to ) ) ;
2008-11-09 22:29:28 +00:00
}
2004-08-21 01:25:48 +00:00
2012-01-17 07:57:46 +00:00
qboolean NET_EnsureRoute ( ftenet_connections_t * collection , char * routename , char * host , qboolean islisten )
2008-11-09 22:29:28 +00:00
{
netadr_t adr ;
2012-04-09 19:12:12 +00:00
2013-03-12 22:53:23 +00:00
NET_StringToAdr ( host , 0 , & adr ) ;
2008-11-09 22:29:28 +00:00
switch ( adr . type )
2005-04-17 20:54:43 +00:00
{
2012-04-09 19:12:12 +00:00
case NA_WEBSOCKET :
2008-11-09 22:29:28 +00:00
case NA_TCP :
case NA_TCPV6 :
case NA_IRC :
2013-03-31 04:21:08 +00:00
if ( ! FTENET_AddToCollection ( collection , routename , host , adr . type , islisten ) )
2012-01-17 07:57:46 +00:00
return false ;
2005-04-17 20:54:43 +00:00
break ;
2008-11-09 22:29:28 +00:00
default :
//not recognised, or not needed
break ;
2005-04-17 20:54:43 +00:00
}
2012-01-17 07:57:46 +00:00
return true ;
2008-11-09 22:29:28 +00:00
}
2005-04-17 20:54:43 +00:00
2008-11-09 22:29:28 +00:00
void NET_PrintAddresses ( ftenet_connections_t * collection )
{
int i ;
int adrno , adrcount = 1 ;
netadr_t adr ;
char adrbuf [ MAX_ADR_SIZE ] ;
2004-08-21 01:25:48 +00:00
2008-11-09 22:29:28 +00:00
if ( ! collection )
return ;
2004-08-21 01:25:48 +00:00
2008-11-09 22:29:28 +00:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( ! collection - > conn [ i ] )
continue ;
2013-03-31 04:21:08 +00:00
adrno = 0 ;
2008-11-09 22:29:28 +00:00
if ( collection - > conn [ i ] - > GetLocalAddress )
{
2013-03-31 04:21:08 +00:00
for ( adrcount = 1 ; ( adrcount = collection - > conn [ i ] - > GetLocalAddress ( collection - > conn [ i ] , & adr , adrno ) ) & & adrno < adrcount ; adrno + + )
2008-11-09 22:29:28 +00:00
{
2013-03-31 04:21:08 +00:00
Con_Printf ( " net address (%s): %s \n " , collection - > conn [ i ] - > name , NET_AdrToString ( adrbuf , sizeof ( adrbuf ) , adr ) ) ;
2008-11-09 22:29:28 +00:00
}
}
2013-03-31 04:21:08 +00:00
if ( ! adrno )
Con_Printf ( " net address (%s): no addresses \n " , collection - > conn [ i ] - > name ) ;
2004-08-21 01:25:48 +00:00
}
}
//=============================================================================
2005-11-30 01:20:53 +00:00
int TCP_OpenStream ( netadr_t remoteaddr )
{
2012-04-09 19:12:12 +00:00
# ifndef HAVE_TCP
return INVALID_SOCKET ;
# else
2005-11-30 01:20:53 +00:00
unsigned long _true = true ;
int newsocket ;
int temp ;
struct sockaddr_qstorage qs ;
2012-01-21 07:53:49 +00:00
// struct sockaddr_qstorage loc;
2013-03-31 04:21:08 +00:00
int recvbufsize = ( 1 < < 19 ) ; //512kb
2005-11-30 01:20:53 +00:00
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 ;
2013-03-31 04:21:08 +00:00
setsockopt ( newsocket , SOL_SOCKET , SO_RCVBUF , ( void * ) & recvbufsize , sizeof ( recvbufsize ) ) ;
2012-01-17 07:57:46 +00:00
// memset(&loc, 0, sizeof(loc));
// ((struct sockaddr*)&loc)->sa_family = ((struct sockaddr*)&loc)->sa_family;
// bind(newsocket, (struct sockaddr *)&loc, ((struct sockaddr_in*)&qs)->sin_family == AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6));
2005-11-30 01:20:53 +00:00
if ( connect ( newsocket , ( struct sockaddr * ) & qs , temp ) = = INVALID_SOCKET )
{
2013-03-12 22:44:00 +00:00
int err = qerrno ;
if ( err = = EADDRNOTAVAIL )
{
char buf [ 128 ] ;
NET_AdrToString ( buf , sizeof ( buf ) , remoteaddr ) ;
if ( remoteaddr . port = = 0 & & ( remoteaddr . type = = NA_IP | | remoteaddr . type = = NA_IPV6 ) )
Con_Printf ( " TCP_OpenStream: no port specified \n " ) ;
else
Con_Printf ( " TCP_OpenStream: invalid address trying to connect to %s \n " , buf ) ;
}
else
Con_Printf ( " TCP_OpenStream: connect: error %i \n " , err ) ;
2005-11-30 01:20:53 +00:00
closesocket ( newsocket ) ;
return INVALID_SOCKET ;
}
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " UDP_OpenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
return newsocket ;
2012-04-09 19:12:12 +00:00
# endif
2005-11-30 01:20:53 +00:00
}
2013-03-31 04:21:08 +00:00
/*int TCP_OpenListenSocket (const char *localip, int port)
2005-11-30 01:20:53 +00:00
{
2012-04-09 19:12:12 +00:00
# ifndef HAVE_TCP
return INVALID_SOCKET ;
# else
2005-11-30 01:20:53 +00:00
int newsocket ;
2013-03-31 04:21:08 +00:00
struct sockaddr_qstorage address ;
int pf ;
2005-11-30 01:20:53 +00:00
unsigned long _true = true ;
int i ;
int maxport = port + 100 ;
2013-03-31 04:21:08 +00:00
if ( localip & & * localip )
{
if ( ! NET_StringToSockaddr ( localip , port , & address , & pf , & adrsize ) )
return INVALID_SOCKET ;
}
else
{
adrsize = sizeof ( struct sockaddr_in ) ;
pf = ( ( struct sockaddr_in * ) & address ) - > sin_family = AF_INET ;
( ( struct sockaddr_in * ) & address ) - > sin_port = htons ( port ) ;
//ZOID -- check for interface binding option
if ( ( i = COM_CheckParm ( " -ip " ) ) ! = 0 & & i < com_argc )
{
( ( struct sockaddr_in * ) & address ) - > sin_addr . s_addr = inet_addr ( com_argv [ i + 1 ] ) ;
Con_TPrintf ( TL_NETBINDINTERFACE ,
inet_ntoa ( address . sin_addr ) ) ;
}
else
( ( struct sockaddr_in * ) & address ) - > sin_addr . s_addr = INADDR_ANY ;
}
if ( ( newsocket = socket ( pf , SOCK_STREAM , IPPROTO_TCP ) ) = = INVALID_SOCKET )
2005-11-30 01:20:53 +00:00
return INVALID_SOCKET ;
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " TCP_OpenListenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
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 ;
2012-04-09 19:12:12 +00:00
# endif
2005-11-30 01:20:53 +00:00
}
2013-03-31 04:21:08 +00:00
*/
2005-11-30 01:20:53 +00:00
2012-04-09 19:12:12 +00:00
# if defined(SV_MASTER) || defined(CL_MASTER)
2004-08-21 01:25:48 +00:00
int UDP_OpenSocket ( int port , qboolean bcast )
{
2011-12-23 03:12:29 +00:00
SOCKET newsocket ;
2004-08-21 01:25:48 +00:00
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 )
{
2006-06-27 16:00:41 +00:00
int err ;
2011-12-23 03:12:29 +00:00
SOCKET newsocket ;
2004-08-21 01:25:48 +00:00
struct sockaddr_in6 address ;
unsigned long _true = true ;
// int i;
int maxport = port + 100 ;
2007-07-23 10:56:17 +00:00
memset ( & address , 0 , sizeof ( address ) ) ;
2011-12-23 03:12:29 +00:00
if ( ( newsocket = socket ( PF_INET6 , SOCK_DGRAM , 0 ) ) = = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
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
// }
}
2011-12-05 15:23:40 +00:00
# ifdef IPV6_V6ONLY
setsockopt ( newsocket , IPPROTO_IPV6 , IPV6_V6ONLY , ( char * ) & _true , sizeof ( _true ) ) ;
# endif
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 )
2006-06-27 16:00:41 +00:00
{
err = qerrno ;
Con_Printf ( " UDP6_OpenSocket: bind: (%i) %s " , err , strerror ( err ) ) ;
closesocket ( newsocket ) ;
return INVALID_SOCKET ;
}
2004-08-21 01:25:48 +00:00
port + + ;
if ( port > maxport )
2006-06-27 16:00:41 +00:00
{
err = qerrno ;
Con_Printf ( " UDP6_OpenSocket: bind: (%i) %s " , err , strerror ( err ) ) ;
closesocket ( newsocket ) ;
return INVALID_SOCKET ;
}
2004-08-21 01:25:48 +00:00
}
else
break ;
}
return newsocket ;
}
# endif
void UDP_CloseSocket ( int socket )
{
closesocket ( socket ) ;
}
int IPX_OpenSocket ( int port , qboolean bcast )
{
# ifndef USEIPX
return 0 ;
# else
2011-12-23 03:12:29 +00:00
SOCKET newsocket ;
2004-08-21 01:25:48 +00:00
struct sockaddr_ipx address ;
u_long _true = 1 ;
2011-12-23 03:12:29 +00:00
if ( ( newsocket = socket ( PF_IPX , SOCK_DGRAM , NSPROTO_IPX ) ) = = INVALID_SOCKET )
2004-08-21 01:25:48 +00:00
{
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
}
2012-04-09 19:12:12 +00:00
# endif
2004-08-21 01:25:48 +00:00
// 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 )
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_PACKET
2004-08-21 01:25:48 +00:00
struct timeval timeout ;
fd_set fdset ;
2008-11-09 22:29:28 +00:00
int maxfd ;
int con , sock ;
2004-08-21 01:25:48 +00:00
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
2008-11-09 22:29:28 +00:00
maxfd = 0 ;
if ( svs . sockets )
for ( con = 0 ; con < MAX_CONNECTIONS ; con + + )
2004-08-21 01:25:48 +00:00
{
2008-11-09 22:29:28 +00:00
if ( ! svs . sockets - > conn [ con ] )
continue ;
2012-04-09 19:12:12 +00:00
if ( svs . sockets - > conn [ con ] - > SetReceiveFDSet )
2008-11-09 22:29:28 +00:00
{
2012-04-09 19:12:12 +00:00
sock = svs . sockets - > conn [ con ] - > SetReceiveFDSet ( svs . sockets - > conn [ con ] , & fdset ) ;
2008-11-09 22:29:28 +00:00
if ( sock > maxfd )
maxfd = sock ;
}
2012-04-09 19:12:12 +00:00
else
{
sock = svs . sockets - > conn [ con ] - > thesocket ;
if ( sock ! = INVALID_SOCKET )
{
FD_SET ( sock , & fdset ) ; // network socket
if ( sock > maxfd )
maxfd = sock ;
}
}
2004-08-21 01:25:48 +00:00
}
2008-11-09 22:29:28 +00:00
2004-08-21 01:25:48 +00:00
timeout . tv_sec = msec / 1000 ;
timeout . tv_usec = ( msec % 1000 ) * 1000 ;
2008-11-09 22:29:28 +00:00
select ( maxfd + 1 , & fdset , NULL , NULL , & timeout ) ;
2004-08-21 01:25:48 +00:00
if ( stdinissocket )
return FD_ISSET ( 0 , & fdset ) ;
2012-04-09 19:12:12 +00:00
# endif
2004-08-21 01:25:48 +00:00
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
{
2012-04-09 19:12:12 +00:00
# ifndef HAVE_PACKET
out - > type = NA_INVALID ;
# else
2004-08-21 01:25:48 +00:00
char buff [ 512 ] ;
2008-06-08 14:37:57 +00:00
char adrbuf [ MAX_ADR_SIZE ] ;
2004-08-21 01:25:48 +00:00
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 ;
2013-03-12 22:53:23 +00:00
if ( ! NET_StringToAdr ( buff , 0 , & adr ) ) //urm
NET_StringToAdr ( " 127.0.0.1 " , 0 , & adr ) ;
2005-10-07 16:27:20 +00:00
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 ;
2012-11-27 03:23:19 +00:00
NET_StringToSockaddr ( " 0.0.0.0 " , 0 , ( struct sockaddr_qstorage * ) & address , NULL , NULL ) ;
2005-10-07 16:27:20 +00:00
// 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 ) ;
2008-05-25 01:07:53 +00:00
if ( out - > type = = NA_IP )
{
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
2008-06-08 14:37:57 +00:00
Con_TPrintf ( TL_IPADDRESSIS , NET_AdrToString ( adrbuf , sizeof ( adrbuf ) , * out ) ) ;
2012-04-09 19:12:12 +00:00
# endif
2004-08-21 01:25:48 +00:00
}
2008-11-09 22:29:28 +00:00
# ifndef CLIENTONLY
2011-12-23 03:12:29 +00:00
void SVNET_AddPort_f ( void )
2008-11-09 22:29:28 +00:00
{
char * s = Cmd_Argv ( 1 ) ;
2013-03-31 04:21:08 +00:00
char * conname = Cmd_Argv ( 2 ) ;
if ( ! * s & & ! * conname )
{
Con_Printf ( " Active Server ports: \n " ) ;
NET_PrintAddresses ( svs . sockets ) ;
Con_Printf ( " end of list \n " ) ;
return ;
}
if ( ! * conname )
conname = NULL ;
2008-11-09 22:29:28 +00:00
//just in case
if ( ! svs . sockets )
{
svs . sockets = FTENET_CreateCollection ( true ) ;
# ifndef SERVERONLY
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , " SVLoopback " , " 27500 " , NA_LOOPBACK , true ) ;
2008-11-09 22:29:28 +00:00
# endif
}
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , conname , * s ? s : NULL , * s ? NA_IP : NA_INVALID , true ) ;
}
2008-11-09 22:29:28 +00:00
2013-03-31 04:21:08 +00:00
typedef struct
{
unsigned short msgtype ;
unsigned short msglen ;
unsigned int magiccookie ;
unsigned int transactid [ 3 ] ;
} stunhdr_t ;
typedef struct
{
unsigned short attrtype ;
unsigned short attrlen ;
} stunattr_t ;
static qboolean NET_WasStun ( void )
{
if ( ( net_from . type = = NA_IP | | net_from . type = = NA_IPV6 ) & & net_message . cursize > = 20 )
2008-11-09 22:29:28 +00:00
{
2013-03-31 04:21:08 +00:00
stunhdr_t * stun = ( stunhdr_t * ) net_message . data ;
int stunlen = BigShort ( stun - > msglen ) ;
if ( stun - > msgtype = = BigShort ( 0x0101 ) & & net_message . cursize = = stunlen + sizeof ( * stun ) )
{
stunattr_t * attr = ( stunattr_t * ) ( stun + 1 ) ;
int alen ;
while ( stunlen )
{
stunlen - = sizeof ( * attr ) ;
alen = BigShort ( attr - > attrlen ) ;
if ( alen > stunlen )
return false ;
if ( attr - > attrtype = = BigShort ( 1 ) & & alen = = 8 & & ( ( qbyte * ) attr ) [ 5 ] = = 1 ) //ipv4 MAPPED-ADDRESS
{
netadr_t adr ;
char str [ 256 ] ;
adr . type = NA_IP ;
adr . port = ( ( ( short * ) attr ) [ 3 ] ) ;
memcpy ( adr . address . ip , & ( ( qbyte * ) attr ) [ 8 ] , 4 ) ;
NET_AdrToString ( str , sizeof ( str ) , adr ) ;
Con_Printf ( " Public address %s \n " , str ) ;
}
else if ( attr - > attrtype = = BigShort ( 1 ) & & alen = = 20 & & ( ( qbyte * ) attr ) [ 5 ] = = 2 ) //ipv6 MAPPED-ADDRESS
{
netadr_t adr ;
char str [ 256 ] ;
adr . type = NA_IPV6 ;
adr . port = ( ( ( short * ) attr ) [ 3 ] ) ;
memcpy ( adr . address . ip6 , & ( ( qbyte * ) attr ) [ 8 ] , 16 ) ;
NET_AdrToString ( str , sizeof ( str ) , adr ) ;
Con_Printf ( " Public address %s \n " , str ) ;
}
attr = ( stunattr_t * ) ( ( char * ) ( attr + 1 ) + alen ) ;
}
return true ;
}
}
return false ;
}
void SVNET_Stun_f ( void )
{
char * stunserver = Cmd_Argv ( 1 ) ;
netadr_t stunserverip ;
struct {
stunhdr_t hdr ;
} stunmsg ;
//"stun.l.google.com:19302"
if ( ! NET_StringToAdr ( stunserver , 3478 , & stunserverip ) | | stunserverip . type ! = NA_IP )
{
Con_Printf ( " Specified stun server was not resolved or was not udp v4 \n " ) ;
return ;
}
stunmsg . hdr . magiccookie = BigLong ( 0x2112a442 ) ;
Sys_RandomBytes ( ( qbyte * ) & stunmsg . hdr . transactid [ 0 ] , sizeof ( stunmsg . hdr . transactid ) ) ; // 'and SHOULD be cryptographically random'
stunmsg . hdr . msgtype = BigShort ( 0x0001 ) ; //binding request
stunmsg . hdr . msglen = BigShort ( 0 ) ;
NET_SendPacket ( NS_SERVER , sizeof ( stunmsg ) , & stunmsg , stunserverip ) ;
}
2008-11-09 22:29:28 +00:00
# endif
2013-03-31 04:21:08 +00:00
# ifndef SERVERONLY
void NET_ClientPort_f ( void )
{
Con_Printf ( " Active Client ports: \n " ) ;
NET_PrintAddresses ( cls . sockets ) ;
Con_Printf ( " end of list \n " ) ;
}
2008-11-09 22:29:28 +00:00
# endif
2013-03-31 04:21:08 +00:00
qboolean NET_WasSpecialPacket ( void )
{
# ifndef CLIENTONLY
if ( NET_WasStun ( ) )
return true ;
2008-12-03 01:25:03 +00:00
# endif
2013-03-31 04:21:08 +00:00
# ifdef HAVE_NATPMP
if ( NET_Was_NATPMP ( svs . sockets ) )
return true ;
2008-11-09 22:29:28 +00:00
# endif
2013-03-31 04:21:08 +00:00
return false ;
2008-11-09 22:29:28 +00:00
}
2004-08-21 01:25:48 +00:00
/*
= = = = = = = = = = = = = = = = = = = =
NET_Init
= = = = = = = = = = = = = = = = = = = =
*/
void NET_Init ( void )
{
# ifdef _WIN32
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
r = WSAStartup ( MAKEWORD ( 1 , 1 ) , & winsockdata ) ;
if ( r )
Sys_Error ( " Winsock initialization failed. " ) ;
# endif
2011-12-05 15:23:40 +00:00
Cvar_Register ( & net_hybriddualstack , " networking " ) ;
2012-02-12 05:18:31 +00:00
Cvar_Register ( & net_fakeloss , " networking " ) ;
2011-12-23 03:12:29 +00:00
# ifndef CLIENTONLY
Cmd_AddCommand ( " sv_addport " , SVNET_AddPort_f ) ;
2013-03-31 04:21:08 +00:00
Cmd_AddCommand ( " sv_stun " , SVNET_Stun_f ) ;
# endif
# ifndef SERVERONLY
Cmd_AddCommand ( " cl_addport " , NET_ClientPort_f ) ;
2011-12-23 03:12:29 +00:00
# endif
2004-08-21 01:25:48 +00:00
}
# ifndef SERVERONLY
void NET_InitClient ( void )
{
2009-04-01 22:03:56 +00:00
const char * port ;
2004-08-21 01:25:48 +00:00
int p ;
2011-06-16 02:03:57 +00:00
port = STRINGIFY ( PORT_QWCLIENT ) ;
2005-11-30 01:20:53 +00:00
p = COM_CheckParm ( " -clport " ) ;
if ( p & & p < com_argc )
{
2008-11-09 22:29:28 +00:00
port = com_argv [ p + 1 ] ;
2005-11-30 01:20:53 +00:00
}
2008-11-09 22:29:28 +00:00
cls . sockets = FTENET_CreateCollection ( false ) ;
# ifndef CLIENTONLY
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( cls . sockets , " CLLoopback " , port , NA_LOOPBACK , true ) ;
2004-08-21 01:25:48 +00:00
# endif
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( cls . sockets , " CLUDP4 " , port , NA_IP , true ) ;
2012-04-09 19:12:12 +00:00
# endif
2008-12-01 02:10:35 +00:00
# ifdef IPPROTO_IPV6
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( cls . sockets , " CLUDP6 " , port , NA_IPV6 , true ) ;
2008-12-01 02:10:35 +00:00
# endif
2008-11-13 08:55:41 +00:00
# ifdef USEIPX
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( cls . sockets , " CLIPX " , port , NA_IPX , true ) ;
2008-11-13 08:55:41 +00:00
# endif
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 ;
Con_TPrintf ( TL_CLIENTPORTINITED ) ;
}
# endif
2008-11-09 22:29:28 +00:00
# ifndef CLIENTONLY
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2008-11-09 22:29:28 +00:00
void SV_Tcpport_Callback ( struct cvar_s * var , char * oldvalue )
2004-08-21 01:25:48 +00:00
{
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , var - > name , var - > string , NA_TCP , true ) ;
2008-11-09 22:29:28 +00:00
}
2013-03-31 04:21:08 +00:00
cvar_t sv_port_tcp = CVARC ( " sv_port_tcp " , " " , SV_Tcpport_Callback ) ;
2012-04-09 19:12:12 +00:00
# endif
2008-12-03 07:36:38 +00:00
# ifdef IPPROTO_IPV6
2008-11-09 22:29:28 +00:00
void SV_Tcpport6_Callback ( struct cvar_s * var , char * oldvalue )
{
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , var - > name , var - > string , NA_TCPV6 , true ) ;
2008-11-09 22:29:28 +00:00
}
2013-03-31 04:21:08 +00:00
cvar_t sv_port_tcp6 = CVARC ( " sv_port_tcp6 " , " " , SV_Tcpport6_Callback ) ;
2008-12-03 07:36:38 +00:00
# endif
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2008-11-09 22:29:28 +00:00
void SV_Port_Callback ( struct cvar_s * var , char * oldvalue )
{
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , var - > name , var - > string , NA_IP , true ) ;
2008-11-09 22:29:28 +00:00
}
2013-03-31 04:21:08 +00:00
cvar_t sv_port_ipv4 = CVARC ( " sv_port " , " 27500 " , SV_Port_Callback ) ;
2012-04-09 19:12:12 +00:00
# endif
2005-05-19 02:40:18 +00:00
# ifdef IPPROTO_IPV6
2008-11-09 22:29:28 +00:00
void SV_PortIPv6_Callback ( struct cvar_s * var , char * oldvalue )
{
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , var - > name , var - > string , NA_IPV6 , true ) ;
2008-11-09 22:29:28 +00:00
}
2013-03-31 04:21:08 +00:00
cvar_t sv_port_ipv6 = CVARC ( " sv_port_ipv6 " , " " , SV_PortIPv6_Callback ) ;
2005-05-19 02:40:18 +00:00
# endif
2004-08-21 01:25:48 +00:00
# ifdef USEIPX
2008-11-09 22:29:28 +00:00
void SV_PortIPX_Callback ( struct cvar_s * var , char * oldvalue )
{
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , var - > name , var - > string , NA_IPX , true ) ;
}
cvar_t sv_port_ipx = CVARC ( " sv_port_ipx " , " " , SV_PortIPX_Callback ) ;
# endif
# ifdef HAVE_NATPMP
void SV_Port_NatPMP_Callback ( struct cvar_s * var , char * oldvalue )
{
FTENET_AddToCollection ( svs . sockets , var - > name , va ( " natpmp://%s " , var - > string ) , NA_NATPMP , true ) ;
2008-11-09 22:29:28 +00:00
}
2013-03-31 04:21:08 +00:00
# ifdef SERVERONLY
# define NATPMP_DEFAULT_PORT "" //don't fuck with dedicated servers
# else
# define NATPMP_DEFAULT_PORT "5351" //home users, yay, lucky people.
# endif
cvar_t sv_port_natpmp = CVARCD ( " sv_port_natpmp " , NATPMP_DEFAULT_PORT , SV_Port_NatPMP_Callback , " If set (typically to 5351), automatically configures your router's port forwarding. You can instead specify the full ip address of your router (192.168.1.1:5351 for example). Your router must have NAT-PMP supported and enabled. " ) ;
# endif
void SVNET_RegisterCvars ( void )
{
int p ;
# if defined(TCPCONNECT) && defined(HAVE_IPV4)
Cvar_Register ( & sv_port_tcp , " networking " ) ;
sv_port_tcp . restriction = RESTRICT_MAX ;
# endif
# if defined(TCPCONNECT) && defined(IPPROTO_IPV6)
Cvar_Register ( & sv_port_tcp6 , " networking " ) ;
sv_port_tcp6 . restriction = RESTRICT_MAX ;
# endif
# ifdef IPPROTO_IPV6
Cvar_Register ( & sv_port_ipv6 , " networking " ) ;
sv_port_ipv6 . restriction = RESTRICT_MAX ;
# endif
# ifdef USEIPX
Cvar_Register ( & sv_port_ipx , " networking " ) ;
sv_port_ipx . restriction = RESTRICT_MAX ;
# endif
# ifdef HAVE_IPV4
Cvar_Register ( & sv_port_ipv4 , " networking " ) ;
sv_port_ipv4 . restriction = RESTRICT_MAX ;
# endif
# ifdef HAVE_NATPMP
Cvar_Register ( & sv_port_natpmp , " networking " ) ;
sv_port_natpmp . restriction = RESTRICT_MAX ;
# endif
// parse params for cvars
p = COM_CheckParm ( " -port " ) ;
if ( ! p )
p = COM_CheckParm ( " -svport " ) ;
if ( p & & p < com_argc )
{
extern cvar_t sv_port_ipv4 , sv_port_ipv6 , sv_port_ipx ;
int port = atoi ( com_argv [ p + 1 ] ) ;
if ( ! port )
port = PORT_QWSERVER ;
# ifdef HAVE_IPV4
if ( * sv_port_ipv4 . string )
Cvar_SetValue ( & sv_port_ipv4 , port ) ;
2004-08-21 01:25:48 +00:00
# endif
2013-03-31 04:21:08 +00:00
# ifdef IPPROTO_IPV6
if ( * sv_port_ipv6 . string )
Cvar_SetValue ( & sv_port_ipv6 , port ) ;
# endif
# ifdef USEIPX
if ( * sv_port_ipx . string )
Cvar_SetValue ( & sv_port_ipx , port ) ;
2005-11-30 01:20:53 +00:00
# endif
2013-03-31 04:21:08 +00:00
}
}
2004-08-21 01:25:48 +00:00
2008-11-09 22:29:28 +00:00
void NET_CloseServer ( void )
{
allowconnects = false ;
FTENET_CloseCollection ( svs . sockets ) ;
svs . sockets = NULL ;
2004-08-21 01:25:48 +00:00
}
void NET_InitServer ( void )
{
2008-11-09 22:29:28 +00:00
char * port ;
2011-06-16 02:03:57 +00:00
port = STRINGIFY ( PORT_QWSERVER ) ;
2008-11-09 22:29:28 +00:00
if ( sv_listen_nq . value | | sv_listen_dp . value | | sv_listen_qw . value | | sv_listen_q3 . value )
2004-08-21 01:25:48 +00:00
{
2010-07-18 08:42:59 +00:00
if ( ! svs . sockets )
{
svs . sockets = FTENET_CreateCollection ( true ) ;
2013-03-31 04:21:08 +00:00
# ifndef SERVERONLY
FTENET_AddToCollection ( svs . sockets , " SVLoopback " , port , NA_LOOPBACK , true ) ;
# endif
2010-07-18 08:42:59 +00:00
}
2006-05-09 00:02:05 +00:00
allowconnects = true ;
2004-08-21 01:25:48 +00:00
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2011-10-27 16:16:29 +00:00
Cvar_ForceCallback ( & sv_port_ipv4 ) ;
2012-04-09 19:12:12 +00:00
# endif
2004-08-21 01:25:48 +00:00
# ifdef IPPROTO_IPV6
2006-05-09 00:02:05 +00:00
Cvar_ForceCallback ( & sv_port_ipv6 ) ;
2004-08-21 01:25:48 +00:00
# endif
# ifdef USEIPX
2006-05-09 00:02:05 +00:00
Cvar_ForceCallback ( & sv_port_ipx ) ;
2008-11-09 22:29:28 +00:00
# endif
# ifdef TCPCONNECT
Cvar_ForceCallback ( & sv_port_tcp ) ;
# ifdef IPPROTO_IPV6
Cvar_ForceCallback ( & sv_port_tcp6 ) ;
# endif
2013-03-31 04:21:08 +00:00
# endif
# ifdef HAVE_NATPMP
Cvar_ForceCallback ( & sv_port_natpmp ) ;
2004-08-21 01:25:48 +00:00
# endif
}
else
2010-07-18 08:42:59 +00:00
{
2004-08-21 01:25:48 +00:00
NET_CloseServer ( ) ;
2010-07-18 08:42:59 +00:00
# ifndef SERVERONLY
svs . sockets = FTENET_CreateCollection ( true ) ;
2013-03-31 04:21:08 +00:00
FTENET_AddToCollection ( svs . sockets , " SVLoopback " , port , NA_LOOPBACK , true ) ;
2010-07-18 08:42:59 +00:00
# endif
}
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
2008-11-09 22:29:28 +00:00
FTENET_CloseCollection ( cls . sockets ) ;
cls . sockets = NULL ;
2004-08-21 01:25:48 +00:00
# endif
2008-11-09 22:29:28 +00:00
2004-08-21 01:25:48 +00:00
# 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
2012-04-09 19:12:12 +00:00
# ifdef HAVE_TCP
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 ;
2007-12-01 05:55:44 +00:00
int trying ;
2006-03-14 01:25:46 +00:00
if ( tf - > sock ! = INVALID_SOCKET )
{
2007-12-01 05:55:44 +00:00
trying = sizeof ( tf - > readbuffer ) - tf - > readbuffered ;
if ( trying > 1500 )
trying = 1500 ;
len = recv ( tf - > sock , tf - > readbuffer + tf - > readbuffered , trying , 0 ) ;
2006-03-14 01:25:46 +00:00
if ( len = = - 1 )
{
2013-03-31 04:21:08 +00:00
int e = qerrno ;
if ( e ! = EWOULDBLOCK )
{
switch ( e )
{
case ECONNABORTED :
Sys_Printf ( " conenction aborted \n " , e ) ;
break ;
default :
Sys_Printf ( " socket error %i \n " , e ) ;
}
VFSTCP_Error ( tf ) ;
}
2006-03-14 01:25:46 +00:00
//fixme: figure out wouldblock or error
}
2007-12-01 05:55:44 +00:00
else if ( len = = 0 & & trying ! = 0 )
{
2013-03-31 04:21:08 +00:00
//peer disconnected
2006-03-14 01:25:46 +00:00
VFSTCP_Error ( tf ) ;
2007-12-01 05:55:44 +00:00
}
2006-03-14 01:25:46 +00:00
else
2007-12-01 05:55:44 +00:00
{
2006-03-14 01:25:46 +00:00
tf - > readbuffered + = len ;
2007-12-01 05:55:44 +00:00
}
2006-03-14 01:25:46 +00:00
}
2007-12-01 05:55:44 +00:00
//return a partially filled buffer.
if ( bytestoread > tf - > readbuffered )
bytestoread = tf - > readbuffered ;
if ( bytestoread < 0 )
2007-12-03 11:08:56 +00:00
VFSTCP_Error ( tf ) ;
2007-12-01 05:55:44 +00:00
if ( bytestoread > 0 )
2006-03-14 01:25:46 +00:00
{
memcpy ( buffer , tf - > readbuffer , bytestoread ) ;
tf - > readbuffered - = bytestoread ;
memmove ( tf - > readbuffer , tf - > readbuffer + bytestoread , tf - > readbuffered ) ;
return bytestoread ;
}
else
2007-12-01 05:55:44 +00:00
{
if ( tf - > sock = = INVALID_SOCKET )
return - 1 ; //signal an error
return 0 ; //signal nothing available
}
2006-03-14 01:25:46 +00:00
}
2009-04-01 22:03:56 +00:00
int VFSTCP_WriteBytes ( struct vfsfile_s * file , const void * buffer , int bytestoread )
2006-03-14 01:25:46 +00:00
{
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 )
{
2013-03-31 04:21:08 +00:00
// don't destroy it on write errors, because that prevents us from reading anything that was sent to us afterwards.
// instead let the read handling kill it if there's nothing new to be read
VFSTCP_ReadBytes ( file , NULL , 0 ) ;
2006-03-14 01:25:46 +00:00
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 ) ;
}
2013-03-31 04:21:08 +00:00
vfsfile_t * FS_OpenTCP ( const char * name , int defaultport )
2006-03-14 01:25:46 +00:00
{
tcpfile_t * newf ;
int sock ;
2006-03-23 19:22:12 +00:00
netadr_t adr = { 0 } ;
2013-03-31 04:21:08 +00:00
if ( NET_StringToAdr ( name , defaultport , & adr ) )
2006-03-23 19:22:12 +00:00
{
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 ;
}
2012-04-24 07:59:11 +00:00
# elif 0 //defined(HAVE_WEBSOCKCL)
This code is disabled .
2012-07-14 17:25:21 +00:00
I cannot provide a reliable mechanism over chrome / nacls websockets at this time .
2012-04-24 07:59:11 +00:00
Some module within the ppapi / nacl / chrome stack refuses to forward the data when stressed .
All I can determine is that the connection has a gap .
Hopefully this should be fixed by pepper_19 .
2012-07-14 17:25:21 +00:00
As far as Im aware , this and the relevent code in QTV should be functionally complete .
2012-04-24 07:59:11 +00:00
typedef struct
{
vfsfile_t funcs ;
PP_Resource sock ;
unsigned char readbuffer [ 65536 ] ;
int readbuffered ;
qboolean havepacket ;
struct PP_Var incomingpacket ;
qboolean failed ;
} tcpfile_t ;
static void tcp_websocketgot ( void * user_data , int32_t result )
{
tcpfile_t * wsc = user_data ;
if ( result = = PP_OK )
{
if ( wsc - > incomingpacket . type = = PP_VARTYPE_UNDEFINED )
{
Con_Printf ( " ERROR: %s: var was not set by PPAPI. Data has been lost. \n " , __func__ ) ;
wsc - > failed = true ;
}
wsc - > havepacket = true ;
}
else
{
Sys_Printf ( " %s: %i \n " , __func__ , result ) ;
wsc - > failed = true ;
}
}
static void tcp_websocketconnected ( void * user_data , int32_t result )
{
tcpfile_t * wsc = user_data ;
if ( result = = PP_OK )
{
int res ;
//we got a successful connection, enable reception.
struct PP_CompletionCallback ccb = { tcp_websocketgot , wsc , PP_COMPLETIONCALLBACK_FLAG_NONE } ;
res = ppb_websocket_interface - > ReceiveMessage ( wsc - > sock , & wsc - > incomingpacket , ccb ) ;
if ( res ! = PP_OK_COMPLETIONPENDING )
tcp_websocketgot ( wsc , res ) ;
}
else
{
Sys_Printf ( " %s: %i \n " , __func__ , result ) ;
//some sort of error connecting, make it timeout now
wsc - > failed = true ;
}
}
static void tcp_websocketclosed ( void * user_data , int32_t result )
{
tcpfile_t * wsc = user_data ;
wsc - > failed = true ;
if ( wsc - > havepacket )
{
wsc - > havepacket = false ;
ppb_var_interface - > Release ( wsc - > incomingpacket ) ;
}
ppb_core - > ReleaseResource ( wsc - > sock ) ;
wsc - > sock = 0 ;
// Z_Free(wsc);
}
void VFSTCP_Close ( struct vfsfile_s * file )
{
/*meant to free the memory too, in this case we get the callback to do it*/
tcpfile_t * wsc = ( void * ) file ;
struct PP_CompletionCallback ccb = { tcp_websocketclosed , wsc , PP_COMPLETIONCALLBACK_FLAG_NONE } ;
ppb_websocket_interface - > Close ( wsc - > sock , PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE , PP_MakeUndefined ( ) , ccb ) ;
}
int VFSTCP_ReadBytes ( struct vfsfile_s * file , void * buffer , int bytestoread )
{
tcpfile_t * wsc = ( void * ) file ;
int res ;
if ( wsc - > havepacket & & wsc - > readbuffered < bytestoread + 1024 )
{
if ( wsc - > incomingpacket . type = = PP_VARTYPE_UNDEFINED )
Con_Printf ( " PPAPI bug: var is still undefined after being received \n " ) ;
else
{
int len = 0 ;
unsigned char * utf8 = ( unsigned char * ) ppb_var_interface - > VarToUtf8 ( wsc - > incomingpacket , & len ) ;
unsigned char * out = ( unsigned char * ) wsc - > readbuffer + wsc - > readbuffered ;
wsc - > havepacket = false ;
Con_Printf ( " Len: %i \n " , len ) ;
while ( len & & out < wsc - > readbuffer + sizeof ( wsc - > readbuffer ) )
{
if ( ( * utf8 & 0xe0 ) = = 0xc0 & & len > 1 )
{
* out = ( ( utf8 [ 0 ] & 0x1f ) < < 6 ) | ( ( utf8 [ 1 ] & 0x3f ) < < 0 ) ;
utf8 + = 2 ;
len - = 2 ;
}
else if ( * utf8 & 0x80 )
{
* out = ' ? ' ;
utf8 + + ;
len - = 1 ;
}
else
{
* out = utf8 [ 0 ] ;
utf8 + + ;
len - = 1 ;
}
out + + ;
}
if ( len )
{
Con_Printf ( " oh noes! buffer not big enough! \n " ) ;
wsc - > failed = true ;
}
Con_Printf ( " Old: %i \n " , wsc - > readbuffered ) ;
wsc - > readbuffered = out - wsc - > readbuffer ;
Con_Printf ( " New: %i \n " , wsc - > readbuffered ) ;
ppb_var_interface - > Release ( wsc - > incomingpacket ) ;
wsc - > incomingpacket = PP_MakeUndefined ( ) ;
}
if ( ! wsc - > failed )
{
//get the next one
struct PP_CompletionCallback ccb = { tcp_websocketgot , wsc , PP_COMPLETIONCALLBACK_FLAG_NONE } ;
res = ppb_websocket_interface - > ReceiveMessage ( wsc - > sock , & wsc - > incomingpacket , ccb ) ;
if ( res ! = PP_OK_COMPLETIONPENDING )
tcp_websocketgot ( wsc , res ) ;
}
}
if ( wsc - > readbuffered )
{
// Con_Printf("Reading %i bytes of %i\n", bytestoread, wsc->readbuffered);
if ( bytestoread > wsc - > readbuffered )
bytestoread = wsc - > readbuffered ;
memcpy ( buffer , wsc - > readbuffer , bytestoread ) ;
memmove ( wsc - > readbuffer , wsc - > readbuffer + bytestoread , wsc - > readbuffered - bytestoread ) ;
wsc - > readbuffered - = bytestoread ;
}
else if ( wsc - > failed )
bytestoread = - 1 ; /*signal eof*/
else
bytestoread = 0 ;
return bytestoread ;
}
int VFSTCP_WriteBytes ( struct vfsfile_s * file , const void * buffer , int bytestowrite )
{
tcpfile_t * wsc = ( void * ) file ;
int res ;
int outchars = 0 ;
unsigned char outdata [ bytestowrite * 2 + 1 ] ;
unsigned char * out = outdata ;
const unsigned char * in = buffer ;
if ( wsc - > failed )
return 0 ;
for ( res = 0 ; res < bytestowrite ; res + + )
{
/*FIXME: do we need this code?*/
if ( ! * in )
{
* out + + = 0xc0 | ( 0x100 > > 6 ) ;
* out + + = 0x80 | ( 0x100 & 0x3f ) ;
}
else if ( * in > = 0x80 )
{
* out + + = 0xc0 | ( * in > > 6 ) ;
* out + + = 0x80 | ( * in & 0x3f ) ;
}
else
* out + + = * in ;
in + + ;
outchars + + ;
}
* out = 0 ;
struct PP_Var str = ppb_var_interface - > VarFromUtf8 ( outdata , out - outdata ) ;
res = ppb_websocket_interface - > SendMessage ( wsc - > sock , str ) ;
// Sys_Printf("FTENET_WebSocket_SendPacket: result %i\n", res);
ppb_var_interface - > Release ( str ) ;
if ( res = = PP_OK )
return bytestowrite ;
return 0 ;
}
qboolean VFSTCP_Seek ( struct vfsfile_s * file , unsigned long pos )
{
//no seeking allowed
tcpfile_t * wsc = ( void * ) file ;
Con_Printf ( " tcp seek? \n " ) ;
wsc - > failed = true ;
return false ;
}
unsigned long VFSTCP_Tell ( struct vfsfile_s * file )
{
//no telling allowed
tcpfile_t * wsc = ( void * ) file ;
Con_Printf ( " tcp tell? \n " ) ;
wsc - > failed = true ;
return 0 ;
}
unsigned long VFSTCP_GetLen ( struct vfsfile_s * file )
{
return 0 ;
}
/*nacl websockets implementation...*/
2013-03-31 04:21:08 +00:00
vfsfile_t * FS_OpenTCP ( const char * name , int defaultport )
2012-04-24 07:59:11 +00:00
{
tcpfile_t * newf ;
netadr_t adr ;
if ( ! ppb_websocket_interface )
{
return NULL ;
}
2013-03-31 04:21:08 +00:00
if ( ! NET_StringToAdr ( name , defaultport , & adr ) )
2012-04-24 07:59:11 +00:00
return NULL ; //couldn't resolve the name
newf = Z_Malloc ( sizeof ( * newf ) ) ;
if ( newf )
{
struct PP_CompletionCallback ccb = { tcp_websocketconnected , newf , PP_COMPLETIONCALLBACK_FLAG_NONE } ;
newf - > sock = ppb_websocket_interface - > Create ( pp_instance ) ;
struct PP_Var str = ppb_var_interface - > VarFromUtf8 ( adr . address . websocketurl , strlen ( adr . address . websocketurl ) ) ;
ppb_websocket_interface - > Connect ( newf - > sock , str , NULL , 0 , ccb ) ;
ppb_var_interface - > Release ( str ) ;
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 ;
}
return NULL ;
}
2012-04-09 19:12:12 +00:00
# else
2013-03-31 04:21:08 +00:00
vfsfile_t * FS_OpenTCP ( const char * name , int defaultport )
2012-04-09 19:12:12 +00:00
{
return NULL ;
}
# endif