Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

unix_net.c (16044B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // unix_net.c
     23 
     24 #include "../game/q_shared.h"
     25 #include "../qcommon/qcommon.h"
     26 
     27 #include <unistd.h>
     28 #include <sys/socket.h>
     29 #include <sys/time.h>
     30 #include <netinet/in.h>
     31 #include <netdb.h>
     32 #include <arpa/inet.h> // bk001204
     33 
     34 #include <sys/param.h>
     35 #include <sys/ioctl.h>
     36 #include <sys/uio.h>
     37 #include <errno.h>
     38 
     39 #ifdef MACOS_X
     40 #import <sys/sockio.h>
     41 #import <net/if.h>
     42 #import <net/if_types.h>
     43 
     44 #import <arpa/inet.h>         // for inet_ntoa()
     45 #import <net/if_dl.h>         // for 'struct sockaddr_dl'
     46 #endif
     47 
     48 static cvar_t	*noudp;
     49 
     50 netadr_t	net_local_adr;
     51 
     52 int			ip_socket;
     53 int			ipx_socket;
     54 
     55 #define	MAX_IPS		16
     56 static	int		numIP;
     57 static	byte	localIP[MAX_IPS][4];
     58 
     59 int NET_Socket (char *net_interface, int port);
     60 char *NET_ErrorString (void);
     61 
     62 //=============================================================================
     63 
     64 void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
     65 {
     66 	memset (s, 0, sizeof(*s));
     67 
     68 	if (a->type == NA_BROADCAST)
     69 	{
     70 		s->sin_family = AF_INET;
     71 
     72 		s->sin_port = a->port;
     73 		*(int *)&s->sin_addr = -1;
     74 	}
     75 	else if (a->type == NA_IP)
     76 	{
     77 		s->sin_family = AF_INET;
     78 
     79 		*(int *)&s->sin_addr = *(int *)&a->ip;
     80 		s->sin_port = a->port;
     81 	}
     82 }
     83 
     84 void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
     85 {
     86 	*(int *)&a->ip = *(int *)&s->sin_addr;
     87 	a->port = s->sin_port;
     88 	a->type = NA_IP;
     89 }
     90 
     91 char	*NET_BaseAdrToString (netadr_t a)
     92 {
     93 	static	char	s[64];
     94 	
     95 	Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
     96 
     97 	return s;
     98 }
     99 
    100 /*
    101 =============
    102 Sys_StringToAdr
    103 
    104 idnewt
    105 192.246.40.70
    106 =============
    107 */
    108 qboolean	Sys_StringToSockaddr (const char *s, struct sockaddr *sadr)
    109 {
    110 	struct hostent	*h;
    111 	//char	*colon; // bk001204 - unused
    112 	
    113 	memset (sadr, 0, sizeof(*sadr));
    114 	((struct sockaddr_in *)sadr)->sin_family = AF_INET;
    115 	
    116 	((struct sockaddr_in *)sadr)->sin_port = 0;
    117 	
    118 	if ( s[0] >= '0' && s[0] <= '9')
    119 	{
    120 		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s);
    121 	}
    122 	else
    123 	{
    124 		if (! (h = gethostbyname(s)) )
    125 			return qfalse;
    126 		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
    127 	}
    128 	
    129 	return qtrue;
    130 }
    131 
    132 /*
    133 =============
    134 Sys_StringToAdr
    135 
    136 localhost
    137 idnewt
    138 idnewt:28000
    139 192.246.40.70
    140 192.246.40.70:28000
    141 =============
    142 */
    143 qboolean	Sys_StringToAdr (const char *s, netadr_t *a)
    144 {
    145 	struct sockaddr_in sadr;
    146 	
    147 	if (!Sys_StringToSockaddr (s, (struct sockaddr *)&sadr))
    148 		return qfalse;
    149 	
    150 	SockadrToNetadr (&sadr, a);
    151 
    152 	return qtrue;
    153 }
    154 
    155 
    156 //=============================================================================
    157 
    158 qboolean	Sys_GetPacket (netadr_t *net_from, msg_t *net_message)
    159 {
    160 	int 	ret;
    161 	struct sockaddr_in	from;
    162 	int		fromlen;
    163 	int		net_socket;
    164 	int		protocol;
    165 	int		err;
    166 
    167 	for (protocol = 0 ; protocol < 2 ; protocol++)
    168 	{
    169 		if (protocol == 0)
    170 			net_socket = ip_socket;
    171 		else
    172 			net_socket = ipx_socket;
    173 
    174 		if (!net_socket)
    175 			continue;
    176 
    177 		fromlen = sizeof(from);
    178 		ret = recvfrom (net_socket, net_message->data, net_message->maxsize
    179 			, 0, (struct sockaddr *)&from, &fromlen);
    180 
    181 		SockadrToNetadr (&from, net_from);
    182 		// bk000305: was missing
    183 		net_message->readcount = 0;
    184 
    185 		if (ret == -1)
    186 		{
    187 			err = errno;
    188 
    189 			if (err == EWOULDBLOCK || err == ECONNREFUSED)
    190 				continue;
    191 			Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(),
    192 						NET_AdrToString(*net_from));
    193 			continue;
    194 		}
    195 
    196 		if (ret == net_message->maxsize)
    197 		{
    198 			Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
    199 			continue;
    200 		}
    201 
    202 		net_message->cursize = ret;
    203 		return qtrue;
    204 	}
    205 
    206 	return qfalse;
    207 }
    208 
    209 //=============================================================================
    210 
    211 void	Sys_SendPacket( int length, const void *data, netadr_t to )
    212 {
    213 	int		ret;
    214 	struct sockaddr_in	addr;
    215 	int		net_socket;
    216 
    217 	if (to.type == NA_BROADCAST)
    218 	{
    219 		net_socket = ip_socket;
    220 	}
    221 	else if (to.type == NA_IP)
    222 	{
    223 		net_socket = ip_socket;
    224 	}
    225 	else if (to.type == NA_IPX)
    226 	{
    227 		net_socket = ipx_socket;
    228 	}
    229 	else if (to.type == NA_BROADCAST_IPX)
    230 	{
    231 		net_socket = ipx_socket;
    232 	}
    233 	else {
    234 		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
    235 		return;
    236 	}
    237 
    238 	if (!net_socket)
    239 		return;
    240 
    241 	NetadrToSockadr (&to, &addr);
    242 
    243 	ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
    244 	if (ret == -1)
    245 	{
    246 		Com_Printf ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(),
    247 				NET_AdrToString (to));
    248 	}
    249 }
    250 
    251 
    252 //=============================================================================
    253 
    254 /*
    255 ==================
    256 Sys_IsLANAddress
    257 
    258 LAN clients will have their rate var ignored
    259 ==================
    260 */
    261 qboolean	Sys_IsLANAddress (netadr_t adr) {
    262 	int		i;
    263 
    264 	if( adr.type == NA_LOOPBACK ) {
    265 		return qtrue;
    266 	}
    267 
    268 	if( adr.type == NA_IPX ) {
    269 		return qtrue;
    270 	}
    271 
    272 	if( adr.type != NA_IP ) {
    273 		return qfalse;
    274 	}
    275 
    276 	// choose which comparison to use based on the class of the address being tested
    277 	// any local adresses of a different class than the address being tested will fail based on the first byte
    278 
    279 	// Class A
    280 	if( (adr.ip[0] & 0x80) == 0x00 ) {
    281 		for ( i = 0 ; i < numIP ; i++ ) {
    282 			if( adr.ip[0] == localIP[i][0] ) {
    283 				return qtrue;
    284 			}
    285 		}
    286 		// the RFC1918 class a block will pass the above test
    287 		return qfalse;
    288 	}
    289 
    290 	// Class B
    291 	if( (adr.ip[0] & 0xc0) == 0x80 ) {
    292 		for ( i = 0 ; i < numIP ; i++ ) {
    293 			if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) {
    294 				return qtrue;
    295 			}
    296 			// also check against the RFC1918 class b blocks
    297 			if( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 ) {
    298 				return qtrue;
    299 			}
    300 		}
    301 		return qfalse;
    302 	}
    303 
    304 	// Class C
    305 	for ( i = 0 ; i < numIP ; i++ ) {
    306 		if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) {
    307 			return qtrue;
    308 		}
    309 		// also check against the RFC1918 class c blocks
    310 		if( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) {
    311 			return qtrue;
    312 		}
    313 	}
    314 	return qfalse;
    315 }
    316 
    317 /*
    318 ==================
    319 Sys_ShowIP
    320 ==================
    321 */
    322 void Sys_ShowIP(void) {
    323 	int i;
    324 
    325 	for (i = 0; i < numIP; i++) {
    326 		Com_Printf( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] );
    327 	}
    328 }
    329 
    330 /*
    331 =====================
    332 NET_GetLocalAddress
    333 =====================
    334 */
    335 #ifdef MACOS_X
    336 // Don't do a forward mapping from the hostname of the machine to the IP.  The reason is that we might have obtained an IP address from DHCP and there might not be any name registered for the machine.  On Mac OS X, the machine name defaults to 'localhost' and NetInfo has 127.0.0.1 listed for this name.  Instead, we want to get a list of all the IP network interfaces on the machine.
    337 // This code adapted from OmniNetworking.
    338 
    339 #define IFR_NEXT(ifr)	\
    340     ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \
    341       MAX(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr))))
    342 
    343 void NET_GetLocalAddress( void ) {
    344         struct ifreq requestBuffer[MAX_IPS], *linkInterface, *inetInterface;
    345         struct ifconf ifc;
    346         struct ifreq ifr;
    347         struct sockaddr_dl *sdl;
    348         int interfaceSocket;
    349         int family;
    350         
    351         //Com_Printf("NET_GetLocalAddress: Querying for network interfaces\n");
    352         
    353         // Set this early so we can just return if there is an error
    354 	numIP = 0;
    355         
    356         ifc.ifc_len = sizeof(requestBuffer);
    357         ifc.ifc_buf = (caddr_t)requestBuffer;
    358 
    359         // Since we get at this info via an ioctl, we need a temporary little socket.  This will only get AF_INET interfaces, but we probably don't care about anything else.  If we do end up caring later, we should add a ONAddressFamily and at a -interfaces method to it.
    360         family = AF_INET;
    361         if ((interfaceSocket = socket(family, SOCK_DGRAM, 0)) < 0) {
    362             Com_Printf("NET_GetLocalAddress: Unable to create temporary socket, errno = %d\n", errno);
    363             return;
    364         }
    365 
    366         if (ioctl(interfaceSocket, SIOCGIFCONF, &ifc) != 0) {
    367             Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces, errno = %d\n", errno);
    368             return;
    369         }
    370 
    371 
    372         linkInterface = (struct ifreq *) ifc.ifc_buf;
    373         while ((char *) linkInterface < &ifc.ifc_buf[ifc.ifc_len]) {
    374             unsigned int nameLength;
    375 
    376             // The ioctl returns both the entries having the address (AF_INET) and the link layer entries (AF_LINK).  The AF_LINK entry has the link layer address which contains the interface type.  This is the only way I can see to get this information.  We cannot assume that we will get bot an AF_LINK and AF_INET entry since the interface may not be configured.  For example, if you have a 10Mb port on the motherboard and a 100Mb card, you may not configure the motherboard port.
    377 
    378             // For each AF_LINK entry...
    379             if (linkInterface->ifr_addr.sa_family == AF_LINK) {
    380                 // if there is a matching AF_INET entry
    381                 inetInterface = (struct ifreq *) ifc.ifc_buf;
    382                 while ((char *) inetInterface < &ifc.ifc_buf[ifc.ifc_len]) {
    383                     if (inetInterface->ifr_addr.sa_family == AF_INET &&
    384                         !strncmp(inetInterface->ifr_name, linkInterface->ifr_name, sizeof(linkInterface->ifr_name))) {
    385 
    386                         for (nameLength = 0; nameLength < IFNAMSIZ; nameLength++)
    387                             if (!linkInterface->ifr_name[nameLength])
    388                                 break;
    389 
    390                         sdl = (struct sockaddr_dl *)&linkInterface->ifr_addr;
    391                         // Skip loopback interfaces
    392                         if (sdl->sdl_type != IFT_LOOP) {
    393                             // Get the local interface address
    394                             strncpy(ifr.ifr_name, inetInterface->ifr_name, sizeof(ifr.ifr_name));
    395                             if (ioctl(interfaceSocket, OSIOCGIFADDR, (caddr_t)&ifr) < 0) {
    396                                 Com_Printf("NET_GetLocalAddress: Unable to get local address for interface '%s', errno = %d\n", inetInterface->ifr_name, errno);
    397                             } else {
    398                                 struct sockaddr_in *sin;
    399                                 int ip;
    400             
    401                                 sin = (struct sockaddr_in *)&ifr.ifr_addr;
    402             
    403                                 ip = ntohl(sin->sin_addr.s_addr);
    404                                 localIP[ numIP ][0] = (ip >> 24) & 0xff;
    405                                 localIP[ numIP ][1] = (ip >> 16) & 0xff;
    406                                 localIP[ numIP ][2] = (ip >>  8) & 0xff;
    407                                 localIP[ numIP ][3] = (ip >>  0) & 0xff;
    408                                 Com_Printf( "IP: %i.%i.%i.%i (%s)\n", localIP[ numIP ][0], localIP[ numIP ][1], localIP[ numIP ][2], localIP[ numIP ][3], inetInterface->ifr_name);
    409                                 numIP++;
    410                             }
    411                         }
    412 
    413                         // We will assume that there is only one AF_INET entry per AF_LINK entry.
    414                         // What happens when we have an interface that has multiple IP addresses, or
    415                         // can that even happen?
    416                         // break;
    417                     }
    418                     inetInterface = IFR_NEXT(inetInterface);
    419                 }
    420             }
    421             linkInterface = IFR_NEXT(linkInterface);
    422         }
    423 
    424         close(interfaceSocket);
    425 }
    426 
    427 #else
    428 void NET_GetLocalAddress( void ) {
    429 	char				hostname[256];
    430 	struct hostent		*hostInfo;
    431 	// int					error; // bk001204 - unused
    432 	char				*p;
    433 	int					ip;
    434 	int					n;
    435 
    436 	if ( gethostname( hostname, 256 ) == -1 ) {
    437 		return;
    438 	}
    439 
    440 	hostInfo = gethostbyname( hostname );
    441 	if ( !hostInfo ) {
    442 		return;
    443 	}
    444 
    445 	Com_Printf( "Hostname: %s\n", hostInfo->h_name );
    446 	n = 0;
    447 	while( ( p = hostInfo->h_aliases[n++] ) != NULL ) {
    448 		Com_Printf( "Alias: %s\n", p );
    449 	}
    450 
    451 	if ( hostInfo->h_addrtype != AF_INET ) {
    452 		return;
    453 	}
    454 
    455 	numIP = 0;
    456 	while( ( p = hostInfo->h_addr_list[numIP++] ) != NULL && numIP < MAX_IPS ) {
    457 		ip = ntohl( *(int *)p );
    458 		localIP[ numIP ][0] = p[0];
    459 		localIP[ numIP ][1] = p[1];
    460 		localIP[ numIP ][2] = p[2];
    461 		localIP[ numIP ][3] = p[3];
    462 		Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff );
    463 	}
    464 }
    465 #endif
    466 
    467 /*
    468 ====================
    469 NET_OpenIP
    470 ====================
    471 */
    472 // bk001204 - prototype needed
    473 int NET_IPSocket (char *net_interface, int port);
    474 void NET_OpenIP (void)
    475 {
    476 	cvar_t	*ip;
    477 	int		port;
    478 	int		i;
    479 
    480 	ip = Cvar_Get ("net_ip", "localhost", 0);
    481 
    482 	port = Cvar_Get("net_port", va("%i", PORT_SERVER), 0)->value;
    483 
    484 	for ( i = 0 ; i < 10 ; i++ ) {
    485 		ip_socket = NET_IPSocket (ip->string, port + i);
    486 		if ( ip_socket ) {
    487 			Cvar_SetValue( "net_port", port + i );
    488 			NET_GetLocalAddress();
    489 			return;
    490 		}
    491 	}
    492 	Com_Error (ERR_FATAL, "Couldn't allocate IP port");
    493 }
    494 
    495 
    496 /*
    497 ====================
    498 NET_Init
    499 ====================
    500 */
    501 void NET_Init (void)
    502 {
    503 	noudp = Cvar_Get ("net_noudp", "0", 0);
    504 	// open sockets
    505 	if (! noudp->value) {
    506 		NET_OpenIP ();
    507 	}
    508 }
    509 
    510 
    511 /*
    512 ====================
    513 NET_IPSocket
    514 ====================
    515 */
    516 int NET_IPSocket (char *net_interface, int port)
    517 {
    518 	int newsocket;
    519 	struct sockaddr_in address;
    520 	qboolean _qtrue = qtrue;
    521 	int	i = 1;
    522 
    523 	if ( net_interface ) {
    524 		Com_Printf("Opening IP socket: %s:%i\n", net_interface, port );
    525 	} else {
    526 		Com_Printf("Opening IP socket: localhost:%i\n", port );
    527 	}
    528 
    529 	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    530 	{
    531 		Com_Printf ("ERROR: UDP_OpenSocket: socket: %s", NET_ErrorString());
    532 		return 0;
    533 	}
    534 
    535 	// make it non-blocking
    536 	if (ioctl (newsocket, FIONBIO, &_qtrue) == -1)
    537 	{
    538 		Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
    539 		return 0;
    540 	}
    541 
    542 	// make it broadcast capable
    543 	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
    544 	{
    545 		Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
    546 		return 0;
    547 	}
    548 
    549 	if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost"))
    550 		address.sin_addr.s_addr = INADDR_ANY;
    551 	else
    552 		Sys_StringToSockaddr (net_interface, (struct sockaddr *)&address);
    553 
    554 	if (port == PORT_ANY)
    555 		address.sin_port = 0;
    556 	else
    557 		address.sin_port = htons((short)port);
    558 
    559 	address.sin_family = AF_INET;
    560 
    561 	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
    562 	{
    563 		Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
    564 		close (newsocket);
    565 		return 0;
    566 	}
    567 
    568 	return newsocket;
    569 }
    570 
    571 /*
    572 ====================
    573 NET_Shutdown
    574 ====================
    575 */
    576 void	NET_Shutdown (void)
    577 {
    578 	if (ip_socket) {
    579 		close(ip_socket);
    580 		ip_socket = 0;
    581 	}
    582 }
    583 
    584 
    585 /*
    586 ====================
    587 NET_ErrorString
    588 ====================
    589 */
    590 char *NET_ErrorString (void)
    591 {
    592 	int		code;
    593 
    594 	code = errno;
    595 	return strerror (code);
    596 }
    597 
    598 // sleeps msec or until net socket is ready
    599 void NET_Sleep(int msec)
    600 {
    601     struct timeval timeout;
    602 	fd_set	fdset;
    603 	extern qboolean stdin_active;
    604 
    605 	if (!ip_socket || !com_dedicated->integer)
    606 		return; // we're not a server, just run full speed
    607 
    608 	FD_ZERO(&fdset);
    609 	if (stdin_active)
    610 		FD_SET(0, &fdset); // stdin is processed too
    611 	FD_SET(ip_socket, &fdset); // network socket
    612 	timeout.tv_sec = msec/1000;
    613 	timeout.tv_usec = (msec%1000)*1000;
    614 	select(ip_socket+1, &fdset, NULL, NULL, &timeout);
    615 }
    616