mirror of
https://github.com/id-Software/DOOM-iOS.git
synced 2026-03-20 00:49:34 +01:00
Source release for DOOM Classic for iOS version 2.1
This commit is contained in:
492
code/iphone/.svn/text-base/iphone_net.c.svn-base
Normal file
492
code/iphone/.svn/text-base/iphone_net.c.svn-base
Normal file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* iphone_net.c
|
||||
* doom
|
||||
*
|
||||
* Created by John Carmack on 7/8/09.
|
||||
* Copyright 2009 id Software. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Deal with all the DNS / bonjour service discovery and resolution
|
||||
|
||||
*/
|
||||
|
||||
#include "../doomiphone.h"
|
||||
|
||||
#include <dns_sd.h>
|
||||
#include <netdb.h> // for gethostbyname
|
||||
#include <net/if.h> // for if_nameindex()
|
||||
|
||||
DNSServiceRef browseRef;
|
||||
DNSServiceRef clientServiceRef;
|
||||
DNSServiceRef serviceRef;
|
||||
boolean serviceRefValid;
|
||||
|
||||
typedef struct {
|
||||
int interfaceIndex;
|
||||
char browseName[1024];
|
||||
char browseRegtype[1024];
|
||||
char browseDomain[1024];
|
||||
} service_t;
|
||||
|
||||
boolean localServer;
|
||||
|
||||
// we can find services on both WiFi and Bluetooth interfaces
|
||||
#define MAX_SERVICE_INTEFACES 4
|
||||
service_t serviceInterfaces[MAX_SERVICE_INTEFACES];
|
||||
|
||||
boolean gotServerAddress;
|
||||
struct sockaddr resolvedServerAddress;
|
||||
|
||||
static const char *serviceName = "_DoomServer._udp.";
|
||||
|
||||
void DNSServiceRegisterReplyCallback (
|
||||
DNSServiceRef sdRef,
|
||||
DNSServiceFlags flags,
|
||||
DNSServiceErrorType errorCode,
|
||||
const char *name,
|
||||
const char *regtype,
|
||||
const char *domain,
|
||||
void *context ) {
|
||||
if ( errorCode == kDNSServiceErr_NoError ) {
|
||||
localServer = true;
|
||||
} else {
|
||||
localServer = false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean RegisterGameService() {
|
||||
DNSServiceErrorType err = DNSServiceRegister(
|
||||
&serviceRef,
|
||||
kDNSServiceFlagsNoAutoRename, // we want a conflict error
|
||||
0, // all interfaces
|
||||
"iPhone Doom Classic",
|
||||
serviceName,
|
||||
NULL, // domain
|
||||
NULL, // host
|
||||
htons( DOOM_PORT ),
|
||||
0, // txtLen
|
||||
NULL, // txtRecord
|
||||
DNSServiceRegisterReplyCallback,
|
||||
NULL // context
|
||||
);
|
||||
|
||||
if ( err != kDNSServiceErr_NoError ) {
|
||||
printf( "DNSServiceRegister error\n" );
|
||||
} else {
|
||||
// block until we get a response, process it, and run the callback
|
||||
err = DNSServiceProcessResult( serviceRef );
|
||||
if ( err != kDNSServiceErr_NoError ) {
|
||||
printf( "DNSServiceProcessResult error\n" );
|
||||
}
|
||||
}
|
||||
return localServer;
|
||||
}
|
||||
|
||||
void TerminateGameService() {
|
||||
if ( localServer ) {
|
||||
localServer = false;
|
||||
}
|
||||
DNSServiceRefDeallocate( serviceRef );
|
||||
memset( serviceInterfaces, 0, sizeof( serviceInterfaces ) );
|
||||
}
|
||||
|
||||
void DNSServiceQueryRecordReplyCallback (
|
||||
DNSServiceRef DNSServiceRef,
|
||||
DNSServiceFlags flags,
|
||||
uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode,
|
||||
const char *fullname,
|
||||
uint16_t rrtype,
|
||||
uint16_t rrclass,
|
||||
uint16_t rdlen,
|
||||
const void *rdata,
|
||||
uint32_t ttl,
|
||||
void *context ) {
|
||||
assert( rdlen == 4 );
|
||||
const byte *ip = (const byte *)rdata;
|
||||
char interfaceName[IF_NAMESIZE];
|
||||
if_indextoname( interfaceIndex, interfaceName );
|
||||
printf( "DNSServiceQueryRecordReplyCallback: %s, interface[%i] = %s, [%i] = %i.%i.%i.%i\n",
|
||||
fullname, interfaceIndex, interfaceName, rdlen, ip[0], ip[1], ip[2], ip[3] );
|
||||
|
||||
ReportNetworkInterfaces();
|
||||
|
||||
memset( &resolvedServerAddress, 0, sizeof( resolvedServerAddress ) );
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)&resolvedServerAddress;
|
||||
sin->sin_len = sizeof( resolvedServerAddress );
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_port = htons( DOOM_PORT );
|
||||
memcpy( &sin->sin_addr, ip, 4 );
|
||||
|
||||
gotServerAddress = true;
|
||||
}
|
||||
|
||||
|
||||
DNSServiceFlags callbackFlags;
|
||||
|
||||
void DNSServiceResolveReplyCallback (
|
||||
DNSServiceRef sdRef,
|
||||
DNSServiceFlags flags,
|
||||
uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode,
|
||||
const char *fullname,
|
||||
const char *hosttarget,
|
||||
uint16_t port,
|
||||
uint16_t txtLen,
|
||||
const unsigned char *txtRecord,
|
||||
void *context ) {
|
||||
char interfaceName[IF_NAMESIZE];
|
||||
if_indextoname( interfaceIndex, interfaceName );
|
||||
printf( "Resolve: interfaceIndex [%i]=%s : %s @ %s\n", interfaceIndex, interfaceName, fullname, hosttarget );
|
||||
callbackFlags = flags;
|
||||
|
||||
#if 0
|
||||
struct hostent * host = gethostbyname( hosttarget );
|
||||
if ( host ) {
|
||||
printf( "h_name: %s\n", host->h_name );
|
||||
if ( host->h_aliases ) { // this can be NULL
|
||||
for ( char **list = host->h_aliases ; *list ; list++ ) {
|
||||
printf( "h_alias: %s\n", *list );
|
||||
}
|
||||
}
|
||||
printf( "h_addrtype: %i\n", host->h_addrtype );
|
||||
printf( "h_length: %i\n", host->h_length );
|
||||
if ( !host->h_addr_list ) { // I doubt this would ever be NULL...
|
||||
return;
|
||||
}
|
||||
for ( char **list = host->h_addr_list ; *list ; list++ ) {
|
||||
printf( "addr: %i.%i.%i.%i\n", ((byte *)*list)[0], ((byte *)*list)[1], ((byte *)*list)[2], ((byte *)*list)[3] );
|
||||
}
|
||||
|
||||
memset( &resolvedServerAddress, 0, sizeof( resolvedServerAddress ) );
|
||||
resolvedServerAddress.sin_len = sizeof( resolvedServerAddress );
|
||||
resolvedServerAddress.sin_family = host->h_addrtype;
|
||||
resolvedServerAddress.sin_port = htons( DOOM_PORT );
|
||||
assert( host->h_length == 4 );
|
||||
memcpy( &resolvedServerAddress.sin_addr, *host->h_addr_list, host->h_length );
|
||||
|
||||
gotServerAddress = true;
|
||||
}
|
||||
#else
|
||||
DNSServiceRef queryRef;
|
||||
|
||||
// look up the name for this host
|
||||
DNSServiceErrorType err = DNSServiceQueryRecord (
|
||||
&queryRef,
|
||||
kDNSServiceFlagsForceMulticast,
|
||||
interfaceIndex,
|
||||
hosttarget,
|
||||
kDNSServiceType_A, // we want the host address
|
||||
kDNSServiceClass_IN,
|
||||
DNSServiceQueryRecordReplyCallback,
|
||||
NULL /* may be NULL */
|
||||
);
|
||||
if ( err != kDNSServiceErr_NoError ) {
|
||||
printf( "DNSServiceQueryRecord error\n" );
|
||||
} else {
|
||||
// block until we get a response, process it, and run the callback
|
||||
err = DNSServiceProcessResult( queryRef );
|
||||
if ( err != kDNSServiceErr_NoError ) {
|
||||
printf( "DNSServiceProcessResult error\n" );
|
||||
}
|
||||
DNSServiceRefDeallocate( queryRef );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
boolean NetworkServerAvailable() {
|
||||
for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) {
|
||||
if ( serviceInterfaces[i].interfaceIndex != 0 ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns "WiFi", "BlueTooth", or "" for display on the
|
||||
// main menu multiplayer icon
|
||||
const char *NetworkServerTransport() {
|
||||
int count = 0;
|
||||
for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) {
|
||||
if ( serviceInterfaces[i].interfaceIndex != 0 ) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
static char str[1024];
|
||||
|
||||
str[0] = 0;
|
||||
for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) {
|
||||
int index = serviceInterfaces[i].interfaceIndex;
|
||||
if ( index == 0 ) {
|
||||
continue;
|
||||
}
|
||||
if ( str[0] ) {
|
||||
strcat( str, "+" );
|
||||
}
|
||||
if ( index == -1 ) {
|
||||
strcat( str, "BT-NEW" );
|
||||
} else if ( index == 1 ) {
|
||||
strcat( str, "LOOP" ); // we should never see this!
|
||||
} else if ( index == 2 ) {
|
||||
strcat( str, "WiFi" );
|
||||
} else {
|
||||
strcat( str, "BT-EST" );
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean ResolveNetworkServer( struct sockaddr *addr ) {
|
||||
if ( !NetworkServerAvailable() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gotServerAddress = false;
|
||||
|
||||
DNSServiceRef resolveRef;
|
||||
|
||||
// An unconnected bluetooth service will report an interfaceIndex of -1, so if
|
||||
// we have a wifi link with an interfaceIndex > 0, use that
|
||||
// explicitly.
|
||||
service_t *service = NULL;
|
||||
for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) {
|
||||
if ( serviceInterfaces[i].interfaceIndex > 0 ) {
|
||||
service = &serviceInterfaces[i];
|
||||
char interfaceName[IF_NAMESIZE];
|
||||
if_indextoname( service->interfaceIndex, interfaceName );
|
||||
printf( "explicitly using resolving server on interface %i = %s\n", service->interfaceIndex, interfaceName );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !service ) {
|
||||
// settle for the unconnected bluetooth service
|
||||
for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) {
|
||||
if ( serviceInterfaces[i].interfaceIndex != 0 ) {
|
||||
service = &serviceInterfaces[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !service ) {
|
||||
printf( "No serviceInterface current.\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// look up the name for this service
|
||||
|
||||
DNSServiceErrorType err = DNSServiceResolve (
|
||||
&resolveRef,
|
||||
kDNSServiceFlagsForceMulticast, // always on local link
|
||||
service->interfaceIndex > 0 ? service->interfaceIndex : 0, // don't use -1 for bluetooth
|
||||
service->browseName,
|
||||
service->browseRegtype,
|
||||
service->browseDomain,
|
||||
DNSServiceResolveReplyCallback,
|
||||
NULL /* context */
|
||||
);
|
||||
|
||||
if ( err != kDNSServiceErr_NoError ) {
|
||||
printf( "DNSServiceResolve error\n" );
|
||||
} else {
|
||||
// We can get two callbacks when both wifi and bluetooth are enabled
|
||||
callbackFlags = 0;
|
||||
do {
|
||||
err = DNSServiceProcessResult( resolveRef );
|
||||
if ( err != kDNSServiceErr_NoError ) {
|
||||
printf( "DNSServiceProcessResult error\n" );
|
||||
}
|
||||
} while ( callbackFlags & kDNSServiceFlagsMoreComing );
|
||||
DNSServiceRefDeallocate( resolveRef );
|
||||
}
|
||||
|
||||
if ( gotServerAddress ) {
|
||||
*addr = resolvedServerAddress;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void DNSServiceBrowseReplyCallback(
|
||||
DNSServiceRef sdRef,
|
||||
DNSServiceFlags flags,
|
||||
uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode,
|
||||
const char *serviceName,
|
||||
const char *regtype,
|
||||
const char *replyDomain,
|
||||
void *context ) {
|
||||
printf( "DNSServiceBrowseReplyCallback %s: interface:%i name:%s regtype:%s domain:%s\n",
|
||||
(flags & kDNSServiceFlagsAdd) ? "ADD" : "REMOVE",
|
||||
interfaceIndex, serviceName, regtype, replyDomain );
|
||||
if ( flags & kDNSServiceFlagsAdd ) {
|
||||
// add it to the list
|
||||
if ( interfaceIndex == 1 ) {
|
||||
printf( "Not adding service on loopback interface.\n" );
|
||||
} else {
|
||||
for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) {
|
||||
service_t *service = &serviceInterfaces[i];
|
||||
if ( service->interfaceIndex == 0 ) {
|
||||
strncpy( service->browseName, serviceName, sizeof( service->browseName ) -1 );
|
||||
strncpy( service->browseRegtype, regtype, sizeof( service->browseRegtype ) -1 );
|
||||
strncpy( service->browseDomain, replyDomain, sizeof( service->browseDomain ) -1 );
|
||||
service->interfaceIndex = interfaceIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// remove it from the list
|
||||
for ( int i = 0 ; i < MAX_SERVICE_INTEFACES ; i++ ) {
|
||||
if ( serviceInterfaces[i].interfaceIndex == interfaceIndex ) {
|
||||
serviceInterfaces[i].interfaceIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessDNSMessages() {
|
||||
static boolean initialized;
|
||||
|
||||
if ( !initialized ) {
|
||||
initialized = true;
|
||||
DNSServiceErrorType err = DNSServiceBrowse (
|
||||
&browseRef,
|
||||
0, /* flags */
|
||||
0, /* interface */
|
||||
serviceName,
|
||||
NULL, /* domain */
|
||||
DNSServiceBrowseReplyCallback,
|
||||
NULL /* context */
|
||||
);
|
||||
if ( err != kDNSServiceErr_NoError ) {
|
||||
printf( "DNSServiceBrowse error\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// poll the socket for updates
|
||||
int socket = DNSServiceRefSockFD( browseRef );
|
||||
if ( socket <= 0 ) {
|
||||
return;
|
||||
}
|
||||
fd_set set;
|
||||
FD_ZERO( &set );
|
||||
FD_SET( socket, &set );
|
||||
|
||||
struct timeval tv;
|
||||
memset( &tv, 0, sizeof( tv ) );
|
||||
if ( select( socket+1, &set, NULL, NULL, &tv ) > 0 ) {
|
||||
DNSServiceProcessResult( browseRef );
|
||||
}
|
||||
}
|
||||
|
||||
void ReportNetworkInterfaces() {
|
||||
struct ifaddrs *ifap;
|
||||
printf( "getifaddrs():\n" );
|
||||
if ( getifaddrs( &ifap ) == -1 ) {
|
||||
perror( "getifaddrs(): " );
|
||||
} else {
|
||||
for ( struct ifaddrs *ifa = ifap ; ifa ; ifa = ifa->ifa_next ) {
|
||||
struct sockaddr_in *ina = (struct sockaddr_in *)ifa->ifa_addr;
|
||||
if ( ina->sin_family == AF_INET ) {
|
||||
byte *ip = (byte *)&ina->sin_addr;
|
||||
// struct ifa_data *data = (struct ifa_data *)ifa->ifa_data;
|
||||
|
||||
printf( "ifa_name: %s ifa_flags: %i sa_family: %i=AF_INET ip: %i.%i.%i.%i\n", ifa->ifa_name, ifa->ifa_flags,
|
||||
ina->sin_family, ip[0], ip[1], ip[2], ip[3] );
|
||||
} else if ( ina->sin_family == AF_LINK ) {
|
||||
struct if_data *data = (struct if_data *)ifa->ifa_data;
|
||||
printf( "ifa_name: %s ifa_flags: %i sa_family: %i=AF_LINK ifi_ipackets: %i\n", ifa->ifa_name, ifa->ifa_flags,
|
||||
ina->sin_family, data->ifi_ipackets );
|
||||
} else {
|
||||
printf( "ifa_name: %s ifa_flags: %i sa_family: %i=???\n", ifa->ifa_name, ifa->ifa_flags,
|
||||
ina->sin_family );
|
||||
}
|
||||
}
|
||||
freeifaddrs( ifap );
|
||||
}
|
||||
|
||||
printf( "if_nameindex():\n" );
|
||||
struct if_nameindex *ifnames = if_nameindex();
|
||||
if ( !ifnames ) {
|
||||
perror( "if_ameindex():" );
|
||||
} else {
|
||||
for ( int i = 0 ; ifnames[i].if_index != 0 ; i++ ) {
|
||||
printf( "%i : %s\n", ifnames[i].if_index, ifnames[i].if_name );
|
||||
}
|
||||
if_freenameindex( ifnames );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int InterfaceIndexForAddress( struct sockaddr_in *adr ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in AddressForInterfaceIndex( int interfaceIndex ) {
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_len = sizeof( addr );
|
||||
addr.sin_family = AF_INET;
|
||||
|
||||
if ( interfaceIndex == 0 ) {
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
int UDPSocket( int interfaceIndex, int portnum ) {
|
||||
int udpSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||
if ( udpSocket == -1 ) {
|
||||
Com_Printf( "UDP socket failed: %s\n", strerror( errno ) );
|
||||
return -1;
|
||||
}
|
||||
struct sockaddr_in addr = AddressForInterfaceIndex( interfaceIndex );
|
||||
addr.sin_port = htons( portnum );
|
||||
|
||||
if ( bind( udpSocket, (struct sockaddr *)&addr, sizeof( addr ) ) == -1 ) {
|
||||
Com_Printf( "UDP bind failed: %s\n", strerror( errno ) );
|
||||
close( udpSocket );
|
||||
return -1;
|
||||
}
|
||||
#if 0
|
||||
// enable broadcast
|
||||
int on = 1;
|
||||
if ( setsockopt( udpSocket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on) ) == -1 ) {
|
||||
Com_Printf( "UDP setsockopt failed: %s\n", strerror( errno ) );
|
||||
close( udpSocket );
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// set the type-of-service, in hopes that the link level drivers use it
|
||||
// to stop buffering huge amounts of data when there are line errors
|
||||
int tos = 0x10; /* IPTOS_LOWDELAY; */ /* see <netinet/in.h> */
|
||||
if ( setsockopt( udpSocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos) ) == -1 ) {
|
||||
Com_Printf( "setsockopt IP_TOS failed: %s\n", strerror( errno ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
// enable non-blocking IO
|
||||
if ( fcntl( udpSocket, F_SETFL, O_NONBLOCK ) == -1 ) {
|
||||
Com_Printf( "UDP fcntl failed: %s\n", strerror( errno ) );
|
||||
close( udpSocket );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return udpSocket;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user