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