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 ) ;
2013-05-03 04:28:08 +00:00
qboolean ( * SendPacket ) ( struct ftenet_generic_connection_s * con , int length , void * data , netadr_t * to ) ;
2013-03-31 04:21:08 +00:00
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 ;
2013-07-31 00:20:16 +00:00
# ifdef HAVE_PACKET
2013-06-24 09:04:00 +00:00
SOCKET thesocket ;
2013-07-31 00:20:16 +00:00
# else
int thesocket ;
# endif
2013-03-31 04:21:08 +00:00
} 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 ;
2013-04-02 05:18:17 +00:00
* ( int * ) & ( ( struct sockaddr_in * ) s ) - > sin_addr = 0xffffffff ; //INADDR_BROADCAST;
2004-08-21 01:25:48 +00:00
( ( struct sockaddr_in * ) s ) - > sin_port = a - > port ;
2005-11-30 01:20:53 +00:00
return sizeof ( struct sockaddr_in ) ;
2004-08-21 01:25:48 +00:00
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 ;
}
}
2013-05-03 04:28:08 +00:00
qboolean NET_CompareAdr ( netadr_t * a , netadr_t * b )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +00:00
if ( a - > type ! = b - > type )
2013-03-31 04:21:08 +00:00
{
int i ;
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IP & & b - > type = = NA_IPV6 )
2013-03-31 04:21:08 +00:00
{
for ( i = 0 ; i < 10 ; i + + )
2013-05-03 04:28:08 +00:00
if ( b - > address . ip6 [ i ] ! = 0 )
2013-03-31 04:21:08 +00:00
return false ; //only matches if they're 0s, otherwise its not an ipv4 address there
for ( ; i < 12 ; i + + )
2013-05-03 04:28:08 +00:00
if ( b - > address . ip6 [ i ] ! = 0xff & & b - > address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
2013-03-31 04:21:08 +00:00
return false ; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there
for ( i = 0 ; i < 4 ; i + + )
{
2013-05-03 04:28:08 +00:00
if ( a - > address . ip [ i ] ! = b - > address . ip6 [ 12 + i ] )
2013-03-31 04:21:08 +00:00
return false ; //mask doesn't match
}
return true ; //its an ipv4 address in there, the mask matched the whole way through
}
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IPV6 & & b - > type = = NA_IP )
2013-03-31 04:21:08 +00:00
{
for ( i = 0 ; i < 10 ; i + + )
2013-05-03 04:28:08 +00:00
if ( a - > address . ip6 [ i ] ! = 0 )
2013-03-31 04:21:08 +00:00
return false ; //only matches if they're 0s, otherwise its not an ipv4 address there
for ( ; i < 12 ; i + + )
2013-05-03 04:28:08 +00:00
if ( a - > address . ip6 [ i ] ! = 0xff & & a - > address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
2013-03-31 04:21:08 +00:00
return false ; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there
for ( i = 0 ; i < 4 ; i + + )
{
2013-05-03 04:28:08 +00:00
if ( a - > address . ip6 [ 12 + i ] ! = b - > address . ip [ i ] )
2013-03-31 04:21:08 +00:00
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
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_LOOPBACK )
2004-08-21 01:25:48 +00:00
return true ;
2012-04-09 19:12:12 +00:00
# ifdef HAVE_WEBSOCKCL
2013-05-07 19:36:42 +00:00
if ( a - > type = = NA_WEBSOCKET )
2012-04-09 19:12:12 +00:00
{
2013-05-07 19:36:42 +00:00
if ( ! strcmp ( a - > address . websocketurl , a - > address . websocketurl ) & & a - > port = = b - > port )
2012-04-09 19:12:12 +00:00
return true ;
return false ;
}
# endif
# ifdef HAVE_IPV4
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IP | | a - > type = = NA_BROADCAST_IP | | a - > type = = NA_TCP )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IPV6 | | a - > type = = NA_BROADCAST_IP6 | | a - > type = = NA_TCPV6 )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IPX | | a - > type = = NA_BROADCAST_IPX )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IRC )
2008-11-09 22:29:28 +00:00
{
2013-05-03 04:28:08 +00:00
if ( ! strcmp ( a - > address . irc . user , b - > address . irc . user ) )
2008-11-09 22:29:28 +00:00
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
= = = = = = = = = = = = = = = = = = =
*/
2013-05-03 04:28:08 +00:00
qboolean NET_CompareBaseAdr ( netadr_t * a , netadr_t * b )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +00:00
if ( a - > type ! = b - > type )
2004-08-21 01:25:48 +00:00
return false ;
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_LOOPBACK )
2004-08-21 01:25:48 +00:00
return true ;
2012-04-09 19:12:12 +00:00
# ifdef HAVE_IPV4
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IP | | a - > type = = NA_TCP )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IPV6 | | a - > type = = NA_BROADCAST_IP6 )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IPX )
2004-08-21 01:25:48 +00:00
{
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
if ( a - > type = = NA_IRC )
2008-11-09 22:29:28 +00:00
{
2013-05-03 04:28:08 +00:00
if ( ! strcmp ( a - > address . irc . user , b - > address . irc . user ) )
2008-11-09 22:29:28 +00:00
return true ;
return false ;
}
# endif
2004-08-21 01:25:48 +00:00
Sys_Error ( " NET_CompareBaseAdr: Bad address type " ) ;
return false ;
}
2013-05-03 04:28:08 +00:00
qboolean NET_AddressSmellsFunny ( netadr_t * a )
2008-05-25 01:07:53 +00:00
{
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
2013-05-03 04:28:08 +00:00
switch ( a - > type )
2008-05-25 01:07:53 +00:00
{
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
2013-05-03 04:28:08 +00:00
if ( a - > address . ip [ 0 ] = = 127 ) // && a->address.ip[1] == 0 && a->address.ip[2] == 0 && a->address.ip[3] == 1 )
2008-05-25 01:07:53 +00:00
return true ;
//'this' network (not an issue, but lets reject it anyway)
2013-05-03 04:28:08 +00:00
if ( a - > address . ip [ 0 ] = = 0 & & a - > address . ip [ 1 ] = = 0 & & a - > address . ip [ 2 ] = = 0 & & a - > address . ip [ 3 ] = = 0 )
2008-05-25 01:07:53 +00:00
return true ;
//reject any broadcasts
2013-05-03 04:28:08 +00:00
if ( a - > address . ip [ 0 ] = = 255 & & a - > address . ip [ 1 ] = = 255 & & a - > address . ip [ 2 ] = = 255 & & a - > address . ip [ 3 ] = = 0 )
2008-05-25 01:07:53 +00:00
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 + + )
2013-05-03 04:28:08 +00:00
if ( a - > address . ip6 [ i ] )
2008-05-25 01:07:53 +00:00
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 ;
}
}
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
switch ( a - > type )
2004-08-21 01:25:48 +00:00
{
2012-04-09 19:12:12 +00:00
# ifdef HAVE_WEBSOCKCL
case NA_WEBSOCKET :
2013-05-07 19:36:42 +00:00
Q_strncpyz ( s , a - > address . websocketurl , len ) ;
2012-04-09 19:12:12 +00:00
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 :
2013-05-03 04:28:08 +00:00
if ( a - > port )
2010-11-28 19:15:37 +00:00
{
2011-05-15 13:23:13 +00:00
snprintf ( s , len , " %i.%i.%i.%i:%i " ,
2013-05-03 04:28:08 +00:00
a - > address . ip [ 0 ] ,
a - > address . ip [ 1 ] ,
a - > address . ip [ 2 ] ,
a - > address . ip [ 3 ] ,
ntohs ( a - > port ) ) ;
2010-11-28 19:15:37 +00:00
}
else
{
2011-05-15 13:23:13 +00:00
snprintf ( s , len , " %i.%i.%i.%i " ,
2013-05-03 04:28:08 +00:00
a - > address . ip [ 0 ] ,
a - > address . ip [ 1 ] ,
a - > address . ip [ 2 ] ,
a - > address . ip [ 3 ] ) ;
2010-11-28 19:15:37 +00:00
}
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
2013-05-03 04:28:08 +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 )
2011-12-05 15:23:40 +00:00
{
2013-05-03 04:28:08 +00:00
if ( a - > port )
2011-12-05 15:23:40 +00:00
snprintf ( s , len , " %i.%i.%i.%i:%i " ,
2013-05-03 04:28:08 +00:00
a - > address . ip6 [ 12 ] ,
a - > address . ip6 [ 13 ] ,
a - > address . ip6 [ 14 ] ,
a - > address . ip6 [ 15 ] ,
ntohs ( a - > port ) ) ;
2011-12-05 15:23:40 +00:00
else
snprintf ( s , len , " %i.%i.%i.%i " ,
2013-05-03 04:28:08 +00:00
a - > address . ip6 [ 12 ] ,
a - > address . ip6 [ 13 ] ,
a - > address . ip6 [ 14 ] ,
a - > address . ip6 [ 15 ] ) ;
2011-12-05 15:23:40 +00:00
break ;
}
2008-06-08 20:41:22 +00:00
* s = 0 ;
2008-05-25 01:07:53 +00:00
doneblank = false ;
p = s ;
2013-06-23 02:17:02 +00:00
if ( a - > port )
{
snprintf ( s , len - strlen ( s ) , " [ " ) ;
p + = strlen ( p ) ;
}
2008-05-25 01:07:53 +00:00
for ( i = 0 ; i < 16 ; i + = 2 )
{
2013-05-03 04:28:08 +00:00
if ( doneblank ! = true & & a - > address . ip6 [ i ] = = 0 & & a - > address . ip6 [ i + 1 ] = = 0 )
2008-05-25 01:07:53 +00:00
{
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 ) ;
}
2013-05-03 04:28:08 +00:00
if ( a - > address . ip6 [ i + 0 ] )
2008-05-25 01:07:53 +00:00
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x%02x " ,
2013-05-03 04:28:08 +00:00
a - > address . ip6 [ i + 0 ] ,
a - > address . ip6 [ i + 1 ] ) ;
2008-05-25 01:07:53 +00:00
}
else
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x " ,
2013-05-03 04:28:08 +00:00
a - > address . ip6 [ i + 1 ] ) ;
2008-05-25 01:07:53 +00:00
}
p + = strlen ( p ) ;
}
}
2013-06-23 02:17:02 +00:00
if ( a - > port )
snprintf ( p , len - strlen ( s ) , " ]:%i " ,
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 " ,
2013-05-03 04:28:08 +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 :
2013-05-03 04:28:08 +00:00
if ( * a - > address . irc . channel )
snprintf ( s , len , " irc://%s@%s " , a - > address . irc . user , a - > address . irc . channel ) ;
2008-11-09 22:29:28 +00:00
else
2013-05-03 04:28:08 +00:00
snprintf ( s , len , " irc://%s " , a - > address . irc . user ) ;
2008-11-09 22:29:28 +00:00
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
}
2013-05-03 04:28:08 +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
2013-05-03 04:28:08 +00:00
switch ( a - > type )
2004-08-21 01:25:48 +00:00
{
case NA_BROADCAST_IP :
case NA_IP :
2011-05-15 13:23:13 +00:00
snprintf ( s , len , " %i.%i.%i.%i " ,
2013-05-03 04:28:08 +00:00
a - > address . ip [ 0 ] ,
a - > address . ip [ 1 ] ,
a - > address . ip [ 2 ] ,
a - > address . ip [ 3 ] ) ;
2004-08-21 01:25:48 +00:00
break ;
2012-01-17 07:57:46 +00:00
case NA_TCP :
snprintf ( s , len , " tcp://%i.%i.%i.%i " ,
2013-05-03 04:28:08 +00:00
a - > address . ip [ 0 ] ,
a - > address . ip [ 1 ] ,
a - > address . ip [ 2 ] ,
a - > address . ip [ 3 ] ) ;
2012-01-17 07:57:46 +00:00
break ;
2004-08-21 01:25:48 +00:00
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
2013-05-03 04:28:08 +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 )
2011-12-05 15:23:40 +00:00
{
snprintf ( s , len , " %i.%i.%i.%i " ,
2013-05-03 04:28:08 +00:00
a - > address . ip6 [ 12 ] ,
a - > address . ip6 [ 13 ] ,
a - > address . ip6 [ 14 ] ,
a - > address . ip6 [ 15 ] ) ;
2011-12-05 15:23:40 +00:00
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 )
{
2013-05-03 04:28:08 +00:00
if ( doneblank ! = true & & a - > address . ip6 [ i ] = = 0 & & a - > address . ip6 [ i + 1 ] = = 0 )
2008-05-25 01:07:53 +00:00
{
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 ) ;
}
2013-05-03 04:28:08 +00:00
if ( a - > address . ip6 [ i + 0 ] )
2008-05-25 01:07:53 +00:00
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x%02x " ,
2013-05-03 04:28:08 +00:00
a - > address . ip6 [ i + 0 ] ,
a - > address . ip6 [ i + 1 ] ) ;
2008-05-25 01:07:53 +00:00
}
else
{
2008-06-08 20:20:11 +00:00
snprintf ( p , len - strlen ( s ) , " %x " ,
2013-05-03 04:28:08 +00:00
a - > address . ip6 [ i + 1 ] ) ;
2008-05-25 01:07:53 +00:00
}
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 " ,
2013-05-03 04:28:08 +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 :
2013-05-03 04:28:08 +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 :
2013-05-03 04:28:08 +00:00
NET_AdrToString ( s , len , a ) ;
2008-11-09 22:29:28 +00:00
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
2013-05-11 05:03:07 +00:00
# ifdef pgetaddrinfo
if ( 1 )
# else
2006-06-30 15:45:16 +00:00
if ( pgetaddrinfo )
2013-05-11 05:03:07 +00:00
# endif
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)
2013-04-08 11:27:39 +00:00
if ( ! NET_StringToSockaddr ( s + 6 , defaultport , & 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 ;
2013-05-03 04:28:08 +00:00
char * slash ;
2008-11-09 22:29:28 +00:00
memset ( a , 0 , sizeof ( * a ) ) ;
a - > type = NA_IRC ;
s + = 6 ;
2013-05-03 04:28:08 +00:00
slash = strchr ( s , ' / ' ) ;
if ( ! slash )
return false ;
if ( slash - s + 1 > = sizeof ( a - > address . irc . host ) )
return false ;
memcpy ( a - > address . irc . host , s , slash - s ) ;
a - > address . irc . host [ slash - s ] = 0 ;
s = slash + 1 ;
2008-11-09 22:29:28 +00:00
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 ) ;
2013-04-08 11:27:39 +00:00
# if !defined(HAVE_PACKET) && defined(HAVE_TCP)
//bump over protocols that cannot work in the first place.
if ( a - > type = = NA_IP )
a - > type = NA_TCP ;
if ( a - > type = = NA_IPV6 )
a - > type = NA_TCPV6 ;
# endif
2004-08-21 01:25:48 +00:00
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
2013-05-11 05:03:07 +00:00
case NA_NATPMP :
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
2013-05-03 04:28:08 +00:00
qboolean NET_CompareAdrMasked ( netadr_t * a , netadr_t * b , netadr_t * mask )
2006-05-22 22:51:14 +00:00
{
int i ;
2008-05-25 01:07:53 +00:00
//make sure the address being checked against matches the mask
2013-05-03 04:28:08 +00:00
if ( b - > type ! = mask - > type )
2006-05-22 22:51:14 +00:00
return false ;
// check port if both are non-zero
2013-05-03 04:28:08 +00:00
if ( a - > port & & b - > port & & a - > port ! = b - > port )
2006-05-22 22:51:14 +00:00
return false ;
2008-05-25 01:07:53 +00:00
// check to make sure all types match
2013-05-03 04:28:08 +00:00
if ( a - > type ! = b - > type )
2008-05-25 01:07:53 +00:00
{
2013-05-03 04:28:08 +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 + + )
2013-05-03 04:28:08 +00:00
if ( b - > address . ip6 [ i ] ! = 0 )
2011-10-27 16:16:29 +00:00
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 + + )
2013-05-03 04:28:08 +00:00
if ( b - > address . ip6 [ i ] ! = 0xff & & b - > address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
2011-10-27 16:16:29 +00:00
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
{
2013-05-03 04:28:08 +00:00
if ( ( a - > address . ip [ i ] & mask - > address . ip [ i ] ) ! = ( b - > address . ip6 [ 12 + i ] & mask - > address . ip [ i ] ) )
2011-10-27 16:16:29 +00:00
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
}
2013-05-03 04:28:08 +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 + + )
2013-05-03 04:28:08 +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 + + )
2013-05-03 04:28:08 +00:00
if ( a - > address . ip6 [ i ] ! = 0xff & & a - > address . ip6 [ i ] ! = 0x00 ) //0x00 is depricated
2011-01-29 21:01:40 +00:00
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 + + )
{
2013-05-03 04:28:08 +00:00
if ( ( a - > address . ip6 [ 12 + i ] & mask - > address . ip [ i ] ) ! = ( b - > address . ip [ i ] & mask - > address . ip [ i ] ) )
2008-05-25 01:07:53 +00:00
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
2013-05-03 04:28:08 +00:00
switch ( a - > type )
2006-05-22 22:51:14 +00:00
{
case NA_LOOPBACK :
return true ;
case NA_BROADCAST_IP :
case NA_IP :
for ( i = 0 ; i < 4 ; i + + )
{
2013-05-03 04:28:08 +00:00
if ( ( a - > address . ip [ i ] & mask - > address . ip [ i ] ) ! = ( b - > address . ip [ i ] & mask - > address . ip [ i ] ) )
2006-05-22 22:51:14 +00:00
return false ;
}
break ;
# ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6 :
case NA_IPV6 :
for ( i = 0 ; i < 16 ; i + + )
{
2013-05-03 04:28:08 +00:00
if ( ( a - > address . ip6 [ i ] & mask - > address . ip6 [ i ] ) ! = ( b - > address . ip6 [ i ] & mask - > address . ip6 [ i ] ) )
2006-05-22 22:51:14 +00:00
return false ;
}
break ;
# endif
# ifdef USEIPX
case NA_BROADCAST_IPX :
case NA_IPX :
for ( i = 0 ; i < 10 ; i + + )
{
2013-05-03 04:28:08 +00:00
if ( ( a - > address . ipx [ i ] & mask - > address . ipx [ i ] ) ! = ( b - > address . ipx [ i ] & mask - > address . ipx [ i ] ) )
2006-05-22 22:51:14 +00:00
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
2013-05-03 04:28:08 +00:00
if ( strcmp ( a - > address . irc . user , b - > address . irc . user ) )
2008-11-09 22:29:28 +00:00
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
2013-05-03 04:28:08 +00:00
int UniformMaskedBits ( netadr_t * mask )
2006-05-22 22:51:14 +00:00
{
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 ;
2013-05-03 04:28:08 +00:00
switch ( mask - > type )
2006-05-22 22:51:14 +00:00
{
case NA_BROADCAST_IP :
case NA_IP :
bits = 32 ;
for ( b = 3 ; b > = 0 ; b - - )
{
2013-05-03 04:28:08 +00:00
if ( mask - > address . ip [ b ] = = 0xFF )
2006-05-22 22:51:14 +00:00
bitenc = true ;
2013-05-03 04:28:08 +00:00
else if ( mask - > address . ip [ b ] )
2006-05-22 22:51:14 +00:00
{
2013-05-03 04:28:08 +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 - - )
{
2013-05-03 04:28:08 +00:00
if ( mask - > address . ip6 [ b ] = = 0xFF )
2006-05-22 22:51:14 +00:00
bitenc = true ;
2013-05-03 04:28:08 +00:00
else if ( mask - > address . ip6 [ b ] )
2006-05-22 22:51:14 +00:00
{
2013-05-03 04:28:08 +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 - - )
{
2013-05-03 04:28:08 +00:00
if ( mask - > address . ipx [ b ] = = 0xFF )
2006-05-22 22:51:14 +00:00
bitenc = true ;
2013-05-03 04:28:08 +00:00
else if ( mask - > address . ipx [ b ] )
2006-05-22 22:51:14 +00:00
{
2013-05-03 04:28:08 +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
}
2013-05-03 04:28:08 +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
}
2013-05-03 04:28:08 +00:00
qboolean NET_IsLoopBackAddress ( netadr_t * adr )
2004-08-21 01:25:48 +00:00
{
// return (!strcmp(cls.servername, NET_AdrToString(net_local_adr)) || !strcmp(cls.servername, "local");
2013-05-03 04:28:08 +00:00
return adr - > type = = NA_LOOPBACK ;
2004-08-21 01:25:48 +00:00
}
/////////////////////////////////////////////
//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-05-03 04:28: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-05-03 04:28:08 +00:00
qboolean FTENET_Loop_SendPacket ( ftenet_generic_connection_t * con , int length , void * data , netadr_t * to )
2013-03-31 04:21:08 +00:00
{
2013-05-03 04:28:08 +00:00
if ( to - > type = = NA_LOOPBACK )
2013-03-31 04:21:08 +00:00
{
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 ) ;
2013-05-11 05:03:07 +00:00
# ifdef USEIPX
2013-03-31 04:21:08 +00:00
static ftenet_generic_connection_t * FTENET_IPX_EstablishConnection ( qboolean isserver , const char * address ) ;
2013-05-11 05:03:07 +00:00
# endif
# ifdef HAVE_WEBSOCKCL
2013-03-31 04:21:08 +00:00
static ftenet_generic_connection_t * FTENET_WebSocket_EstablishConnection ( qboolean isserver , const char * address ) ;
2013-05-11 05:03:07 +00:00
# endif
2013-03-31 04:21:08 +00:00
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 ] ;
2013-05-03 04:28:08 +00:00
if ( NET_CompareAdr ( & pmp - > pmpaddr , & net_from ) )
2013-03-31 04:21:08 +00:00
{
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 ) ) ;
2013-05-03 04:28:08 +00:00
NET_AdrToString ( adrbuf , sizeof ( adrbuf ) , & pmp - > natadr ) ;
2013-03-31 04:21:08 +00:00
// 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 ;
2013-04-04 08:08:49 +00:00
if ( * ( int * ) pmp - > pmpaddr . address . ip = = INADDR_ANY )
continue ;
2013-03-31 04:21:08 +00:00
//get the public ip.
pmpreqmsg . op = 0 ;
2013-05-03 04:28:08 +00:00
NET_SendPacket ( NS_SERVER , 2 , & pmpreqmsg , & pmp - > pmpaddr ) ;
2013-03-31 04:21:08 +00:00
//open the firewall/nat.
pmpreqmsg . op = 1 ;
2013-05-03 04:28:08 +00:00
NET_SendPacket ( NS_SERVER , sizeof ( pmpreqmsg ) , & pmpreqmsg , & pmp - > pmpaddr ) ;
2013-04-04 08:08:49 +00:00
break ;
2013-03-31 04:21:08 +00:00
}
}
}
}
# 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 ;
}
2013-05-03 04:28:08 +00:00
qboolean FTENET_NATPMP_SendPacket ( struct ftenet_generic_connection_s * con , int length , void * data , netadr_t * to )
2013-03-31 04:21:08 +00:00
{
return false ;
}
2013-04-04 08:08:49 +00:00
void FTENET_NATPMP_Close ( struct ftenet_generic_connection_s * con )
2013-03-31 04:21:08 +00:00
{
//FIXME: we should send a packet to close the port
Z_Free ( con ) ;
}
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 ;
2013-05-11 05:03:07 +00:00
# ifdef USE_GETHOSTNAME_LOCALLISTING
2008-11-09 22:29:28 +00:00
char adrs [ MAX_ADR_SIZE ] ;
int b ;
2013-05-11 05:03:07 +00:00
# endif
2008-11-09 22:29:28 +00:00
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 ,
2013-05-03 04:28:08 +00:00
NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2008-11-09 22:29:28 +00:00
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 ) )
{
2013-05-03 04:28:08 +00:00
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
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
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
2013-05-03 04:28:08 +00:00
qboolean FTENET_Generic_SendPacket ( ftenet_generic_connection_t * con , int length , void * data , netadr_t * to )
2008-11-09 22:29:28 +00:00
{
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 + + )
2013-05-03 04:28:08 +00:00
if ( to - > type = = con - > addrtype [ size ] )
2008-11-09 22:29:28 +00:00
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*/
2013-05-03 04:28:08 +00:00
if ( con - > addrtype [ 1 ] = = NA_IPV6 & & to - > type = = NA_IP )
2011-12-05 15:23:40 +00:00
{
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 ;
2013-05-03 04:28:08 +00:00
* ( int * ) & ( ( struct sockaddr_in6 * ) & addr ) - > sin6_addr . s6_addr [ 12 ] = * ( int * ) & to - > address . ip ;
( ( struct sockaddr_in6 * ) & addr ) - > sin6_port = to - > port ;
2011-12-05 15:23:40 +00:00
size = sizeof ( struct sockaddr_in6 ) ;
}
else
# endif
2008-11-09 22:29:28 +00:00
{
2013-05-03 04:28:08 +00:00
NetadrToSockadr ( to , & addr ) ;
2011-12-05 15:23:40 +00:00
2013-05-03 04:28:08 +00:00
switch ( to - > type )
2011-12-05 15:23:40 +00:00
{
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 ;
2013-05-03 04:28:08 +00:00
if ( ecode = = EACCES )
{
Con_Printf ( " Access denied: check firewall \n " ) ;
return true ;
}
2008-11-09 22:29:28 +00:00
# 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 ) ) )
{
2013-05-11 05:03:07 +00:00
// int ip = ((struct sockaddr_in*)&qs)->sin_addr.s_addr;
2011-12-05 15:23:40 +00:00
int port = ( ( struct sockaddr_in * ) & qs ) - > sin_port ;
2013-05-11 05:03:07 +00:00
// ip = ((struct sockaddr_in*)&qs)->sin_addr.s_addr;
2011-12-05 15:23:40 +00:00
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
2013-06-23 03:59:48 +00:00
# ifdef _WIN32
//win32 is so fucked up
2013-06-23 02:17:02 +00:00
setsockopt ( newsocket , SOL_SOCKET , SO_EXCLUSIVEADDRUSE , ( char * ) & _true , sizeof ( _true ) ) ;
2013-06-23 03:59:48 +00:00
# endif
2013-06-23 02:17:02 +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.
2013-05-03 04:28:08 +00:00
NET_AdrToString ( ( char * ) & qs , sizeof ( qs ) , & adr ) ;
2008-11-09 22:29:28 +00:00
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 {
2013-06-24 09:04:00 +00:00
SOCKET socketnum ;
2008-11-09 22:29:28 +00:00
int inlen ;
2012-04-09 19:12:12 +00:00
int outlen ;
enum
{
2013-04-06 03:36:00 +00:00
TCPC_UNKNOWN , //waiting to see what they send us.
TCPC_UNFRAMED , //something else is doing the framing (ie: we're running in emscripten and over some hidden websocket connection)
TCPC_HTTPCLIENT , //we're sending a file to this victim.
TCPC_QIZMO , //'qizmo\n' handshake, followed by packets prefixed with a 16bit packet length.
TCPC_WEBSOCKETU , //utf-8 encoded data.
TCPC_WEBSOCKETB , //binary encoded data (subprotocol = 'binary')
2012-04-09 19:12:12 +00:00
} clienttype ;
char inbuffer [ 3000 ] ;
char outbuffer [ 3000 ] ;
2013-04-06 03:36:00 +00:00
vfsfile_t * file ;
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 ;
}
2013-04-06 03:36:00 +00:00
# include "fs.h"
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 )
2013-04-06 03:36:00 +00:00
{
2013-05-03 04:28:08 +00:00
Con_Printf ( " tcp peer %s timed out \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2008-11-09 22:29:28 +00:00
goto closesvstream ;
2013-04-06 03:36:00 +00:00
}
2008-11-09 22:29:28 +00:00
ret = recv ( st - > socketnum , st - > inbuffer + st - > inlen , sizeof ( st - > inbuffer ) - st - > inlen , 0 ) ;
if ( ret = = 0 )
2013-04-06 03:36:00 +00:00
{
2013-05-03 04:28:08 +00:00
Con_Printf ( " tcp peer %s closed connection \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2008-11-09 22:29:28 +00:00
goto closesvstream ;
2013-04-06 03:36:00 +00:00
}
2008-11-09 22:29:28 +00:00
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.
2013-04-06 03:36:00 +00:00
if ( ! stricmp ( arg [ WCATTR_UPGRADE ] , " websocket " ) & & ( ! stricmp ( arg [ WCATTR_CONNECTION ] , " Upgrade " ) | | ! stricmp ( arg [ WCATTR_CONNECTION ] , " keep-alive, Upgrade " ) ) )
2012-04-09 19:12:12 +00:00
{
if ( atoi ( arg [ WCATTR_WSVER ] ) ! = 13 )
{
2013-05-11 05:03:07 +00:00
Con_Printf ( " Outdated websocket request for \" %s \" from \" %s \" . got version %i, expected version 13 \n " , arg [ WCATTR_URL ] , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) , atoi ( arg [ WCATTR_WSVER ] ) ) ;
2013-04-06 03:36:00 +00:00
2012-04-09 19:12:12 +00:00
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 ] ;
2013-06-23 02:17:02 +00:00
char * blurgh ;
2012-04-09 19:12:12 +00:00
memmove ( st - > inbuffer , st - > inbuffer + i , st - > inlen - ( i ) ) ;
st - > inlen - = i ;
2013-06-23 02:17:02 +00:00
blurgh = va ( " %s258EAFA5-E914-47DA-95CA-C5AB0DC85B11 " , arg [ WCATTR_WSKEY ] ) ;
tobase64 ( acceptkey , sizeof ( acceptkey ) , sha1digest , SHA1 ( sha1digest , sizeof ( sha1digest ) , blurgh , strlen ( blurgh ) ) ) ;
2012-04-09 19:12:12 +00:00
2013-05-03 04:28:08 +00:00
Con_Printf ( " Websocket request for %s from %s \n " , arg [ WCATTR_URL ] , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2013-04-06 03:36:00 +00:00
2013-05-09 03:01:29 +00:00
resp = va ( " HTTP/1.1 101 WebSocket Protocol Handshak \r \n "
2012-04-09 19:12:12 +00:00
" Upgrade: websocket \r \n "
" Connection: Upgrade \r \n "
2013-05-09 03:01:29 +00:00
" Access-Control-Allow-Origin: * \r \n " //allow cross-origin requests. this means you can use any domain to play on any public server.
2012-04-09 19:12:12 +00:00
" 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
2013-04-06 03:36:00 +00:00
if ( ! strcmp ( arg [ WCATTR_WSPROTO ] , " binary " ) )
st - > clienttype = TCPC_WEBSOCKETB ; //emscripten doesn't give us a choice, but its compact.
else
st - > clienttype = TCPC_WEBSOCKETU ; //nacl supports only utf-8 encoded data, at least at the time I implemented it.
2012-04-09 19:12:12 +00:00
}
}
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> "
) ;
}
2013-04-06 03:36:00 +00:00
/* else if ((!strcmp(arg[WCATTR_URL], "/ftewebgl.html") || !strcmp(arg[WCATTR_URL], "/ftewebgl.html.fmf") || !strcmp(arg[WCATTR_URL], "/pak0.pak")) && ((st->file = VFSOS_Open(va("C:/Incoming/vm%s", arg[WCATTR_URL]), "rb"))))
2013-03-12 23:09:25 +00:00
{
2013-04-06 03:36:00 +00:00
Con_Printf ( " Downloading %s to %s \n " , arg [ WCATTR_URL ] , NET_AdrToString ( adr , sizeof ( adr ) , st - > remoteaddr ) ) ;
2013-03-12 23:09:25 +00:00
resp = va ( " HTTP/1.1 200 Ok \r \n "
" Content-Type: text/html \r \n "
2013-04-06 03:36:00 +00:00
" Content-Length: %i \r \n "
" \r \n " ,
VFS_GETLEN ( st - > file )
2013-03-12 23:09:25 +00:00
) ;
2013-04-06 03:36:00 +00:00
send ( st - > socketnum , resp , strlen ( resp ) , 0 ) ;
st - > clienttype = TCPC_HTTPCLIENT ;
continue ;
}
*/
2013-03-12 23:09:25 +00:00
else
{
2013-05-03 04:28:08 +00:00
Con_Printf ( " Invalid download request %s to %s \n " , arg [ WCATTR_URL ] , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2013-03-12 23:09:25 +00:00
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 :
2013-05-03 04:28:08 +00:00
Con_Printf ( " Unknown TCP handshake from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2012-04-09 19:12:12 +00:00
goto closesvstream ;
}
break ;
2013-04-06 03:36:00 +00:00
case TCPC_HTTPCLIENT :
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 ;
st - > timeouttime = timeval + 30 ;
}
}
if ( ! st - > outlen )
{
st - > outlen = VFS_READ ( st - > file , st - > outbuffer , sizeof ( st - > outbuffer ) ) ;
if ( st - > outlen < = 0 )
{
VFS_CLOSE ( st - > file ) ;
st - > file = NULL ;
st - > clienttype = TCPC_UNKNOWN ;
Con_Printf ( " Outgoing file transfer complete \n " ) ;
}
}
continue ;
2012-04-09 19:12:12 +00:00
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
{
2013-05-03 04:28:08 +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
2013-04-04 08:08:49 +00:00
return true ;
case TCPC_UNFRAMED :
if ( ! st - > inlen )
continue ;
net_message . cursize = st - > inlen ;
memcpy ( net_message_buffer , st - > inbuffer , net_message . cursize ) ;
st - > inlen = 0 ;
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
net_from = st - > remoteaddr ;
2012-04-09 19:12:12 +00:00
return true ;
2013-04-06 03:36:00 +00:00
case TCPC_WEBSOCKETU :
case TCPC_WEBSOCKETB :
2012-04-09 19:12:12 +00:00
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)
{
2013-05-03 04:28:08 +00:00
Con_Printf ( " %s: payload frame too large \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2012-04-09 19:12:12 +00:00
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 )
{
2013-05-03 04:28:08 +00:00
Con_Printf ( " %s: payload size encoded badly \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2012-04-09 19:12:12 +00:00
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*/
2013-05-03 04:28:08 +00:00
Con_Printf ( " websocket continuation frame from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2012-04-09 19:12:12 +00:00
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*/
2013-04-06 03:36:00 +00:00
// Con_Printf ("websocket binary frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr));
2012-04-09 19:12:12 +00:00
net_message . cursize = paylen ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
{
2013-05-03 04:28:08 +00:00
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2012-04-09 19:12:12 +00:00
goto closesvstream ;
}
memcpy ( net_message_buffer , st - > inbuffer + payoffs , paylen ) ;
break ;
case 8 : /*connection close*/
2013-05-03 04:28:08 +00:00
Con_Printf ( " websocket closure %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2012-04-09 19:12:12 +00:00
goto closesvstream ;
case 9 : /*ping*/
2013-05-03 04:28:08 +00:00
Con_Printf ( " websocket ping from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2012-04-09 19:12:12 +00:00
goto closesvstream ;
case 10 : /*pong*/
2013-05-03 04:28:08 +00:00
Con_Printf ( " websocket pong from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2012-04-09 19:12:12 +00:00
goto closesvstream ;
default :
2013-05-03 04:28:08 +00:00
Con_Printf ( " Unsupported websocket opcode (%i) from %s \n " , ( ctrl > > 8 ) & 0xf , NET_AdrToString ( adr , sizeof ( adr ) , & st - > remoteaddr ) ) ;
2012-04-09 19:12:12 +00:00
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 ;
}
2013-05-03 04:28:08 +00:00
qboolean FTENET_TCPConnect_SendPacket ( ftenet_generic_connection_t * gcon , int length , void * data , netadr_t * to )
2008-11-09 22:29:28 +00:00
{
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 ;
2013-05-03 04:28:08 +00:00
if ( NET_CompareAdr ( to , & st - > remoteaddr ) )
2008-11-09 22:29:28 +00:00
{
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 ;
2013-04-04 08:08:49 +00:00
case TCPC_UNFRAMED :
if ( length > sizeof ( st - > outbuffer ) )
{
Con_DPrintf ( " FTENET_TCPConnect_SendPacket: outgoing overflow \n " ) ;
}
memcpy ( st - > outbuffer , data , length ) ;
st - > outlen = length ;
break ;
2013-04-06 03:36:00 +00:00
case TCPC_WEBSOCKETU :
case TCPC_WEBSOCKETB :
2012-04-09 19:12:12 +00:00
{
/*as a server, we don't need the mask stuff*/
2013-04-06 03:36:00 +00:00
unsigned short ctrl = ( st - > clienttype = = TCPC_WEBSOCKETB ) ? 0x8200 : 0x8100 ;
2012-04-09 19:12:12 +00:00
unsigned int paylen = 0 ;
unsigned int payoffs = 2 ;
int i ;
2013-04-06 03:36:00 +00:00
switch ( ( ctrl > > 8 ) & 0xf )
2012-04-09 19:12:12 +00:00
{
2013-04-06 03:36:00 +00:00
case 1 :
for ( i = 0 ; i < length ; i + + )
{
paylen + = ( ( ( char * ) data ) [ i ] = = 0 | | ( ( unsigned char * ) data ) [ i ] > = 0x80 ) ? 2 : 1 ;
}
break ;
default :
paylen = length ;
break ;
2012-04-09 19:12:12 +00:00
}
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 ;
}
2013-04-06 03:36:00 +00:00
switch ( ( ctrl > > 8 ) & 0xf )
2012-04-09 19:12:12 +00:00
{
2013-04-06 03:36:00 +00:00
case 1 : /*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 ] ;
}
2012-04-09 19:12:12 +00:00
}
2013-04-06 03:36:00 +00:00
break ;
default : //raw data
memcpy ( st - > outbuffer + payoffs , data , length ) ;
payoffs + = length ;
break ;
2012-04-09 19:12:12 +00:00
}
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 ) ;
}
2013-04-04 08:08:49 +00:00
# ifdef HAVE_PACKET
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 ;
}
2013-04-04 08:08:49 +00:00
# endif
2012-04-09 19:12:12 +00:00
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 ;
2013-04-04 08:08:49 +00:00
if ( ! strncmp ( address , " ws:// " , 5 ) )
address + = 5 ;
if ( ! strncmp ( address , " wss:// " , 6 ) )
address + = 6 ;
2008-11-09 22:29:28 +00:00
if ( isserver )
{
2013-04-04 08:08:49 +00:00
# ifndef HAVE_PACKET
//unable to listen on tcp if we have no packet interface
return NULL ;
# else
2008-11-09 22:29:28 +00:00
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.
2013-05-03 04:28:08 +00:00
NET_AdrToString ( ( char * ) & qs , sizeof ( qs ) , & adr ) ;
2008-11-09 22:29:28 +00:00
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 ) ) ;
2013-04-04 08:08:49 +00:00
# endif
2008-11-09 22:29:28 +00:00
}
else
{
2013-04-04 08:08:49 +00:00
if ( ! NET_StringToAdr ( address , 0 , & 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 ;
2013-05-03 04:28:08 +00:00
newsocket = TCP_OpenStream ( & adr ) ;
2009-07-05 18:45:53 +00:00
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 ;
2013-04-04 08:08:49 +00:00
# ifdef HAVE_PACKET
2012-04-09 19:12:12 +00:00
newcon - > generic . SetReceiveFDSet = FTENET_TCPConnect_SetReceiveFDSet ;
2013-04-04 08:08:49 +00:00
# endif
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 ) ) ;
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
2013-04-04 08:08:49 +00:00
# ifdef FTE_TARGET_WEB
newcon - > tcpstreams - > clienttype = TCPC_UNFRAMED ;
# else
2008-11-09 22:29:28 +00:00
//send the qizmo greeting.
2013-04-04 08:08:49 +00:00
newcon - > tcpstreams - > clienttype = TCPC_UNKNOWN ;
2008-11-09 22:29:28 +00:00
send ( newsocket , " qizmo \n " , 6 , 0 ) ;
2013-04-04 08:08:49 +00:00
# endif
2008-11-09 22:29:28 +00:00
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 )
{
2013-05-03 04:28:08 +00:00
netadr_t ip ;
2008-11-09 22:29:28 +00:00
cvar_t * ircuser = Cvar_Get ( " ircuser " , " none " , 0 , " IRC Connect " ) ;
2013-05-03 04:28:08 +00:00
cvar_t * ircnick = Cvar_Get ( " ircnick " , " " , 0 , " IRC Connect " ) ;
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 " ) ;
2013-05-03 04:28:08 +00:00
NET_StringToAdr ( con - > ircserver . address . irc . host , 6667 , & ip ) ;
con - > generic . thesocket = TCP_OpenStream ( & ip ) ;
2008-11-09 22:29:28 +00:00
2013-05-03 04:28:08 +00:00
//when hosting, the specified nick is the name we're using.
//when connecting, the specified nick is the name we're trying to send to, and our own name is inconsequential.
if ( con - > generic . islisten & & * con - > ircserver . address . irc . user )
Q_strncpyz ( con - > ourusername , con - > ircserver . address . irc . user , sizeof ( con - > ourusername ) ) ;
else
Q_strncpyz ( con - > ourusername , ircnick - > string , sizeof ( con - > ourusername ) ) ;
if ( ! * con - > ourusername )
{
Q_snprintfz ( con - > ourusername , sizeof ( con - > ourusername ) , " fte%x \n " , rand ( ) ) ;
}
2008-11-09 22:29:28 +00:00
send ( con - > generic . thesocket , " USER " , 5 , 0 ) ;
send ( con - > generic . thesocket , ircuser - > string , strlen ( ircuser - > string ) , 0 ) ;
send ( con - > generic . thesocket , " " , 1 , 0 ) ;
2013-05-03 04:28:08 +00:00
send ( con - > generic . thesocket , con - > ircserver . address . irc . host , strlen ( con - > ircserver . address . irc . host ) , 0 ) ;
2008-11-09 22:29:28 +00:00
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 ) )
{
2013-05-03 04:28:08 +00:00
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2008-11-09 22:29:28 +00:00
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 ;
2013-05-03 04:28:08 +00:00
Con_Printf ( " Corrupt packet from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2008-11-09 22:29:28 +00:00
}
else if ( st - > inlen = = psize )
{
/*interpret as a connectionless packet*/
net_message . cursize = st - > inlen ;
if ( net_message . cursize > = sizeof ( net_message_buffer ) )
{
2013-05-03 04:28:08 +00:00
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2008-11-09 22:29:28 +00:00
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 :
{
2013-05-03 04:28:08 +00:00
if ( con - > ircserver . address . irc . channel )
2008-11-09 22:29:28 +00:00
{
send ( con - > generic . thesocket , " JOIN " , 5 , 0 ) ;
2013-05-03 04:28:08 +00:00
send ( con - > generic . thesocket , con - > ircserver . address . irc . channel , strlen ( con - > ircserver . address . irc . channel ) , 0 ) ;
2008-11-09 22:29:28 +00:00
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 ;
}
2013-05-03 04:28:08 +00:00
qboolean FTENET_IRCConnect_SendPacket ( ftenet_generic_connection_t * gcon , int length , void * data , netadr_t * to )
2008-11-09 22:29:28 +00:00
{
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 + + )
2013-05-03 04:28:08 +00:00
if ( to - > type = = con - > generic . addrtype [ packed ] )
2008-11-09 22:29:28 +00:00
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 ;
2013-05-03 04:28:08 +00:00
if ( * to - > address . irc . channel )
2008-11-09 22:29:28 +00:00
{
int unamelen ;
int chanlen ;
2013-05-03 04:28:08 +00:00
unamelen = strlen ( to - > address . irc . user ) ;
chanlen = strlen ( to - > address . irc . channel ) ;
2008-11-09 22:29:28 +00:00
packed = 8 + chanlen + 3 + unamelen + 1 + 3 ;
if ( packed + 1 + newoutcount > sizeof ( con - > outbuf ) )
break ;
memcpy ( buffer , " PRIVMSG " , 8 ) ;
2013-05-03 04:28:08 +00:00
memcpy ( buffer + 8 , to - > address . irc . channel , chanlen ) ;
2008-11-09 22:29:28 +00:00
memcpy ( buffer + 8 + chanlen , " :$ " , 3 ) ;
2013-05-03 04:28:08 +00:00
memcpy ( buffer + 8 + chanlen + 3 , to - > address . irc . user , unamelen ) ;
2008-11-09 22:29:28 +00:00
memcpy ( buffer + 8 + chanlen + 3 + unamelen , " # " , 1 ) ;
lenofs = buffer + 8 + chanlen + 3 + unamelen + 1 ;
sprintf ( lenofs , " %03x " , fulllen ) ;
}
else
{
int unamelen ;
2013-05-03 04:28:08 +00:00
unamelen = strlen ( to - > address . irc . user ) ;
2008-11-09 22:29:28 +00:00
packed = 8 + unamelen + 3 + 3 ;
if ( packed + 1 + newoutcount > sizeof ( con - > outbuf ) )
break ;
memcpy ( buffer , " PRIVMSG " , 8 ) ;
2013-05-03 04:28:08 +00:00
memcpy ( buffer + 8 , to - > address . irc . user , unamelen ) ;
2008-11-09 22:29:28 +00:00
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
2013-07-31 00:20:16 +00:00
# ifdef FTE_TARGET_WEB
int emscriptenfte_ws_connect ( char * url ) ;
int emscriptenfte_ws_close ( int sock ) ;
int emscriptenfte_ws_cansend ( int sock , int extra , int maxpending ) ;
int emscriptenfte_ws_send ( int sock , void * data , int len ) ;
int emscriptenfte_ws_recv ( int sock , void * data , int len ) ;
typedef struct
{
ftenet_generic_connection_t generic ;
int sock ;
netadr_t remoteadr ;
qboolean failed ;
} ftenet_websocket_connection_t ;
static void FTENET_WebSocket_Close ( ftenet_generic_connection_t * gcon )
{
ftenet_websocket_connection_t * wsc = ( void * ) gcon ;
emscriptenfte_ws_close ( wsc - > sock ) ;
}
static qboolean FTENET_WebSocket_GetPacket ( ftenet_generic_connection_t * gcon )
{
ftenet_websocket_connection_t * wsc = ( void * ) gcon ;
net_message . cursize = emscriptenfte_ws_recv ( wsc - > sock , net_message_buffer , sizeof ( net_message_buffer ) ) ;
if ( net_message . cursize > 0 )
{
net_from = wsc - > remoteadr ;
return true ;
}
net_message . cursize = 0 ; //just incase
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 ;
if ( NET_CompareAdr ( to , & wsc - > remoteadr ) )
{
emscriptenfte_ws_send ( wsc - > sock , data , length ) ;
return true ;
}
return false ;
}
static ftenet_generic_connection_t * FTENET_WebSocket_EstablishConnection ( qboolean isserver , const char * address )
{
ftenet_websocket_connection_t * newcon ;
netadr_t adr ;
int newsocket ;
if ( isserver )
{
return NULL ;
}
if ( ! NET_StringToAdr ( address , 80 , & adr ) )
return NULL ; //couldn't resolve the name
newsocket = emscriptenfte_ws_connect ( address ) ;
if ( newsocket < 0 )
return NULL ;
newcon = Z_Malloc ( sizeof ( * newcon ) ) ;
if ( newcon )
{
Q_strncpyz ( newcon - > generic . name , " WebSocket " , sizeof ( newcon - > generic . name ) ) ;
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
# ifdef NACL
2012-04-09 19:12:12 +00:00
# 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 ;
struct PP_Var incomingpacket ;
2013-07-31 00:20:16 +00:00
qboolean havepacket ;
2012-04-09 19:12:12 +00:00
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);
}
2013-07-31 00:20:16 +00:00
static void FTENET_NaClWebSocket_Close ( ftenet_generic_connection_t * gcon )
2012-04-09 19:12:12 +00:00
{
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 ) ;
}
2013-07-31 00:20:16 +00:00
static qboolean FTENET_NaClWebSocket_GetPacket ( ftenet_generic_connection_t * gcon )
2012-04-09 19:12:12 +00:00
{
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 ] ;
2013-05-07 22:23:28 +00:00
Con_TPrintf ( TL_OVERSIZEPACKETFROM , NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2012-04-09 19:12:12 +00:00
return false ;
}
return true ;
}
return false ;
}
2013-07-31 00:20:16 +00:00
static qboolean FTENET_NaClWebSocket_SendPacket ( ftenet_generic_connection_t * gcon , int length , void * data , netadr_t * to )
2012-04-09 19:12:12 +00:00
{
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 ) ) ;
2013-07-31 00:20:16 +00:00
newcon - > generic . GetPacket = FTENET_NaClWebSocket_GetPacket ;
newcon - > generic . SendPacket = FTENET_NaClWebSocket_SendPacket ;
newcon - > generic . Close = FTENET_NaClWebSocket_Close ;
2012-04-09 19:12:12 +00:00
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 ) ;
}
2013-05-03 04:28:08 +00:00
void NET_SendPacket ( netsrc_t netsrc , int length , void * data , netadr_t * to )
2008-11-09 22:29:28 +00:00
{
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 ;
}
2013-05-03 04:28:08 +00:00
if ( to - > connum )
2008-11-09 22:29:28 +00:00
{
2013-05-03 04:28:08 +00:00
if ( collection - > conn [ to - > connum - 1 ] )
if ( collection - > conn [ to - > connum - 1 ] - > SendPacket ( collection - > conn [ to - > connum - 1 ] , length , data , to ) )
2008-11-09 22:29:28 +00:00
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-05-03 04:28: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
}
}
//=============================================================================
2013-05-03 04:28:08 +00:00
int TCP_OpenStream ( netadr_t * remoteaddr )
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
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
2013-05-03 04:28:08 +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 )
2013-06-24 09:04:00 +00:00
return ( int ) INVALID_SOCKET ;
2005-11-30 01:20:53 +00:00
2013-03-31 04:21:08 +00:00
setsockopt ( newsocket , SOL_SOCKET , SO_RCVBUF , ( void * ) & recvbufsize , sizeof ( recvbufsize ) ) ;
2013-06-23 02:17:02 +00:00
if ( ioctlsocket ( newsocket , FIONBIO , & _true ) = = - 1 )
Sys_Error ( " UDP_OpenSocket: ioctl FIONBIO: %s " , strerror ( qerrno ) ) ;
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 ;
2013-06-24 09:04:00 +00:00
if ( err ! = EWOULDBLOCK & & err ! = EINPROGRESS )
2013-03-12 22:44:00 +00:00
{
2013-06-24 09:04:00 +00:00
char buf [ 256 ] ;
NET_AdrToString ( buf , sizeof ( buf ) , remoteaddr ) ;
2013-06-23 02:17:02 +00:00
if ( err = = EADDRNOTAVAIL )
{
if ( remoteaddr - > port = = 0 & & ( remoteaddr - > type = = NA_IP | | remoteaddr - > type = = NA_IPV6 ) )
2013-06-24 09:04:00 +00:00
Con_Printf ( " TCP_OpenStream: no port specified (%s) \n " , buf ) ;
2013-06-23 02:17:02 +00:00
else
Con_Printf ( " TCP_OpenStream: invalid address trying to connect to %s \n " , buf ) ;
}
else if ( err = = EACCES )
2013-06-24 09:04:00 +00:00
Con_Printf ( " TCP_OpenStream: access denied: check firewall (%s) \n " , buf ) ;
2013-03-12 22:44:00 +00:00
else
2013-06-24 09:04:00 +00:00
Con_Printf ( " TCP_OpenStream: connect: error %i (%s) \n " , err , buf ) ;
2013-06-23 02:17:02 +00:00
closesocket ( newsocket ) ;
2013-06-24 09:04:00 +00:00
return ( int ) INVALID_SOCKET ;
2013-03-12 22:44:00 +00:00
}
2005-11-30 01:20:53 +00:00
}
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 )
2013-06-24 09:04:00 +00:00
return ( int ) 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 " ) ;
2013-06-24 09:04:00 +00:00
return ( int ) 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 ) ) ;
2013-06-24 09:04:00 +00:00
return ( int ) 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 ) ;
2013-06-24 09:04:00 +00:00
return ( int ) 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 ) ;
2013-06-24 09:04:00 +00:00
return ( int ) INVALID_SOCKET ;
2006-06-27 16:00:41 +00:00
}
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 ) ;
2013-06-24 09:04:00 +00:00
return ( int ) INVALID_SOCKET ;
2006-06-27 16:00:41 +00:00
}
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 ;
2013-07-13 12:14:32 +00:00
if ( ! maxfd )
Sys_Sleep ( msec / 1000.0 ) ;
else
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
2013-05-03 04:28:08 +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
}
2013-06-29 16:01:07 +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 ;
2013-06-23 02:17:02 +00:00
# ifdef SUPPORT_ICE
2013-06-29 16:01:07 +00:00
/*
Interactive Connectivity Establishment ( rfc 5245 )
find out your peer ' s potential ports .
spam your peer with stun packets .
see what sticks .
the ' controller ' assigns some final candidate pair to ensure that both peers send + receive from a single connection .
if no candidates are available , try using stun to find public nat addresses .
in fte , a ' pair ' is actually in terms of each local socket and remote address . hopefully that won ' t cause too much weirdness .
stun test packets must contain all sorts of info . username + integrity + fingerprint for validation . priority + usecandidate + icecontrol ( ing ) to decree the priority of any new remote candidates , whether its finished , and just who decides whether its finished .
peers don ' t like it when those are missing .
host candidates - addresses that are directly known
server reflexive candidates - addresses that we found from some public stun server
peer reflexive candidates - addresses that our peer finds out about as we spam them
relayed candidates - some sort of socks5 or something proxy .
*/
struct icecandidate_s
{
struct icecandinfo_s info ;
struct icecandidate_s * next ;
netadr_t peer ;
//peer needs telling or something.
qboolean dirty ;
//these are bitmasks. one bit for each local socket.
unsigned int reachable ;
unsigned int tried ;
} ;
struct icestate_s
{
struct icestate_s * next ;
void * module ;
netadr_t chosenpeer ;
netadr_t pubstunserver ;
unsigned int stunretry ; //once a second, extended to once a minite on reply
char * stunserver ; //where to get our public ip from.
int stunport ;
unsigned int stunrnd [ 3 ] ;
unsigned int timeout ; //time when we consider the connection dead
unsigned int keepalive ; //sent periodically...
unsigned int retries ; //bumped after each round of connectivity checks. affects future intervals.
enum iceproto_e proto ;
enum icemode_e mode ;
qboolean controlled ; //controller chooses final ports.
enum icestate_e state ;
char * conname ; //internal id.
char * friendlyname ; //who you're talking to.
struct icecandidate_s * lc ;
char * lpwd ;
char * lufrag ;
struct icecandidate_s * rc ;
char * rpwd ;
char * rufrag ;
unsigned int tiehigh ;
unsigned int tielow ;
char * codec [ 32 ] ; //96-127. don't really need to care about other ones.
} ;
2013-06-23 02:17:02 +00:00
static struct icestate_s * icelist ;
2013-06-29 16:01:07 +00:00
# if !defined(SERVERONLY) && defined(VOICECHAT)
extern cvar_t cl_voip_send ;
struct rtpheader_s
{
unsigned char v2_p1_x1_cc4 ;
unsigned char m1_pt7 ;
unsigned short seq ;
unsigned int timestamp ;
unsigned int ssrc ;
unsigned int csrc [ 1 ] ; //sized according to cc
} ;
void S_Voip_RTP_Parse ( unsigned short sequence , char * codec , unsigned char * data , unsigned int datalen ) ;
qboolean NET_RTP_Parse ( void )
{
struct rtpheader_s * rtpheader = ( void * ) net_message . data ;
if ( net_message . cursize > = sizeof ( * rtpheader ) & & ( rtpheader - > v2_p1_x1_cc4 & 0xc0 ) = = 0x80 )
{
int hlen ;
int padding = 0 ;
struct icestate_s * con ;
int proto ;
//make sure this really came from an accepted rtp stream
//note that an rtp connection equal to the game connection will likely mess up when sequences start to get big
//(especially problematic in sane clients that start with a random sequence)
for ( con = icelist ; con ; con = con - > next )
{
if ( con - > state ! = ICE_INACTIVE & & con - > proto = = ICEP_VOICE & & NET_CompareAdr ( & net_from , & con - > chosenpeer ) )
break ;
}
//and continue with parsing it if its okay.
if ( con )
{
proto = rtpheader - > m1_pt7 & 0x7f ;
if ( proto < 96 | | proto > 127 )
return false ;
proto - = 96 ;
if ( rtpheader - > v2_p1_x1_cc4 & 0x20 )
padding = net_message . data [ net_message . cursize - 1 ] ;
hlen = sizeof ( * rtpheader ) ;
hlen + = ( ( rtpheader - > v2_p1_x1_cc4 & 0xf ) - 1 ) * sizeof ( int ) ;
S_Voip_RTP_Parse ( ( unsigned short ) BigShort ( rtpheader - > seq ) , con - > codec [ proto ] , hlen + ( char * ) ( rtpheader ) , net_message . cursize - padding - hlen ) ;
return true ;
}
}
return false ;
}
qboolean NET_RTP_Active ( void )
{
struct icestate_s * con ;
for ( con = icelist ; con ; con = con - > next )
{
if ( con - > state = = ICE_CONNECTED & & con - > proto = = ICEP_VOICE )
return true ;
}
return false ;
}
qboolean NET_RTP_Transmit ( unsigned int sequence , unsigned int timestamp , char * codec , char * cdata , int clength )
{
sizebuf_t buf ;
char pdata [ 512 ] ;
int i ;
struct icestate_s * con ;
qboolean built = false ;
memset ( & buf , 0 , sizeof ( buf ) ) ;
buf . maxsize = sizeof ( pdata ) ;
buf . cursize = 0 ;
buf . allowoverflow = true ;
buf . data = pdata ;
for ( con = icelist ; con ; con = con - > next )
{
if ( con - > state = = ICE_CONNECTED & & con - > proto = = ICEP_VOICE )
{
for ( i = 0 ; i < sizeof ( con - > codec ) / sizeof ( con - > codec [ 0 ] ) ; i + + )
{
if ( con - > codec [ i ] & & ! strcmp ( con - > codec [ i ] , codec ) )
{
if ( ! built )
{
built = true ;
MSG_WriteByte ( & buf , ( 2u < < 6 ) | ( 0u < < 5 ) | ( 0u < < 4 ) | ( 0 < < 0 ) ) ; //v2_p1_x1_cc4
MSG_WriteByte ( & buf , ( 0u < < 7 ) | ( ( i + 96 ) < < 0 ) ) ; //m1_pt7
MSG_WriteShort ( & buf , BigShort ( sequence ) ) ; //seq
MSG_WriteLong ( & buf , BigLong ( timestamp ) ) ; //timestamp
MSG_WriteLong ( & buf , BigLong ( 0 ) ) ; //ssrc
SZ_Write ( & buf , cdata , clength ) ;
if ( buf . overflowed )
return built ;
}
NET_SendPacket ( NS_CLIENT , buf . cursize , buf . data , & con - > chosenpeer ) ;
break ;
}
}
}
}
return built ;
}
# endif
2013-06-23 02:17:02 +00:00
struct icestate_s * QDECL ICE_Find ( void * module , char * conname )
{
struct icestate_s * con ;
for ( con = icelist ; con ; con = con - > next )
{
if ( con - > module = = module & & ! strcmp ( con - > conname , conname ) )
return con ;
}
return NULL ;
}
2013-06-29 16:01:07 +00:00
struct icestate_s * QDECL ICE_Create ( void * module , char * conname , char * peername , enum icemode_e mode , enum iceproto_e proto )
2013-06-23 02:17:02 +00:00
{
ftenet_connections_t * collection ;
struct icestate_s * con ;
2013-06-29 16:01:07 +00:00
//only allow modes that we actually support.
if ( mode ! = ICEM_RAW & & mode ! = ICEM_ICE )
return NULL ;
2013-06-23 02:17:02 +00:00
2013-06-29 16:01:07 +00:00
//only allow protocols that we actually support.
switch ( proto )
2013-06-23 02:17:02 +00:00
{
2013-06-29 16:01:07 +00:00
default :
2013-06-23 02:17:02 +00:00
return NULL ;
2013-06-29 16:01:07 +00:00
# if !defined(SERVERONLY) && defined(VOICECHAT)
case ICEP_VOICE :
collection = cls . sockets ;
break ;
# endif
# ifndef SERVERONLY
case ICEP_QWCLIENT :
collection = cls . sockets ;
break ;
# endif
# ifndef CLIENTONLY
case ICEP_QWSERVER :
collection = svs . sockets ;
break ;
2013-06-23 02:17:02 +00:00
# endif
}
2013-06-29 16:01:07 +00:00
if ( ! conname )
2013-06-23 02:17:02 +00:00
{
2013-06-29 16:01:07 +00:00
int rnd [ 2 ] ;
Sys_RandomBytes ( ( void * ) rnd , sizeof ( rnd ) ) ;
conname = va ( " fte%08x%08x " , rnd [ 0 ] , rnd [ 1 ] ) ;
2013-06-23 02:17:02 +00:00
}
con = Z_Malloc ( sizeof ( * con ) ) ;
con - > conname = Z_StrDup ( conname ) ;
con - > friendlyname = Z_StrDup ( peername ) ;
2013-06-29 16:01:07 +00:00
con - > proto = proto ;
con - > rpwd = Z_StrDup ( " " ) ;
con - > rufrag = Z_StrDup ( " " ) ;
2013-06-23 02:17:02 +00:00
con - > mode = mode ;
con - > next = icelist ;
icelist = con ;
{
int rnd [ 1 ] ; //'must have at least 24 bits randomness'
Sys_RandomBytes ( ( void * ) rnd , sizeof ( rnd ) ) ;
2013-06-29 16:01:07 +00:00
con - > lufrag = Z_StrDup ( va ( " %08x " , rnd [ 0 ] ) ) ;
2013-06-23 02:17:02 +00:00
}
{
int rnd [ 4 ] ; //'must have at least 128 bits randomness'
Sys_RandomBytes ( ( void * ) rnd , sizeof ( rnd ) ) ;
con - > lpwd = Z_StrDup ( va ( " %08x%08x%08x%08x " , rnd [ 0 ] , rnd [ 1 ] , rnd [ 2 ] , rnd [ 3 ] ) ) ;
}
2013-06-29 16:01:07 +00:00
Sys_RandomBytes ( ( void * ) & con - > tiehigh , sizeof ( con - > tiehigh ) ) ;
Sys_RandomBytes ( ( void * ) & con - > tielow , sizeof ( con - > tielow ) ) ;
2013-06-23 02:17:02 +00:00
if ( collection )
{
int i ;
int adrno , adrcount = 1 ;
netadr_t adr ;
char adrbuf [ MAX_ADR_SIZE ] ;
int net = 0 ;
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( ! collection - > conn [ i ] )
continue ;
adrno = 0 ;
if ( collection - > conn [ i ] - > GetLocalAddress )
{
for ( adrcount = 1 ; ( adrcount = collection - > conn [ i ] - > GetLocalAddress ( collection - > conn [ i ] , & adr , adrno ) ) & & adrno < adrcount ; adrno + + )
{
struct icecandidate_s * cand ;
int rnd [ 2 ] ;
if ( adr . type = = NA_IP | | adr . type = = NA_IPV6 )
{
cand = Z_Malloc ( sizeof ( * cand ) ) ;
2013-06-29 16:01:07 +00:00
cand - > info . network = net ;
cand - > info . port = ntohs ( adr . port ) ;
2013-06-23 02:17:02 +00:00
adr . port = 0 ; //to make sure its not part of the string...
2013-06-29 16:01:07 +00:00
Q_strncpyz ( cand - > info . addr , NET_AdrToString ( adrbuf , sizeof ( adrbuf ) , & adr ) , sizeof ( cand - > info . addr ) ) ;
cand - > info . generation = 0 ;
cand - > info . component = 1 ;
cand - > info . foundation = 1 ;
cand - > info . priority =
2013-06-23 02:17:02 +00:00
( 1 < < 24 ) * ( 126 ) +
2013-06-29 16:01:07 +00:00
( 1 < < 8 ) * ( ( adr . type = = NA_IP ? 32768 : 0 ) + net * 256 + ( 255 - adrno ) ) +
( 1 < < 0 ) * ( 256 - cand - > info . component ) ;
2013-06-23 02:17:02 +00:00
Sys_RandomBytes ( ( void * ) rnd , sizeof ( rnd ) ) ;
2013-06-29 16:01:07 +00:00
Q_strncpyz ( cand - > info . candidateid , va ( " x%08x%08x " , rnd [ 0 ] , rnd [ 1 ] ) , sizeof ( cand - > info . candidateid ) ) ;
2013-06-23 02:17:02 +00:00
cand - > dirty = true ;
cand - > next = con - > lc ;
con - > lc = cand ;
}
}
}
net + + ;
}
}
return con ;
}
2013-06-29 16:01:07 +00:00
# include "zlib.h"
ftenet_connections_t * ICE_PickConnection ( struct icestate_s * con )
2013-06-23 02:17:02 +00:00
{
2013-06-29 16:01:07 +00:00
switch ( con - > proto )
2013-06-23 02:17:02 +00:00
{
2013-06-29 16:01:07 +00:00
default :
break ;
# ifndef SERVERONLY
case ICEP_VOICE :
case ICEP_QWCLIENT :
return cls . sockets ;
# endif
# ifndef CLIENTONLY
case ICEP_QWSERVER :
return svs . sockets ;
# endif
}
return NULL ;
}
//if either remotecand is null, new packets will be sent to all.
static qboolean ICE_SendSpam ( struct icestate_s * con )
{
struct icecandidate_s * rc ;
int i ;
int bestlocal = - 1 ;
struct icecandidate_s * bestpeer = NULL ;
ftenet_connections_t * collection = ICE_PickConnection ( con ) ;
if ( ! collection )
return false ;
//only send one ping to each.
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( collection - > conn [ i ] )
2013-06-23 02:17:02 +00:00
{
2013-06-29 16:01:07 +00:00
for ( rc = con - > rc ; rc ; rc = rc - > next )
{
if ( ! ( rc - > tried & ( 1u < < i ) ) & & ! ( rc - > tried & ( 1u < < i ) ) )
{
//fixme: no local priority. a multihomed machine will try the same ip from different ports.
if ( ! bestpeer | | bestpeer - > info . priority < rc - > info . priority )
{
bestpeer = rc ;
bestlocal = i ;
}
}
}
2013-06-23 02:17:02 +00:00
}
}
2013-06-29 16:01:07 +00:00
if ( bestpeer & & bestlocal > = 0 )
{
netadr_t to ;
sizebuf_t buf ;
char data [ 512 ] ;
char integ [ 20 ] ;
int crc ;
qboolean usecandidate = false ;
memset ( & buf , 0 , sizeof ( buf ) ) ;
buf . maxsize = sizeof ( data ) ;
buf . cursize = 0 ;
buf . data = data ;
bestpeer - > tried | = ( 1u < < bestlocal ) ;
if ( ! NET_StringToAdr ( bestpeer - > info . addr , bestpeer - > info . port , & to ) )
return true ;
Con_DPrintf ( " Spam %i -> %s:%i \n " , bestlocal , bestpeer - > info . addr , bestpeer - > info . port ) ;
if ( ! con - > controlled & & NET_CompareAdr ( & to , & con - > chosenpeer ) )
usecandidate = true ;
MSG_WriteShort ( & buf , BigShort ( 0x0001 ) ) ;
MSG_WriteShort ( & buf , 0 ) ; //fill in later
MSG_WriteLong ( & buf , BigLong ( 0x2112a442 ) ) ;
MSG_WriteLong ( & buf , BigLong ( 0 ) ) ; //randomid
MSG_WriteLong ( & buf , BigLong ( 0 ) ) ; //randomid
MSG_WriteLong ( & buf , BigLong ( 0x80000000 | bestlocal ) ) ; //randomid
if ( usecandidate )
{
MSG_WriteShort ( & buf , BigShort ( 0x25 ) ) ; //ICE-USE-CANDIDATE
MSG_WriteShort ( & buf , BigShort ( 0 ) ) ;
}
//username
MSG_WriteShort ( & buf , BigShort ( 0x6 ) ) ; //USERNAME
MSG_WriteShort ( & buf , BigShort ( strlen ( con - > rufrag ) + 1 + strlen ( con - > lufrag ) ) ) ;
SZ_Write ( & buf , con - > rufrag , strlen ( con - > rufrag ) ) ;
MSG_WriteChar ( & buf , ' : ' ) ;
SZ_Write ( & buf , con - > lufrag , strlen ( con - > lufrag ) ) ;
while ( buf . cursize & 3 )
MSG_WriteChar ( & buf , 0 ) ;
//priority
MSG_WriteShort ( & buf , BigShort ( 0x24 ) ) ; //ICE-PRIORITY
MSG_WriteShort ( & buf , BigShort ( 4 ) ) ;
MSG_WriteLong ( & buf , 0 ) ; //FIXME
//these two attributes carry a random 64bit tie-breaker.
//the controller is the one with the highest number.
if ( con - > controlled )
{
MSG_WriteShort ( & buf , BigShort ( 0x8029 ) ) ; //ICE-CONTROLLED
MSG_WriteShort ( & buf , BigShort ( 8 ) ) ;
MSG_WriteLong ( & buf , BigLong ( con - > tiehigh ) ) ;
MSG_WriteLong ( & buf , BigLong ( con - > tielow ) ) ;
}
else
{
MSG_WriteShort ( & buf , BigShort ( 0x802A ) ) ; //ICE-CONTROLLING
MSG_WriteShort ( & buf , BigShort ( 8 ) ) ;
MSG_WriteLong ( & buf , BigLong ( con - > tiehigh ) ) ;
MSG_WriteLong ( & buf , BigLong ( con - > tielow ) ) ;
}
//message integrity is a bit annoying
data [ 2 ] = ( ( buf . cursize + 4 + sizeof ( integ ) - 20 ) > > 8 ) & 0xff ; //hashed header length is up to the end of the hmac attribute
data [ 3 ] = ( ( buf . cursize + 4 + sizeof ( integ ) - 20 ) > > 0 ) & 0xff ;
//but the hash is to the start of the attribute's header
2013-07-13 12:14:32 +00:00
SHA1_HMAC ( integ , sizeof ( integ ) , data , buf . cursize , con - > rpwd , strlen ( con - > rpwd ) ) ;
2013-06-29 16:01:07 +00:00
MSG_WriteShort ( & buf , BigShort ( 0x8 ) ) ; //MESSAGE-INTEGRITY
MSG_WriteShort ( & buf , BigShort ( 20 ) ) ; //sha1 key length
SZ_Write ( & buf , integ , sizeof ( integ ) ) ; //integrity data
data [ 2 ] = ( ( buf . cursize + 8 - 20 ) > > 8 ) & 0xff ; //dummy length
data [ 3 ] = ( ( buf . cursize + 8 - 20 ) > > 0 ) & 0xff ;
crc = crc32 ( 0 , data , buf . cursize ) ^ 0x5354554e ;
MSG_WriteShort ( & buf , BigShort ( 0x8028 ) ) ; //FINGERPRINT
MSG_WriteShort ( & buf , BigShort ( sizeof ( crc ) ) ) ;
MSG_WriteLong ( & buf , BigLong ( crc ) ) ;
//fill in the length (for the fourth time, after filling in the integrity and fingerprint)
data [ 2 ] = ( ( buf . cursize - 20 ) > > 8 ) & 0xff ;
data [ 3 ] = ( ( buf . cursize - 20 ) > > 0 ) & 0xff ;
collection - > conn [ bestlocal ] - > SendPacket ( collection - > conn [ bestlocal ] , buf . cursize , data , & to ) ;
return true ;
}
return false ;
2013-06-23 02:17:02 +00:00
}
2013-06-29 16:01:07 +00:00
void ICE_ToStunServer ( struct icestate_s * con )
{
sizebuf_t buf ;
char data [ 512 ] ;
int crc ;
ftenet_connections_t * collection = ICE_PickConnection ( con ) ;
if ( ! collection )
return ;
if ( ! con - > stunrnd [ 0 ] )
Sys_RandomBytes ( ( char * ) con - > stunrnd , sizeof ( con - > stunrnd ) ) ;
Con_DPrintf ( " Spam stun %s \n " , NET_AdrToString ( data , sizeof ( data ) , & con - > pubstunserver ) ) ;
memset ( & buf , 0 , sizeof ( buf ) ) ;
buf . maxsize = sizeof ( data ) ;
buf . cursize = 0 ;
buf . data = data ;
MSG_WriteShort ( & buf , BigShort ( 0x0001 ) ) ;
MSG_WriteShort ( & buf , 0 ) ; //fill in later
MSG_WriteLong ( & buf , BigLong ( 0x2112a442 ) ) ;
MSG_WriteLong ( & buf , BigLong ( con - > stunrnd [ 0 ] ) ) ; //randomid
MSG_WriteLong ( & buf , BigLong ( con - > stunrnd [ 1 ] ) ) ; //randomid
MSG_WriteLong ( & buf , BigLong ( con - > stunrnd [ 2 ] ) ) ; //randomid
data [ 2 ] = ( ( buf . cursize + 8 - 20 ) > > 8 ) & 0xff ; //dummy length
data [ 3 ] = ( ( buf . cursize + 8 - 20 ) > > 0 ) & 0xff ;
crc = crc32 ( 0 , data , buf . cursize ) ^ 0x5354554e ;
MSG_WriteShort ( & buf , BigShort ( 0x8028 ) ) ; //FINGERPRINT
MSG_WriteShort ( & buf , BigShort ( sizeof ( crc ) ) ) ;
MSG_WriteLong ( & buf , BigLong ( crc ) ) ;
//fill in the length (for the fourth time, after filling in the integrity and fingerprint)
data [ 2 ] = ( ( buf . cursize - 20 ) > > 8 ) & 0xff ;
data [ 3 ] = ( ( buf . cursize - 20 ) > > 0 ) & 0xff ;
NET_SendPacket ( ( con - > proto = = ICEP_QWSERVER ) ? NS_SERVER : NS_CLIENT , buf . cursize , data , & con - > pubstunserver ) ;
}
qboolean QDECL ICE_Set ( struct icestate_s * con , char * prop , char * value )
{
if ( ! strcmp ( prop , " state " ) )
{
int oldstate = con - > state ;
if ( ! strcmp ( value , STRINGIFY ( ICE_CONNECTING ) ) )
con - > state = ICE_CONNECTING ;
else if ( ! strcmp ( value , STRINGIFY ( ICE_INACTIVE ) ) )
con - > state = ICE_INACTIVE ;
else if ( ! strcmp ( value , STRINGIFY ( ICE_FAILED ) ) )
con - > state = ICE_FAILED ;
else if ( ! strcmp ( value , STRINGIFY ( ICE_CONNECTED ) ) )
con - > state = ICE_CONNECTED ;
else
{
Con_Printf ( " ICE_Set invalid state %s \n " , value ) ;
con - > state = ICE_INACTIVE ;
}
con - > timeout = Sys_Milliseconds ( ) ;
con - > retries = 0 ;
if ( oldstate ! = con - > state & & con - > state = = ICE_CONNECTED )
{
if ( con - > chosenpeer . type = = NA_INVALID )
{
con - > state = ICE_FAILED ;
Con_Printf ( " ICE failed. peer not valid. \n " ) ;
}
# ifndef SERVERONLY
else if ( con - > proto = = ICEP_QWCLIENT )
{
char msg [ 256 ] ;
// Con_Printf("Try typing connect %s\n", NET_AdrToString(msg, sizeof(msg), &con->chosenpeer));
Cbuf_AddText ( va ( " \n connect \" %s \" \n " , NET_AdrToString ( msg , sizeof ( msg ) , & con - > chosenpeer ) ) , RESTRICT_LOCAL ) ;
}
# endif
# ifndef CLIENTONLY
else if ( con - > proto = = ICEP_QWSERVER )
{
extern void SVC_GetChallenge ( ) ;
net_from = con - > chosenpeer ;
SVC_GetChallenge ( ) ;
}
# endif
if ( con - > state = = ICE_CONNECTED )
Con_Printf ( " %s connection established. \n " , con - > proto = = ICEP_VOICE ? " voice " : " Quake " ) ;
}
# if !defined(SERVERONLY) && defined(VOICECHAT)
cl_voip_send . ival = ( cl_voip_send . ival & ~ 4 ) | ( NET_RTP_Active ( ) ? 4 : 0 ) ;
# endif
}
else if ( ! strcmp ( prop , " controlled " ) )
con - > controlled = ! ! atoi ( value ) ;
else if ( ! strcmp ( prop , " controller " ) )
con - > controlled = ! atoi ( value ) ;
else if ( ! strncmp ( prop , " codec " , 5 ) )
{
int codec = atoi ( prop + 5 ) ;
if ( codec < 96 | | codec > 127 )
return false ;
if ( strcmp ( value , " speex@8000 " ) & & strcmp ( value , " speex@16000 " ) ) // && strcmp(value, "opus"))
return false ;
codec - = 96 ;
Z_Free ( con - > codec [ codec ] ) ;
con - > codec [ codec ] = Z_StrDup ( value ) ;
}
else if ( ! strcmp ( prop , " rufrag " ) )
{
Z_Free ( con - > rufrag ) ;
con - > rufrag = Z_StrDup ( value ) ;
}
else if ( ! strcmp ( prop , " rpwd " ) )
{
Z_Free ( con - > rpwd ) ;
con - > rpwd = Z_StrDup ( value ) ;
}
else if ( ! strcmp ( prop , " stunip " ) )
{
Z_Free ( con - > stunserver ) ;
con - > stunserver = Z_StrDup ( value ) ;
NET_StringToAdr ( con - > stunserver , con - > stunport , & con - > pubstunserver ) ;
}
else if ( ! strcmp ( prop , " stunport " ) )
{
con - > stunport = atoi ( value ) ;
if ( con - > stunserver )
NET_StringToAdr ( con - > stunserver , con - > stunport , & con - > pubstunserver ) ;
}
else
return false ;
return true ;
}
qboolean QDECL ICE_Get ( struct icestate_s * con , char * prop , char * value , int valuelen )
{
if ( ! strcmp ( prop , " sid " ) )
Q_strncpyz ( value , con - > conname , valuelen ) ;
else if ( ! strcmp ( prop , " state " ) )
Q_snprintfz ( value , valuelen , " %i " , con - > state ) ;
else if ( ! strcmp ( prop , " lufrag " ) )
Q_strncpyz ( value , con - > lufrag , valuelen ) ;
else if ( ! strcmp ( prop , " lpwd " ) )
Q_strncpyz ( value , con - > lpwd , valuelen ) ;
else if ( ! strncmp ( prop , " codec " , 5 ) )
{
int codec = atoi ( prop + 5 ) ;
if ( codec < 96 | | codec > 127 )
return false ;
codec - = 96 ;
if ( con - > codec [ codec ] )
Q_strncpyz ( value , con - > codec [ codec ] , valuelen ) ;
else
Q_strncpyz ( value , " " , valuelen ) ;
}
else if ( ! strcmp ( prop , " newlc " ) )
{
struct icecandidate_s * can ;
Q_strncpyz ( value , " 0 " , valuelen ) ;
for ( can = con - > lc ; can ; can = can - > next )
{
if ( can - > dirty )
{
Q_strncpyz ( value , " 1 " , valuelen ) ;
break ;
}
}
}
else
return false ;
return true ;
}
struct icecandinfo_s * QDECL ICE_GetLCandidateInfo ( struct icestate_s * con )
2013-06-23 02:17:02 +00:00
{
struct icecandidate_s * can ;
for ( can = con - > lc ; can ; can = can - > next )
{
if ( can - > dirty )
{
can - > dirty = false ;
2013-06-29 16:01:07 +00:00
return & can - > info ;
2013-06-23 02:17:02 +00:00
}
}
return NULL ;
}
2013-06-29 16:01:07 +00:00
void QDECL ICE_AddRCandidateInfo ( struct icestate_s * con , struct icecandinfo_s * n )
2013-06-23 02:17:02 +00:00
{
struct icecandidate_s * o ;
2013-06-29 16:01:07 +00:00
qboolean isnew ;
netadr_t peer ;
//I don't give a damn about rtpc.
if ( n - > component ! = 1 )
return ;
if ( ! NET_StringToAdr ( n - > addr , n - > port , & peer ) )
return ;
2013-07-13 12:14:32 +00:00
if ( peer . type = = NA_IP )
{
//ignore invalid addresses
if ( ! peer . address . ip [ 0 ] & & ! peer . address . ip [ 1 ] & & ! peer . address . ip [ 2 ] & & ! peer . address . ip [ 3 ] )
return ;
}
2013-06-23 02:17:02 +00:00
for ( o = con - > rc ; o ; o = o - > next )
{
2013-06-29 16:01:07 +00:00
//not sure that updating candidates is particuarly useful tbh, but hey.
if ( ! strcmp ( o - > info . candidateid , n - > candidateid ) )
2013-06-23 02:17:02 +00:00
break ;
}
if ( ! o )
{
o = Z_Malloc ( sizeof ( * o ) ) ;
o - > next = con - > rc ;
con - > rc = o ;
2013-06-29 16:01:07 +00:00
Q_strncpyz ( o - > info . candidateid , n - > candidateid , sizeof ( o - > info . candidateid ) ) ;
isnew = true ;
2013-06-23 02:17:02 +00:00
}
else
{
2013-06-29 16:01:07 +00:00
isnew = false ;
}
Q_strncpyz ( o - > info . addr , n - > addr , sizeof ( o - > info . addr ) ) ;
o - > info . port = n - > port ;
o - > info . type = n - > type ;
o - > info . priority = n - > priority ;
o - > info . network = n - > network ;
o - > info . generation = n - > generation ;
o - > info . foundation = n - > foundation ;
o - > info . component = n - > component ;
o - > info . transport = n - > transport ;
o - > dirty = true ;
o - > peer = peer ;
o - > tried = 0 ;
o - > reachable = 0 ;
Con_DPrintf ( " %s remote candidate %s: [%s]:%i \n " , isnew ? " Added " : " Updated " , o - > info . candidateid , o - > info . addr , o - > info . port ) ;
2013-06-23 02:17:02 +00:00
}
static void ICE_Destroy ( struct icestate_s * con )
{
//has already been unlinked
Z_Free ( con ) ;
}
2013-06-29 16:01:07 +00:00
static void ICE_Tick ( void )
{
struct icestate_s * con ;
unsigned int curtime = Sys_Milliseconds ( ) ;
for ( con = icelist ; con ; con = con - > next )
{
switch ( con - > mode )
{
case ICEM_RAW :
//raw doesn't do handshakes or keepalives. it should just directly connect.
//raw just uses the first (assumed only) option
if ( con - > state = = ICE_CONNECTING )
{
struct icecandidate_s * rc ;
rc = con - > rc ;
if ( rc )
NET_StringToAdr ( rc - > info . addr , rc - > info . port , & con - > chosenpeer ) ;
else
con - > chosenpeer . type = NA_INVALID ;
ICE_Set ( con , " state " , STRINGIFY ( ICE_CONNECTED ) ) ;
}
break ;
case ICEM_ICE :
if ( con - > state = = ICE_CONNECTING )
{
if ( con - > stunretry < curtime & & con - > pubstunserver . type ! = NA_INVALID )
{
ICE_ToStunServer ( con ) ;
con - > stunretry = curtime + 2 * 1000 ;
}
if ( con - > keepalive < curtime )
{
if ( ! ICE_SendSpam ( con ) )
{
struct icecandidate_s * rc ;
struct icecandidate_s * best = NULL ;
for ( rc = con - > rc ; rc ; rc = rc - > next )
{
if ( rc - > reachable & & ( ! best | | rc - > info . priority > best - > info . priority ) )
best = rc ;
}
if ( best )
{
best - > tried = ~ best - > reachable ;
con - > chosenpeer = best - > peer ;
ICE_SendSpam ( con ) ;
}
else
{
for ( rc = con - > rc ; rc ; rc = rc - > next )
rc - > tried = 0 ;
}
con - > retries + + ;
if ( con - > retries > 32 )
con - > retries = 32 ;
con - > keepalive = curtime + 200 * ( con - > retries ) ; //RTO
}
else
con - > keepalive = curtime + 50 * ( con - > retries + 1 ) ; //Ta
}
}
break ;
}
}
}
2013-06-23 02:17:02 +00:00
void QDECL ICE_Close ( struct icestate_s * con )
{
struct icestate_s * * link ;
2013-06-29 21:08:09 +00:00
ICE_Set ( con , " state " , STRINGIFY ( ICE_INACTIVE ) ) ;
2013-06-23 02:17:02 +00:00
for ( link = & icelist ; * link ; )
{
if ( con = = * link )
{
* link = con - > next ;
ICE_Destroy ( con ) ;
return ;
}
else
link = & ( * link ) - > next ;
}
}
void QDECL ICE_CloseModule ( void * module )
{
struct icestate_s * * link , * con ;
for ( link = & icelist ; * link ; )
{
con = * link ;
if ( con - > module = = module )
{
* link = con - > next ;
ICE_Destroy ( con ) ;
}
else
link = & ( * link ) - > next ;
}
}
2013-06-29 16:01:07 +00:00
icefuncs_t iceapi =
2008-11-09 22:29:28 +00:00
{
2013-06-29 16:01:07 +00:00
ICE_Create ,
ICE_Set ,
ICE_Get ,
ICE_GetLCandidateInfo ,
ICE_AddRCandidateInfo ,
ICE_Close ,
ICE_CloseModule
} ;
2013-03-31 04:21:08 +00:00
2013-06-29 16:01:07 +00:00
static qboolean NET_WasStun ( netsrc_t netsrc )
{
# if !defined(SERVERONLY) && defined(VOICECHAT)
if ( netsrc = = NS_CLIENT )
2013-03-31 04:21:08 +00:00
{
2013-06-29 16:01:07 +00:00
if ( NET_RTP_Parse ( ) )
return true ;
2013-03-31 04:21:08 +00:00
}
2008-11-09 22:29:28 +00:00
# endif
2013-03-31 04:21:08 +00:00
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 ) ;
2013-06-29 16:01:07 +00:00
if ( ( stun - > msgtype = = BigShort ( 0x0101 ) | | stun - > msgtype = = BigShort ( 0x0111 ) ) & & net_message . cursize = = stunlen + sizeof ( * stun ) )
2013-03-31 04:21:08 +00:00
{
2013-06-29 16:01:07 +00:00
//binding reply (or error)
netadr_t adr = net_from ;
char xor [ 16 ] ;
short portxor ;
2013-03-31 04:21:08 +00:00
stunattr_t * attr = ( stunattr_t * ) ( stun + 1 ) ;
int alen ;
while ( stunlen )
{
stunlen - = sizeof ( * attr ) ;
2013-06-29 16:01:07 +00:00
alen = ( unsigned short ) BigShort ( attr - > attrlen ) ;
2013-03-31 04:21:08 +00:00
if ( alen > stunlen )
return false ;
2013-06-23 02:17:02 +00:00
stunlen - = alen ;
switch ( BigShort ( attr - > attrtype ) )
2013-03-31 04:21:08 +00:00
{
2013-06-29 16:01:07 +00:00
default :
break ;
2013-06-23 02:17:02 +00:00
case 1 :
2013-06-29 16:01:07 +00:00
case 0x20 :
if ( BigShort ( attr - > attrtype ) = = 0x20 )
{
portxor = * ( short * ) & stun - > magiccookie ;
memcpy ( xor , & stun - > magiccookie , sizeof ( xor ) ) ;
}
else
{
portxor = 0 ;
memset ( xor , 0 , sizeof ( xor ) ) ;
}
2013-06-23 02:17:02 +00:00
if ( alen = = 8 & & ( ( qbyte * ) attr ) [ 5 ] = = 1 ) //ipv4 MAPPED-ADDRESS
{
char str [ 256 ] ;
adr . type = NA_IP ;
2013-06-29 16:01:07 +00:00
adr . port = ( ( ( short * ) attr ) [ 3 ] ) ^ portxor ;
* ( int * ) adr . address . ip = * ( int * ) ( & ( ( qbyte * ) attr ) [ 8 ] ) ^ * ( int * ) xor ;
2013-06-23 02:17:02 +00:00
NET_AdrToString ( str , sizeof ( str ) , & adr ) ;
}
else if ( alen = = 20 & & ( ( qbyte * ) attr ) [ 5 ] = = 2 ) //ipv6 MAPPED-ADDRESS
{
netadr_t adr ;
char str [ 256 ] ;
adr . type = NA_IPV6 ;
2013-06-29 16:01:07 +00:00
adr . port = ( ( ( short * ) attr ) [ 3 ] ) ^ portxor ;
( ( int * ) adr . address . ip6 ) [ 0 ] = ( ( int * ) & ( ( qbyte * ) attr ) [ 8 ] ) [ 0 ] ^ ( ( int * ) xor ) [ 0 ] ;
( ( int * ) adr . address . ip6 ) [ 1 ] = ( ( int * ) & ( ( qbyte * ) attr ) [ 8 ] ) [ 1 ] ^ ( ( int * ) xor ) [ 1 ] ;
( ( int * ) adr . address . ip6 ) [ 2 ] = ( ( int * ) & ( ( qbyte * ) attr ) [ 8 ] ) [ 2 ] ^ ( ( int * ) xor ) [ 2 ] ;
( ( int * ) adr . address . ip6 ) [ 3 ] = ( ( int * ) & ( ( qbyte * ) attr ) [ 8 ] ) [ 3 ] ^ ( ( int * ) xor ) [ 3 ] ;
2013-06-23 02:17:02 +00:00
NET_AdrToString ( str , sizeof ( str ) , & adr ) ;
2013-06-29 16:01:07 +00:00
}
{
struct icestate_s * con ;
for ( con = icelist ; con ; con = con - > next )
{
char str [ 256 ] ;
struct icecandidate_s * rc ;
if ( con - > mode ! = ICEM_ICE )
continue ;
//check to see if this is a new peer-reflexive address, which happens when the peer is behind a nat.
if ( NET_CompareAdr ( & net_from , & con - > pubstunserver ) )
{
for ( rc = con - > lc ; rc ; rc = rc - > next )
{
if ( NET_CompareAdr ( & adr , & rc - > peer ) )
break ;
}
if ( ! rc )
{
struct icecandidate_s * rc ;
rc = Z_Malloc ( sizeof ( * rc ) ) ;
rc - > next = con - > lc ;
con - > lc = rc ;
rc - > peer = adr ;
NET_BaseAdrToString ( rc - > info . addr , sizeof ( rc - > info . addr ) , & adr ) ;
rc - > info . port = ntohs ( adr . port ) ;
rc - > info . type = ICE_SRFLX ;
rc - > info . component = 1 ;
rc - > dirty = true ;
rc - > info . priority = 1 ; //FIXME
Con_DPrintf ( " Public address: %s \n " , str ) ;
}
con - > stunretry = Sys_Milliseconds ( ) + 60 * 1000 ;
}
else
{
for ( rc = con - > rc ; rc ; rc = rc - > next )
{
if ( NET_CompareAdr ( & net_from , & rc - > peer ) )
{
if ( ! ( rc - > reachable & ( 1u < < ( net_from . connum - 1 ) ) ) )
Con_DPrintf ( " We can reach %s \n " , NET_AdrToString ( str , sizeof ( str ) , & net_from ) ) ;
rc - > reachable | = 1u < < ( net_from . connum - 1 ) ;
if ( NET_CompareAdr ( & net_from , & con - > chosenpeer ) & & ( stun - > transactid [ 2 ] & BigLong ( 0x80000000 ) ) )
ICE_Set ( con , " state " , STRINGIFY ( ICE_CONNECTED ) ) ;
}
}
}
}
}
break ;
case 9 :
{
char msg [ 64 ] ;
char sender [ 256 ] ;
unsigned short len = BigShort ( attr - > attrlen ) - 4 ;
if ( len > sizeof ( msg ) - 1 )
len = sizeof ( msg ) - 1 ;
memcpy ( msg , & ( ( qbyte * ) attr ) [ 8 ] , len ) ;
msg [ len ] = 0 ;
Con_DPrintf ( " %s: Stun error code %u : %s \n " , NET_AdrToString ( sender , sizeof ( sender ) , & net_from ) , ( ( qbyte * ) attr ) [ 7 ] , msg ) ;
if ( ( ( qbyte * ) attr ) [ 7 ] = = 1 )
{
//not authorised.
}
if ( ( ( qbyte * ) attr ) [ 7 ] = = 87 )
{
//role conflict.
}
2013-06-23 02:17:02 +00:00
}
break ;
2013-03-31 04:21:08 +00:00
}
2013-06-29 16:01:07 +00:00
alen = ( alen + 3 ) & ~ 3 ;
2013-06-23 02:17:02 +00:00
attr = ( stunattr_t * ) ( ( char * ) ( attr + 1 ) + alen ) ;
}
return true ;
}
2013-06-29 16:01:07 +00:00
else if ( stun - > msgtype = = BigShort ( 0x0011 ) & & net_message . cursize = = stunlen + sizeof ( * stun ) & & stun - > magiccookie = = BigLong ( 0x2112a442 ) )
{
//binding indication. used as an rtp keepalive.
return true ;
}
else if ( stun - > msgtype = = BigShort ( 0x0001 ) & & net_message . cursize = = stunlen + sizeof ( * stun ) & & stun - > magiccookie = = BigLong ( 0x2112a442 ) )
2013-06-23 02:17:02 +00:00
{
char username [ 256 ] ;
2013-06-29 16:01:07 +00:00
char integrity [ 20 ] ;
char * integritypos = NULL ;
int role = 0 ;
struct icestate_s * con ;
unsigned int tiehigh = 0 ;
unsigned int tielow = 0 ;
qboolean usecandidate = false ;
int error = 0 ;
unsigned int priority = 0 ;
2013-06-23 02:17:02 +00:00
//binding request
stunattr_t * attr = ( stunattr_t * ) ( stun + 1 ) ;
int alen ;
* username = 0 ;
while ( stunlen )
{
alen = ( unsigned short ) BigShort ( attr - > attrlen ) ;
if ( alen + sizeof ( * attr ) > stunlen )
return false ;
switch ( ( unsigned short ) BigShort ( attr - > attrtype ) )
2013-03-31 04:21:08 +00:00
{
2013-06-29 16:01:07 +00:00
default :
//unknown attributes < 0x8000 are 'mandatory to parse', and such packets must be dropped in their entirety.
//other ones are okay.
if ( ! ( ( unsigned short ) BigShort ( attr - > attrtype ) & 0x8000 ) )
return false ;
break ;
2013-06-23 02:17:02 +00:00
case 0x6 :
//username
if ( alen < sizeof ( username ) )
{
memcpy ( username , attr + 1 , alen ) ;
username [ alen ] = 0 ;
2013-06-29 16:01:07 +00:00
// Con_Printf("Stun username = \"%s\"\n", username);
2013-06-23 02:17:02 +00:00
}
break ;
case 0x8 :
//message integrity
2013-06-29 16:01:07 +00:00
memcpy ( integrity , attr + 1 , sizeof ( integrity ) ) ;
integritypos = ( char * ) ( attr + 1 ) ;
2013-06-23 02:17:02 +00:00
break ;
case 0x24 :
//priority
2013-06-29 16:01:07 +00:00
// Con_Printf("priority = \"%i\"\n", priority);
priority = BigLong ( * ( int * ) ( attr + 1 ) ) ;
break ;
case 0x25 :
//USE-CANDIDATE
usecandidate = true ;
2013-06-23 02:17:02 +00:00
break ;
case 0x8028 :
//fingerprint
2013-06-29 16:01:07 +00:00
// Con_Printf("fingerprint = \"%08x\"\n", BigLong(*(int*)(attr+1)));
2013-06-23 02:17:02 +00:00
break ;
2013-06-29 16:01:07 +00:00
case 0x8029 : //ice controlled
case 0x802A : //ice controlling
role = ( unsigned short ) BigShort ( attr - > attrtype ) ;
2013-06-23 02:17:02 +00:00
//ice controlled
2013-06-29 16:01:07 +00:00
tiehigh = BigLong ( ( ( int * ) ( attr + 1 ) ) [ 0 ] ) ;
tielow = BigLong ( ( ( int * ) ( attr + 1 ) ) [ 1 ] ) ;
2013-06-23 02:17:02 +00:00
break ;
2013-03-31 04:21:08 +00:00
}
2013-06-23 02:17:02 +00:00
alen = ( alen + 3 ) & ~ 3 ;
2013-03-31 04:21:08 +00:00
attr = ( stunattr_t * ) ( ( char * ) ( attr + 1 ) + alen ) ;
2013-06-23 02:17:02 +00:00
stunlen - = alen + sizeof ( * attr ) ;
}
2013-06-29 16:01:07 +00:00
//we need to know which connection its from in order to validate the integrity
for ( con = icelist ; con ; con = con - > next )
{
if ( ! strcmp ( va ( " %s:%s " , con - > lufrag , con - > rufrag ) , username ) )
break ;
}
if ( ! con )
2013-06-23 02:17:02 +00:00
{
2013-06-29 16:01:07 +00:00
Con_DPrintf ( " Received STUN request from unknown user \" %s \" \n " , username ) ;
}
else
{
if ( integritypos )
{
char key [ 20 ] ;
//the hmac is a bit weird. the header length includes the integrity attribute's length, but the checksum doesn't even consider the attribute header.
stun - > msglen = BigShort ( integritypos + sizeof ( integrity ) - ( char * ) stun - sizeof ( * stun ) ) ;
2013-07-13 12:14:32 +00:00
SHA1_HMAC ( key , sizeof ( key ) , ( qbyte * ) stun , integritypos - 4 - ( char * ) stun , con - > lpwd , strlen ( con - > lpwd ) ) ;
2013-06-29 16:01:07 +00:00
if ( memcmp ( key , integrity , sizeof ( integrity ) ) )
{
Con_DPrintf ( " Integrity is bad! needed %x got %x \n " , * ( int * ) key , * ( int * ) integrity ) ;
return true ;
}
}
if ( con - > state ! = ICE_INACTIVE )
{
sizebuf_t buf ;
char data [ 512 ] ;
int alen = 0 , atype = 0 , aofs = 0 ;
int crc ;
struct icecandidate_s * rc ;
memset ( & buf , 0 , sizeof ( buf ) ) ;
buf . maxsize = sizeof ( data ) ;
buf . cursize = 0 ;
buf . data = data ;
//check to see if this is a new peer-reflexive address, which happens when the peer is behind a nat.
for ( rc = con - > rc ; rc ; rc = rc - > next )
{
if ( NET_CompareAdr ( & net_from , & rc - > peer ) )
break ;
}
if ( ! rc )
{
struct icecandidate_s * rc ;
rc = Z_Malloc ( sizeof ( * rc ) ) ;
rc - > next = con - > rc ;
con - > rc = rc ;
rc - > peer = net_from ;
NET_BaseAdrToString ( rc - > info . addr , sizeof ( rc - > info . addr ) , & net_from ) ;
rc - > info . port = ntohs ( net_from . port ) ;
rc - > info . type = ICE_PRFLX ;
rc - > dirty = true ;
rc - > info . priority = priority ;
}
//flip ice control role, if we're wrong.
if ( role & & role ! = ( con - > controlled ? 0x802A : 0x8029 ) )
{
con - > controlled = ( tiehigh > con - > tiehigh ) | | ( tiehigh = = con - > tiehigh & & tielow > con - > tielow ) ;
Con_DPrintf ( " role conflict detected. We should be %s \n " , con - > controlled ? " controlled " : " controlling " ) ;
error = 87 ;
}
else if ( usecandidate & & con - > controlled )
{
//in the controlled role, we're connected once we're told the pair to use (by the usecandidate flag).
//note that this 'nominates' candidate pairs, from which the highest priority is chosen.
//so we just pick select the highest.
//this is problematic, however, as we don't actually know the real priority that the peer thinks we'll nominate it with.
if ( con - > chosenpeer . type ! = NA_INVALID & & ! NET_CompareAdr ( & net_from , & con - > chosenpeer ) )
Con_DPrintf ( " Duplicate use-candidate \n " ) ;
con - > chosenpeer = net_from ;
Con_DPrintf ( " use-candidate: %s \n " , NET_AdrToString ( data , sizeof ( data ) , & net_from ) ) ;
ICE_Set ( con , " state " , STRINGIFY ( ICE_CONNECTED ) ) ;
}
if ( net_from . type = = NA_IP )
{
alen = 4 ;
atype = 1 ;
aofs = 0 ;
}
else if ( net_from . type = = NA_IPV6 & &
! * ( int * ) & net_from . address . ip6 [ 0 ] & &
! * ( int * ) & net_from . address . ip6 [ 4 ] & &
! * ( short * ) & net_from . address . ip6 [ 8 ] & &
* ( short * ) & net_from . address . ip6 [ 10 ] = = ( short ) 0xffff )
{ //just because we use an ipv6 address for ipv4 internally doesn't mean we should tell the peer that they're on ipv6...
alen = 4 ;
atype = 1 ;
aofs = sizeof ( net_from . address . ip6 ) - sizeof ( net_from . address . ip ) ;
}
else if ( net_from . type = = NA_IPV6 )
{
alen = 16 ;
atype = 2 ;
aofs = 0 ;
}
MSG_WriteShort ( & buf , BigShort ( error ? 0x0111 : 0x0101 ) ) ;
MSG_WriteShort ( & buf , BigShort ( 0 ) ) ; //fill in later
MSG_WriteLong ( & buf , stun - > magiccookie ) ;
MSG_WriteLong ( & buf , stun - > transactid [ 0 ] ) ;
MSG_WriteLong ( & buf , stun - > transactid [ 1 ] ) ;
MSG_WriteLong ( & buf , stun - > transactid [ 2 ] ) ;
if ( error )
{
char * txt = " Role Conflict " ;
MSG_WriteShort ( & buf , BigShort ( 0x0009 ) ) ;
MSG_WriteShort ( & buf , BigShort ( 4 + strlen ( txt ) ) ) ;
MSG_WriteShort ( & buf , 0 ) ; //reserved
MSG_WriteByte ( & buf , 0 ) ; //class
MSG_WriteByte ( & buf , error ) ; //code
SZ_Write ( & buf , txt , strlen ( txt ) ) ; //readable
while ( buf . cursize & 3 ) //padding
MSG_WriteChar ( & buf , 0 ) ;
}
else if ( 1 )
{ //xor mapped
MSG_WriteShort ( & buf , BigShort ( 0x0020 ) ) ;
MSG_WriteShort ( & buf , BigShort ( 4 + alen ) ) ;
MSG_WriteShort ( & buf , BigShort ( atype ) ) ;
MSG_WriteShort ( & buf , net_from . port ) ;
SZ_Write ( & buf , ( char * ) & net_from . address + aofs , alen ) ;
}
else
{ //non-xor mapped
MSG_WriteShort ( & buf , BigShort ( 0x0001 ) ) ;
MSG_WriteShort ( & buf , BigShort ( 4 + alen ) ) ;
MSG_WriteShort ( & buf , BigShort ( atype ) ) ;
MSG_WriteShort ( & buf , net_from . port ) ;
SZ_Write ( & buf , ( char * ) & net_from . address + aofs , alen ) ;
}
MSG_WriteShort ( & buf , BigShort ( 0x6 ) ) ; //USERNAME
MSG_WriteShort ( & buf , BigShort ( strlen ( username ) ) ) ;
SZ_Write ( & buf , username , strlen ( username ) ) ;
while ( buf . cursize & 3 )
MSG_WriteChar ( & buf , 0 ) ;
//message integrity is a bit annoying
data [ 2 ] = ( ( buf . cursize + 4 + sizeof ( integrity ) - 20 ) > > 8 ) & 0xff ; //hashed header length is up to the end of the hmac attribute
data [ 3 ] = ( ( buf . cursize + 4 + sizeof ( integrity ) - 20 ) > > 0 ) & 0xff ;
//but the hash is to the start of the attribute's header
SHA1_HMAC ( integrity , sizeof ( integrity ) , con - > lpwd , strlen ( con - > lpwd ) , data , buf . cursize ) ;
MSG_WriteShort ( & buf , BigShort ( 0x8 ) ) ; //MESSAGE-INTEGRITY
MSG_WriteShort ( & buf , BigShort ( sizeof ( integrity ) ) ) ; //sha1 key length
SZ_Write ( & buf , integrity , sizeof ( integrity ) ) ; //integrity data
data [ 2 ] = ( ( buf . cursize + 8 - 20 ) > > 8 ) & 0xff ; //dummy length
data [ 3 ] = ( ( buf . cursize + 8 - 20 ) > > 0 ) & 0xff ;
crc = crc32 ( 0 , data , buf . cursize ) ^ 0x5354554e ;
MSG_WriteShort ( & buf , BigShort ( 0x8028 ) ) ; //FINGERPRINT
MSG_WriteShort ( & buf , BigShort ( sizeof ( crc ) ) ) ;
MSG_WriteLong ( & buf , BigLong ( crc ) ) ;
data [ 2 ] = ( ( buf . cursize - 20 ) > > 8 ) & 0xff ;
data [ 3 ] = ( ( buf . cursize - 20 ) > > 0 ) & 0xff ;
NET_SendPacket ( netsrc , buf . cursize , data , & net_from ) ;
}
2013-03-31 04:21:08 +00:00
}
2013-06-23 02:17:02 +00:00
2013-03-31 04:21:08 +00:00
return true ;
}
}
return false ;
}
2013-06-29 16:01:07 +00:00
# endif
2013-03-31 04:21:08 +00:00
2013-06-29 16:01:07 +00:00
# ifndef CLIENTONLY
void SVNET_AddPort_f ( void )
{
char * s = Cmd_Argv ( 1 ) ;
char * conname = Cmd_Argv ( 2 ) ;
2013-03-31 04:21:08 +00:00
2013-06-29 16:01:07 +00:00
if ( ! * s & & ! * conname )
2013-03-31 04:21:08 +00:00
{
2013-06-29 16:01:07 +00:00
Con_Printf ( " Active Server ports: \n " ) ;
NET_PrintAddresses ( svs . sockets ) ;
Con_Printf ( " end of list \n " ) ;
2013-03-31 04:21:08 +00:00
return ;
}
2013-06-29 16:01:07 +00:00
if ( ! * conname )
conname = NULL ;
//just in case
if ( ! svs . sockets )
{
svs . sockets = FTENET_CreateCollection ( true ) ;
# ifndef SERVERONLY
FTENET_AddToCollection ( svs . sockets , " SVLoopback " , " 27500 " , NA_LOOPBACK , true ) ;
# endif
}
2013-03-31 04:21:08 +00:00
2013-06-29 16:01:07 +00:00
FTENET_AddToCollection ( svs . sockets , conname , * s ? s : NULL , * s ? NA_IP : NA_INVALID , true ) ;
2013-03-31 04:21:08 +00:00
}
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
2013-06-23 02:17:02 +00:00
qboolean NET_WasSpecialPacket ( netsrc_t netsrc )
2013-03-31 04:21:08 +00:00
{
2013-06-23 02:17:02 +00:00
ftenet_connections_t * collection = NULL ;
if ( netsrc = = NS_SERVER )
{
2013-03-31 04:21:08 +00:00
# ifndef CLIENTONLY
2013-06-23 02:17:02 +00:00
collection = svs . sockets ;
# endif
}
else
{
# ifndef SERVERONLY
collection = cls . sockets ;
# endif
}
2013-07-31 00:20:16 +00:00
# ifdef SUPPORT_ICE
2013-06-23 02:17:02 +00:00
if ( NET_WasStun ( netsrc ) )
2013-03-31 04:21:08 +00:00
return true ;
2013-07-31 00:20:16 +00:00
# endif
2013-03-31 04:21:08 +00:00
# ifdef HAVE_NATPMP
2013-06-23 02:17:02 +00:00
if ( NET_Was_NATPMP ( collection ) )
2013-03-31 04:21:08 +00:00
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
# 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-05-11 14:02:55 +00:00
FTENET_AddToCollection ( cls . sockets , " CLLoopback " , " 1 " , 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-05-03 04:28:08 +00:00
# if 1 //def SERVERONLY
2013-03-31 04:21:08 +00:00
# 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 )
{
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
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
2013-05-11 05:03:07 +00:00
FTENET_AddToCollection ( svs . sockets , " SVLoopback " , STRINGIFY ( PORT_QWSERVER ) , NA_LOOPBACK , true ) ;
2013-03-31 04:21:08 +00:00
# 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
2013-04-04 08:08:49 +00:00
# if defined(TCPCONNECT) && defined(HAVE_TCP)
2008-11-09 22:29:28 +00:00
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-05-11 05:03:07 +00:00
FTENET_AddToCollection ( svs . sockets , " SVLoopback " , STRINGIFY ( PORT_QWSERVER ) , 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
2013-06-29 16:01:07 +00:00
void NET_Tick ( void )
{
# ifdef SUPPORT_ICE
ICE_Tick ( ) ;
# endif
}
2004-08-21 01:25:48 +00:00
/*
= = = = = = = = = = = = = = = = = = = =
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 ;
2013-06-23 02:17:02 +00:00
SOCKET sock ;
qboolean conpending ;
2006-03-14 01:25:46 +00:00
char readbuffer [ 65536 ] ;
int readbuffered ;
2013-06-29 16:01:07 +00:00
char peer [ 1 ] ;
2006-03-14 01:25:46 +00:00
} tcpfile_t ;
void VFSTCP_Error ( tcpfile_t * f )
{
if ( f - > sock ! = INVALID_SOCKET )
{
closesocket ( f - > sock ) ;
f - > sock = INVALID_SOCKET ;
}
}
2013-05-03 04:28:08 +00:00
int QDECL VFSTCP_ReadBytes ( struct vfsfile_s * file , void * buffer , int bytestoread )
2006-03-14 01:25:46 +00:00
{
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
2013-06-23 02:17:02 +00:00
if ( tf - > conpending )
{
2013-06-29 16:01:07 +00:00
fd_set wr ;
fd_set ex ;
2013-06-23 02:17:02 +00:00
struct timeval timeout ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 0 ;
2013-06-29 16:01:07 +00:00
FD_ZERO ( & wr ) ;
FD_SET ( tf - > sock , & wr ) ;
FD_ZERO ( & ex ) ;
FD_SET ( tf - > sock , & ex ) ;
if ( ! select ( ( int ) tf - > sock + 1 , NULL , & wr , & ex , & timeout ) )
2013-06-23 02:17:02 +00:00
return 0 ;
tf - > conpending = false ;
}
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 )
{
2013-06-29 16:01:07 +00:00
case ENOTCONN :
Con_Printf ( " connection to \" %s \" failed \n " , tf - > peer ) ;
break ;
2013-03-31 04:21:08 +00:00
case ECONNABORTED :
2013-06-29 16:01:07 +00:00
Con_DPrintf ( " connection to \" %s \" aborted \n " , tf - > peer ) ;
2013-03-31 04:21:08 +00:00
break ;
2013-06-23 02:17:02 +00:00
case ECONNREFUSED :
2013-06-29 16:01:07 +00:00
Con_DPrintf ( " connection to \" %s \" refused \n " , tf - > peer ) ;
2013-06-23 02:17:02 +00:00
break ;
case ECONNRESET :
2013-06-29 16:01:07 +00:00
Con_DPrintf ( " connection to \" %s \" reset \n " , tf - > peer ) ;
2013-06-23 02:17:02 +00:00
break ;
2013-03-31 04:21:08 +00:00
default :
2013-06-29 16:01:07 +00:00
Con_Printf ( " socket error %i \n " , e ) ;
2013-03-31 04:21:08 +00:00
}
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 )
2013-06-24 09:04:00 +00:00
{
perror ( " moo " ) ;
2007-12-01 05:55:44 +00:00
return - 1 ; //signal an error
2013-06-24 09:04:00 +00:00
}
2007-12-01 05:55:44 +00:00
return 0 ; //signal nothing available
}
2006-03-14 01:25:46 +00:00
}
2013-05-03 04:28:08 +00:00
int QDECL 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 ;
2013-06-23 02:17:02 +00:00
if ( tf - > conpending )
{
fd_set fd ;
struct timeval timeout ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 0 ;
FD_ZERO ( & fd ) ;
FD_SET ( tf - > sock , & fd ) ;
2013-06-24 09:04:00 +00:00
if ( ! select ( ( int ) tf - > sock + 1 , NULL , & fd , NULL , & timeout ) )
2013-06-23 02:17:02 +00:00
return 0 ;
tf - > conpending = false ;
}
2006-03-14 01:25:46 +00:00
len = send ( tf - > sock , buffer , bytestoread , 0 ) ;
if ( len = = - 1 | | len = = 0 )
{
2013-06-23 02:17:02 +00:00
int e = qerrno ;
switch ( e )
{
default :
Sys_Printf ( " socket error %i \n " , e ) ;
break ;
}
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 ;
}
2013-05-03 04:28:08 +00:00
qboolean QDECL VFSTCP_Seek ( struct vfsfile_s * file , unsigned long pos )
2006-03-14 01:25:46 +00:00
{
VFSTCP_Error ( ( tcpfile_t * ) file ) ;
return false ;
}
2013-05-03 04:28:08 +00:00
unsigned long QDECL VFSTCP_Tell ( struct vfsfile_s * file )
2006-03-14 01:25:46 +00:00
{
VFSTCP_Error ( ( tcpfile_t * ) file ) ;
return 0 ;
}
2013-05-03 04:28:08 +00:00
unsigned long QDECL VFSTCP_GetLen ( struct vfsfile_s * file )
2006-03-14 01:25:46 +00:00
{
return 0 ;
}
2013-05-03 04:28:08 +00:00
void QDECL VFSTCP_Close ( struct vfsfile_s * file )
2006-03-14 01:25:46 +00:00
{
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
{
2013-05-03 04:28:08 +00:00
sock = TCP_OpenStream ( & adr ) ;
2006-03-23 19:22:12 +00:00
if ( sock = = INVALID_SOCKET )
return NULL ;
2013-06-29 16:01:07 +00:00
newf = Z_Malloc ( sizeof ( * newf ) + strlen ( name ) ) ;
strcpy ( newf - > peer , name ) ;
2013-06-23 02:17:02 +00:00
newf - > conpending = true ;
2006-03-23 19:22:12 +00:00
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