/*
===========================================================================
Wolfenstein: Enemy Territory GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Wolfenstein: Enemy Territory GPL Source Code (Wolf ET Source Code).
Wolf ET Source Code 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 3 of the License, or
(at your option) any later version.
Wolf ET Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Wolf ET Source Code. If not, see .
In addition, the Wolf: ET Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Wolf ET Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include
Q3DEF_BEGIN
#include "../client/client.h"
#include "mac_local.h"
Q3DEF_END
/*
#ifndef DEDICATED
#include "GameRanger SDK/GameRanger.h"
#endif
*/
static qboolean gOTInited;
static EndpointRef endpoint = kOTInvalidEndpointRef;
#define MAX_IPS 16
static int num_interfaces = 0;
static InetInterfaceInfo sys_inetInfo[MAX_IPS];
static byte localIP[MAX_IPS][4];
InetSvcRef inet_services;
static TUDErr uderr;
OTClientContextPtr clientContext = NULL;
void RcvUDErr( EndpointRef inEndpoint ) {
memset( &uderr, 0, sizeof( uderr ) );
uderr.addr.maxlen = 0;
uderr.opt.maxlen = 0;
OTRcvUDErr( inEndpoint, &uderr );
}
void HandleOTError( int err, const char *func, EndpointRef inEndpoint ) {
int r;
static int lastErr;
if ( err != lastErr ) {
Com_Printf( "%s: error %i\n", func, err );
}
// if we don't call OTLook, things wedge
r = OTLook( inEndpoint );
if ( err != lastErr ) {
Com_DPrintf( "%s: OTLook %i\n", func, r );
}
switch ( r )
{
case T_UDERR:
RcvUDErr( inEndpoint );
if ( err != lastErr ) {
Com_DPrintf( "%s: OTRcvUDErr %i\n", func, uderr.error );
}
break;
default:
// Com_Printf( "%s: Unknown OTLook error %i\n", func, r );
break;
}
lastErr = err; // don't spew tons of messages
}
/*
=================
NotifyProc
=================
*/
pascal void NotifyProc( void* contextPtr, OTEventCode code,
OTResult result, void* cookie ) {
switch ( code )
{
case T_OPENCOMPLETE:
endpoint = (EndpointRef) cookie;
break;
case T_UDERR:
RcvUDErr( (EndpointRef)cookie );
break;
}
}
/*
=================
GetFourByteOption
=================
*/
static OTResult GetFourByteOption( EndpointRef ep,
OTXTILevel level,
OTXTIName name,
UInt32 *value ) {
OTResult err;
TOption option;
TOptMgmt request;
TOptMgmt result;
/* Set up the option buffer */
option.len = kOTFourByteOptionSize;
option.level = level;
option.name = name;
option.status = 0;
option.value[0] = 0; // Ignored because we're getting the value.
/* Set up the request parameter for OTOptionManagement to point
to the option buffer we just filled out */
request.opt.buf = (UInt8 *) &option;
request.opt.len = sizeof( option );
request.flags = T_CURRENT;
/* Set up the reply parameter for OTOptionManagement. */
result.opt.buf = (UInt8 *) &option;
result.opt.maxlen = sizeof( option );
err = OTOptionManagement( ep, &request, &result );
if ( err == noErr ) {
switch ( option.status )
{
case T_SUCCESS:
case T_READONLY:
*value = option.value[0];
break;
default:
err = option.status;
break;
}
}
return ( err );
}
/*
=================
SetFourByteOption
=================
*/
static OTResult SetFourByteOption( EndpointRef ep,
OTXTILevel level,
OTXTIName name,
UInt32 value ) {
OTResult err;
TOption option;
TOptMgmt request;
TOptMgmt result;
/* Set up the option buffer to specify the option and value to set. */
option.len = kOTFourByteOptionSize;
option.level = level;
option.name = name;
option.status = 0;
option.value[0] = value;
/* Set up request parameter for OTOptionManagement */
request.opt.buf = (UInt8 *) &option;
request.opt.len = sizeof( option );
request.flags = T_NEGOTIATE;
/* Set up reply parameter for OTOptionManagement. */
result.opt.buf = (UInt8 *) &option;
result.opt.maxlen = sizeof( option );
err = OTOptionManagement( ep, &request, &result );
if ( err == noErr ) {
if ( option.status != T_SUCCESS ) {
err = option.status;
}
}
return ( err );
}
/*
==================
Sys_ShowIP
==================
*/
void Sys_ShowIP( void ) {
int i;
for ( i = 0; i < num_interfaces; i++ ) {
Com_Printf( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] );
}
}
/*
=====================
NET_GetLocalAddress
=====================
*/
void NET_GetLocalAddress( void ) {
OSStatus err;
int iOT;
InetInterfaceInfo inetInfo;
num_interfaces = 0;
iOT = 0;
while ( true ) {
err = OTInetGetInterfaceInfo( &inetInfo, iOT );
if ( err ) {
break;
}
if ( inetInfo.fAddress != 0 ) {
sys_inetInfo[num_interfaces] = inetInfo;
UInt32 IP = ntohl( inetInfo.fAddress );
localIP[num_interfaces][0] = ( (byte*)&IP )[0];
localIP[num_interfaces][1] = ( (byte*)&IP )[1];
localIP[num_interfaces][2] = ( (byte*)&IP )[2];
localIP[num_interfaces][3] = ( (byte*)&IP )[3];
Com_Printf( "LocalAddress: %i.%i.%i.%i\n",
localIP[ num_interfaces ][0],
localIP[ num_interfaces ][1],
localIP[ num_interfaces ][2],
localIP[ num_interfaces ][3] );
UInt32 netmask = ntohl( inetInfo.fNetmask );
Com_Printf( "Netmask: %i.%i.%i.%i\n",
( (byte*)&netmask )[0],
( (byte*)&netmask )[1],
( (byte*)&netmask )[2],
( (byte*)&netmask )[3] );
num_interfaces++;
}
iOT++;
}
}
/*
==================
Sys_InitNetworking
struct InetAddress
{
OTAddressType fAddressType; // always AF_INET
InetPort fPort; // Port number
InetHost fHost; // Host address in net byte order
UInt8 fUnused[8]; // Traditional unused bytes
};
typedef struct InetAddress InetAddress;
==================
*/
void Sys_InitNetworking( void ) {
cvar_t *ip;
int port;
OSStatus err;
OTConfigurationRef config;
TBind bind, bindOut;
InetAddress in, out;
int i;
ip = Cvar_Get( "net_ip", "localhost", CVAR_LATCH );
port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH )->integer;
Com_Printf( "----- Sys_InitNetworking -----\n" );
// init OpenTransport
Com_Printf( "... InitOpenTransport()\n" );
if ( (Ptr) kUnresolvedCFragSymbolAddress == (Ptr) InitOpenTransportInContext ) {
Com_Error( ERR_FATAL, "OpenTransport extensions not installed" );
return;
}
err = InitOpenTransportInContext( kInitOTForApplicationMask, NULL /*&clientContext*/ );
if ( err != noErr ) {
Com_Printf( "InitOpenTransport() failed\n" );
Com_Printf( "------------------------------\n" );
return;
}
gOTInited = qtrue;
// get an endpoint
Com_Printf( "... OTOpenEndpoint()\n" );
config = OTCreateConfiguration( kUDPName );
endpoint = OTOpenEndpointInContext( config, 0, NULL, &err, NULL );
if ( err != noErr ) {
endpoint = 0;
Com_Printf( "OTOpenEndpoint() failed\n" );
Com_Printf( "------------------------------\n" );
return;
}
// set non-blocking
err = OTSetNonBlocking( endpoint );
// scan for a valid port in our range
Com_Printf( "... OTBind()\n" );
for ( i = 0 ; i < 10 ; i++ )
{
in.fAddressType = AF_INET;
in.fPort = port + i;
in.fHost = 0;
bind.addr.maxlen = sizeof( in );
bind.addr.len = sizeof( in );
bind.addr.buf = (unsigned char *)∈
bind.qlen = 0;
bindOut.addr.maxlen = sizeof( out );
bindOut.addr.len = sizeof( out );
bindOut.addr.buf = (unsigned char *)&out;
bindOut.qlen = 0;
err = OTBind( endpoint, &bind, &bindOut );
if ( err == noErr ) {
Com_Printf( "Opened UDP endpoint at port %i\n",
out.fPort );
break;
}
}
if ( err != noErr ) {
Com_Printf( "Couldn't bind a local port\n" );
}
// get the local address for LAN client detection
NET_GetLocalAddress();
// set to allow broadcasts
err = SetFourByteOption( endpoint, INET_IP, kIP_BROADCAST, T_YES );
if ( err != noErr ) {
Com_Printf( "IP_BROADCAST failed\n" );
}
inet_services = OTOpenInternetServicesInContext( kDefaultInternetServicesPath, 0, &err, NULL );
/*
#ifndef DEDICATED
if (GRIsHostCmd())
GRHostReady();
#endif
*/
Com_Printf( "------------------------------\n" );
}
/*
==================
Sys_ShutdownNetworking
==================
*/
void Sys_ShutdownNetworking( void ) {
Com_Printf( "Sys_ShutdownNetworking();\n" );
/*
#ifndef DEDICATED
if (GRIsHostCmd())
GRHostClosed();
#endif
*/
if ( endpoint != kOTInvalidEndpointRef ) {
OTUnbind( endpoint );
OTCloseProvider( endpoint );
endpoint = kOTInvalidEndpointRef;
}
if ( inet_services ) {
OTCloseProvider( inet_services );
}
if ( gOTInited ) {
CloseOpenTransportInContext( NULL );
gOTInited = qfalse;
}
}
/*
====================
NET_Shutdown
====================
*/
void NET_Shutdown( void ) {
}
/*
=============
Sys_StringToAdr
Does NOT parse port numbers
=============
*/
qboolean Sys_StringToAdr( const char *s, netadr_t *a ) {
OSStatus err;
InetHostInfo info;
err = OTInetStringToAddress( inet_services, (char *)s, &info );
if ( err ) {
char name[256];
Com_DPrintf( "Sys_StringToAdr addr failed: %s\n", s );
return qfalse;
}
a->type = NA_IP;
*(int *)a->ip = ntohl( info.addrs[0] );
a->port = 0;
return qtrue;
}
/*
==================
Sys_SendPacket
==================
*/
#define MAX_PACKETLEN 1400
void Sys_SendPacket( int length, const void *data, netadr_t to ) {
TUnitData d;
InetAddress inAddr;
OSStatus err;
if ( !endpoint ) {
return;
}
if ( length > MAX_PACKETLEN ) {
Com_Error( ERR_DROP, "Sys_SendPacket: length > MAX_PACKETLEN" );
}
inAddr.fAddressType = AF_INET;
// netadr_t holds port in network order
// ?but it seems we have to give it in host order here?
inAddr.fPort = ntohs( to.port );
if ( to.type == NA_BROADCAST ) {
inAddr.fHost = -1;
} else {
inAddr.fHost = htonl( *(int*)&to.ip );
}
memset( &d, 0, sizeof( d ) );
d.addr.len = sizeof( inAddr );
d.addr.maxlen = sizeof( inAddr );
d.addr.buf = (unsigned char *)&inAddr;
d.opt.len = 0;
d.opt.maxlen = 0;
d.opt.buf = NULL;
d.udata.len = length;
d.udata.maxlen = length;
d.udata.buf = (unsigned char *)data;
err = OTSndUData( endpoint, &d );
if ( err ) {
HandleOTError( err, "Sys_SendPacket", endpoint );
}
}
/*
==================
Sys_GetPacket
Never called by the game logic, just the system event queing
==================
*/
qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
TUnitData d;
InetAddress inAddr;
OSStatus err;
OTFlags flags;
if ( !endpoint ) {
return qfalse;
}
inAddr.fAddressType = AF_INET;
inAddr.fPort = 0;
inAddr.fHost = 0;
memset( &d, 0, sizeof( d ) );
d.addr.len = sizeof( inAddr );
d.addr.maxlen = sizeof( inAddr );
d.addr.buf = (unsigned char *)&inAddr;
d.opt.len = 0;
d.opt.maxlen = 0;
d.opt.buf = 0;
d.udata.len = net_message->maxsize;
d.udata.maxlen = net_message->maxsize;
d.udata.buf = net_message->data;
err = OTRcvUData( endpoint, &d, &flags );
if ( err ) {
if ( err == kOTNoDataErr ) {
return qfalse;
}
HandleOTError( err, "Sys_GetPacket", endpoint );
return qfalse;
}
net_from->type = NA_IP;
// the game wants them in network order, for some reason we're getting them in host order
net_from->port = htons( inAddr.fPort );
*(int *)net_from->ip = ntohl( inAddr.fHost );
net_message->cursize = d.udata.len;
return qtrue;
}
/*
==================
Sys_IsLANAddress
LAN clients will have their rate var ignored
==================
*/
qboolean Sys_IsLANAddress( netadr_t adr ) {
int i;
if ( adr.type == NA_LOOPBACK ) {
return qtrue;
}
if ( adr.type == NA_IPX ) {
return qtrue;
}
if ( adr.type != NA_IP ) {
return qfalse;
}
//bani
if ( num_interfaces ) {
unsigned long *p_ip;
unsigned long ip;
p_ip = (unsigned long *)&adr.ip[0];
ip = htonl( *p_ip );
for ( i = 0; i < num_interfaces; i++ ) {
if ( ( sys_inetInfo[i].fAddress & sys_inetInfo[i].fNetmask ) == ( ip & sys_inetInfo[i].fNetmask ) ) {
return qtrue;
}
}
return qfalse;
}
// choose which comparison to use based on the class of the address being tested
// any local adresses of a different class than the address being tested will fail based on the first byte
if ( adr.ip[0] == 127 && adr.ip[1] == 0 && adr.ip[2] == 0 && adr.ip[3] == 1 ) {
return qtrue;
}
// Class A
if ( ( adr.ip[0] & 0x80 ) == 0x00 ) {
for ( i = 0 ; i < num_interfaces ; i++ ) {
if ( adr.ip[0] == localIP[i][0] ) {
return qtrue;
}
}
// the RFC1918 class a block will pass the above test
return qfalse;
}
// Class B
if ( ( adr.ip[0] & 0xc0 ) == 0x80 ) {
for ( i = 0 ; i < num_interfaces ; i++ ) {
if ( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) {
return qtrue;
}
// also check against the RFC1918 class b blocks
if ( adr.ip[0] == 172 && localIP[i][0] == 172 && ( adr.ip[1] & 0xf0 ) == 16 && ( localIP[i][1] & 0xf0 ) == 16 ) {
return qtrue;
}
}
return qfalse;
}
// Class C
for ( i = 0 ; i < num_interfaces ; i++ ) {
if ( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) {
return qtrue;
}
// also check against the RFC1918 class c blocks
if ( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) {
return qtrue;
}
}
return qfalse;
}
void NET_Init( void ) {
}
void NET_Sleep( int i ) {
}
extern "C" int WSACleanup( void ) {
return 0;
}