Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

unix_net.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // unix_net.c
00023 
00024 #include "../game/q_shared.h"
00025 #include "../qcommon/qcommon.h"
00026 
00027 #include <unistd.h>
00028 #include <sys/socket.h>
00029 #include <sys/time.h>
00030 #include <netinet/in.h>
00031 #include <netdb.h>
00032 #include <arpa/inet.h> // bk001204
00033 
00034 #include <sys/param.h>
00035 #include <sys/ioctl.h>
00036 #include <sys/uio.h>
00037 #include <errno.h>
00038 
00039 #ifdef MACOS_X
00040 #import <sys/sockio.h>
00041 #import <net/if.h>
00042 #import <net/if_types.h>
00043 
00044 #import <arpa/inet.h>         // for inet_ntoa()
00045 #import <net/if_dl.h>         // for 'struct sockaddr_dl'
00046 #endif
00047 
00048 static cvar_t   *noudp;
00049 
00050 netadr_t    net_local_adr;
00051 
00052 int         ip_socket;
00053 int         ipx_socket;
00054 
00055 #define MAX_IPS     16
00056 static  int     numIP;
00057 static  byte    localIP[MAX_IPS][4];
00058 
00059 int NET_Socket (char *net_interface, int port);
00060 char *NET_ErrorString (void);
00061 
00062 //=============================================================================
00063 
00064 void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
00065 {
00066     memset (s, 0, sizeof(*s));
00067 
00068     if (a->type == NA_BROADCAST)
00069     {
00070         s->sin_family = AF_INET;
00071 
00072         s->sin_port = a->port;
00073         *(int *)&s->sin_addr = -1;
00074     }
00075     else if (a->type == NA_IP)
00076     {
00077         s->sin_family = AF_INET;
00078 
00079         *(int *)&s->sin_addr = *(int *)&a->ip;
00080         s->sin_port = a->port;
00081     }
00082 }
00083 
00084 void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
00085 {
00086     *(int *)&a->ip = *(int *)&s->sin_addr;
00087     a->port = s->sin_port;
00088     a->type = NA_IP;
00089 }
00090 
00091 char    *NET_BaseAdrToString (netadr_t a)
00092 {
00093     static  char    s[64];
00094     
00095     Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
00096 
00097     return s;
00098 }
00099 
00100 /*
00101 =============
00102 Sys_StringToAdr
00103 
00104 idnewt
00105 192.246.40.70
00106 =============
00107 */
00108 qboolean    Sys_StringToSockaddr (const char *s, struct sockaddr *sadr)
00109 {
00110     struct hostent  *h;
00111     //char  *colon; // bk001204 - unused
00112     
00113     memset (sadr, 0, sizeof(*sadr));
00114     ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
00115     
00116     ((struct sockaddr_in *)sadr)->sin_port = 0;
00117     
00118     if ( s[0] >= '0' && s[0] <= '9')
00119     {
00120         *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s);
00121     }
00122     else
00123     {
00124         if (! (h = gethostbyname(s)) )
00125             return qfalse;
00126         *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
00127     }
00128     
00129     return qtrue;
00130 }
00131 
00132 /*
00133 =============
00134 Sys_StringToAdr
00135 
00136 localhost
00137 idnewt
00138 idnewt:28000
00139 192.246.40.70
00140 192.246.40.70:28000
00141 =============
00142 */
00143 qboolean    Sys_StringToAdr (const char *s, netadr_t *a)
00144 {
00145     struct sockaddr_in sadr;
00146     
00147     if (!Sys_StringToSockaddr (s, (struct sockaddr *)&sadr))
00148         return qfalse;
00149     
00150     SockadrToNetadr (&sadr, a);
00151 
00152     return qtrue;
00153 }
00154 
00155 
00156 //=============================================================================
00157 
00158 qboolean    Sys_GetPacket (netadr_t *net_from, msg_t *net_message)
00159 {
00160     int     ret;
00161     struct sockaddr_in  from;
00162     int     fromlen;
00163     int     net_socket;
00164     int     protocol;
00165     int     err;
00166 
00167     for (protocol = 0 ; protocol < 2 ; protocol++)
00168     {
00169         if (protocol == 0)
00170             net_socket = ip_socket;
00171         else
00172             net_socket = ipx_socket;
00173 
00174         if (!net_socket)
00175             continue;
00176 
00177         fromlen = sizeof(from);
00178         ret = recvfrom (net_socket, net_message->data, net_message->maxsize
00179             , 0, (struct sockaddr *)&from, &fromlen);
00180 
00181         SockadrToNetadr (&from, net_from);
00182         // bk000305: was missing
00183         net_message->readcount = 0;
00184 
00185         if (ret == -1)
00186         {
00187             err = errno;
00188 
00189             if (err == EWOULDBLOCK || err == ECONNREFUSED)
00190                 continue;
00191             Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(),
00192                         NET_AdrToString(*net_from));
00193             continue;
00194         }
00195 
00196         if (ret == net_message->maxsize)
00197         {
00198             Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
00199             continue;
00200         }
00201 
00202         net_message->cursize = ret;
00203         return qtrue;
00204     }
00205 
00206     return qfalse;
00207 }
00208 
00209 //=============================================================================
00210 
00211 void    Sys_SendPacket( int length, const void *data, netadr_t to )
00212 {
00213     int     ret;
00214     struct sockaddr_in  addr;
00215     int     net_socket;
00216 
00217     if (to.type == NA_BROADCAST)
00218     {
00219         net_socket = ip_socket;
00220     }
00221     else if (to.type == NA_IP)
00222     {
00223         net_socket = ip_socket;
00224     }
00225     else if (to.type == NA_IPX)
00226     {
00227         net_socket = ipx_socket;
00228     }
00229     else if (to.type == NA_BROADCAST_IPX)
00230     {
00231         net_socket = ipx_socket;
00232     }
00233     else {
00234         Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
00235         return;
00236     }
00237 
00238     if (!net_socket)
00239         return;
00240 
00241     NetadrToSockadr (&to, &addr);
00242 
00243     ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
00244     if (ret == -1)
00245     {
00246         Com_Printf ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(),
00247                 NET_AdrToString (to));
00248     }
00249 }
00250 
00251 
00252 //=============================================================================
00253 
00254 /*
00255 ==================
00256 Sys_IsLANAddress
00257 
00258 LAN clients will have their rate var ignored
00259 ==================
00260 */
00261 qboolean    Sys_IsLANAddress (netadr_t adr) {
00262     int     i;
00263 
00264     if( adr.type == NA_LOOPBACK ) {
00265         return qtrue;
00266     }
00267 
00268     if( adr.type == NA_IPX ) {
00269         return qtrue;
00270     }
00271 
00272     if( adr.type != NA_IP ) {
00273         return qfalse;
00274     }
00275 
00276     // choose which comparison to use based on the class of the address being tested
00277     // any local adresses of a different class than the address being tested will fail based on the first byte
00278 
00279     // Class A
00280     if( (adr.ip[0] & 0x80) == 0x00 ) {
00281         for ( i = 0 ; i < numIP ; i++ ) {
00282             if( adr.ip[0] == localIP[i][0] ) {
00283                 return qtrue;
00284             }
00285         }
00286         // the RFC1918 class a block will pass the above test
00287         return qfalse;
00288     }
00289 
00290     // Class B
00291     if( (adr.ip[0] & 0xc0) == 0x80 ) {
00292         for ( i = 0 ; i < numIP ; i++ ) {
00293             if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) {
00294                 return qtrue;
00295             }
00296             // also check against the RFC1918 class b blocks
00297             if( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 ) {
00298                 return qtrue;
00299             }
00300         }
00301         return qfalse;
00302     }
00303 
00304     // Class C
00305     for ( i = 0 ; i < numIP ; i++ ) {
00306         if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) {
00307             return qtrue;
00308         }
00309         // also check against the RFC1918 class c blocks
00310         if( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) {
00311             return qtrue;
00312         }
00313     }
00314     return qfalse;
00315 }
00316 
00317 /*
00318 ==================
00319 Sys_ShowIP
00320 ==================
00321 */
00322 void Sys_ShowIP(void) {
00323     int i;
00324 
00325     for (i = 0; i < numIP; i++) {
00326         Com_Printf( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] );
00327     }
00328 }
00329 
00330 /*
00331 =====================
00332 NET_GetLocalAddress
00333 =====================
00334 */
00335 #ifdef MACOS_X
00336 // 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.
00337 // This code adapted from OmniNetworking.
00338 
00339 #define IFR_NEXT(ifr)   \
00340     ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \
00341       MAX(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr))))
00342 
00343 void NET_GetLocalAddress( void ) {
00344         struct ifreq requestBuffer[MAX_IPS], *linkInterface, *inetInterface;
00345         struct ifconf ifc;
00346         struct ifreq ifr;
00347         struct sockaddr_dl *sdl;
00348         int interfaceSocket;
00349         int family;
00350         
00351         //Com_Printf("NET_GetLocalAddress: Querying for network interfaces\n");
00352         
00353         // Set this early so we can just return if there is an error
00354     numIP = 0;
00355         
00356         ifc.ifc_len = sizeof(requestBuffer);
00357         ifc.ifc_buf = (caddr_t)requestBuffer;
00358 
00359         // 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.
00360         family = AF_INET;
00361         if ((interfaceSocket = socket(family, SOCK_DGRAM, 0)) < 0) {
00362             Com_Printf("NET_GetLocalAddress: Unable to create temporary socket, errno = %d\n", errno);
00363             return;
00364         }
00365 
00366         if (ioctl(interfaceSocket, SIOCGIFCONF, &ifc) != 0) {
00367             Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces, errno = %d\n", errno);
00368             return;
00369         }
00370 
00371 
00372         linkInterface = (struct ifreq *) ifc.ifc_buf;
00373         while ((char *) linkInterface < &ifc.ifc_buf[ifc.ifc_len]) {
00374             unsigned int nameLength;
00375 
00376             // 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.
00377 
00378             // For each AF_LINK entry...
00379             if (linkInterface->ifr_addr.sa_family == AF_LINK) {
00380                 // if there is a matching AF_INET entry
00381                 inetInterface = (struct ifreq *) ifc.ifc_buf;
00382                 while ((char *) inetInterface < &ifc.ifc_buf[ifc.ifc_len]) {
00383                     if (inetInterface->ifr_addr.sa_family == AF_INET &&
00384                         !strncmp(inetInterface->ifr_name, linkInterface->ifr_name, sizeof(linkInterface->ifr_name))) {
00385 
00386                         for (nameLength = 0; nameLength < IFNAMSIZ; nameLength++)
00387                             if (!linkInterface->ifr_name[nameLength])
00388                                 break;
00389 
00390                         sdl = (struct sockaddr_dl *)&linkInterface->ifr_addr;
00391                         // Skip loopback interfaces
00392                         if (sdl->sdl_type != IFT_LOOP) {
00393                             // Get the local interface address
00394                             strncpy(ifr.ifr_name, inetInterface->ifr_name, sizeof(ifr.ifr_name));
00395                             if (ioctl(interfaceSocket, OSIOCGIFADDR, (caddr_t)&ifr) < 0) {
00396                                 Com_Printf("NET_GetLocalAddress: Unable to get local address for interface '%s', errno = %d\n", inetInterface->ifr_name, errno);
00397                             } else {
00398                                 struct sockaddr_in *sin;
00399                                 int ip;
00400             
00401                                 sin = (struct sockaddr_in *)&ifr.ifr_addr;
00402             
00403                                 ip = ntohl(sin->sin_addr.s_addr);
00404                                 localIP[ numIP ][0] = (ip >> 24) & 0xff;
00405                                 localIP[ numIP ][1] = (ip >> 16) & 0xff;
00406                                 localIP[ numIP ][2] = (ip >>  8) & 0xff;
00407                                 localIP[ numIP ][3] = (ip >>  0) & 0xff;
00408                                 Com_Printf( "IP: %i.%i.%i.%i (%s)\n", localIP[ numIP ][0], localIP[ numIP ][1], localIP[ numIP ][2], localIP[ numIP ][3], inetInterface->ifr_name);
00409                                 numIP++;
00410                             }
00411                         }
00412 
00413                         // We will assume that there is only one AF_INET entry per AF_LINK entry.
00414                         // What happens when we have an interface that has multiple IP addresses, or
00415                         // can that even happen?
00416                         // break;
00417                     }
00418                     inetInterface = IFR_NEXT(inetInterface);
00419                 }
00420             }
00421             linkInterface = IFR_NEXT(linkInterface);
00422         }
00423 
00424         close(interfaceSocket);
00425 }
00426 
00427 #else
00428 void NET_GetLocalAddress( void ) {
00429     char                hostname[256];
00430     struct hostent      *hostInfo;
00431     // int                  error; // bk001204 - unused
00432     char                *p;
00433     int                 ip;
00434     int                 n;
00435 
00436     if ( gethostname( hostname, 256 ) == -1 ) {
00437         return;
00438     }
00439 
00440     hostInfo = gethostbyname( hostname );
00441     if ( !hostInfo ) {
00442         return;
00443     }
00444 
00445     Com_Printf( "Hostname: %s\n", hostInfo->h_name );
00446     n = 0;
00447     while( ( p = hostInfo->h_aliases[n++] ) != NULL ) {
00448         Com_Printf( "Alias: %s\n", p );
00449     }
00450 
00451     if ( hostInfo->h_addrtype != AF_INET ) {
00452         return;
00453     }
00454 
00455     numIP = 0;
00456     while( ( p = hostInfo->h_addr_list[numIP++] ) != NULL && numIP < MAX_IPS ) {
00457         ip = ntohl( *(int *)p );
00458         localIP[ numIP ][0] = p[0];
00459         localIP[ numIP ][1] = p[1];
00460         localIP[ numIP ][2] = p[2];
00461         localIP[ numIP ][3] = p[3];
00462         Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff );
00463     }
00464 }
00465 #endif
00466 
00467 /*
00468 ====================
00469 NET_OpenIP
00470 ====================
00471 */
00472 // bk001204 - prototype needed
00473 int NET_IPSocket (char *net_interface, int port);
00474 void NET_OpenIP (void)
00475 {
00476     cvar_t  *ip;
00477     int     port;
00478     int     i;
00479 
00480     ip = Cvar_Get ("net_ip", "localhost", 0);
00481 
00482     port = Cvar_Get("net_port", va("%i", PORT_SERVER), 0)->value;
00483 
00484     for ( i = 0 ; i < 10 ; i++ ) {
00485         ip_socket = NET_IPSocket (ip->string, port + i);
00486         if ( ip_socket ) {
00487             Cvar_SetValue( "net_port", port + i );
00488             NET_GetLocalAddress();
00489             return;
00490         }
00491     }
00492     Com_Error (ERR_FATAL, "Couldn't allocate IP port");
00493 }
00494 
00495 
00496 /*
00497 ====================
00498 NET_Init
00499 ====================
00500 */
00501 void NET_Init (void)
00502 {
00503     noudp = Cvar_Get ("net_noudp", "0", 0);
00504     // open sockets
00505     if (! noudp->value) {
00506         NET_OpenIP ();
00507     }
00508 }
00509 
00510 
00511 /*
00512 ====================
00513 NET_IPSocket
00514 ====================
00515 */
00516 int NET_IPSocket (char *net_interface, int port)
00517 {
00518     int newsocket;
00519     struct sockaddr_in address;
00520     qboolean _qtrue = qtrue;
00521     int i = 1;
00522 
00523     if ( net_interface ) {
00524         Com_Printf("Opening IP socket: %s:%i\n", net_interface, port );
00525     } else {
00526         Com_Printf("Opening IP socket: localhost:%i\n", port );
00527     }
00528 
00529     if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
00530     {
00531         Com_Printf ("ERROR: UDP_OpenSocket: socket: %s", NET_ErrorString());
00532         return 0;
00533     }
00534 
00535     // make it non-blocking
00536     if (ioctl (newsocket, FIONBIO, &_qtrue) == -1)
00537     {
00538         Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
00539         return 0;
00540     }
00541 
00542     // make it broadcast capable
00543     if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
00544     {
00545         Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
00546         return 0;
00547     }
00548 
00549     if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost"))
00550         address.sin_addr.s_addr = INADDR_ANY;
00551     else
00552         Sys_StringToSockaddr (net_interface, (struct sockaddr *)&address);
00553 
00554     if (port == PORT_ANY)
00555         address.sin_port = 0;
00556     else
00557         address.sin_port = htons((short)port);
00558 
00559     address.sin_family = AF_INET;
00560 
00561     if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
00562     {
00563         Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
00564         close (newsocket);
00565         return 0;
00566     }
00567 
00568     return newsocket;
00569 }
00570 
00571 /*
00572 ====================
00573 NET_Shutdown
00574 ====================
00575 */
00576 void    NET_Shutdown (void)
00577 {
00578     if (ip_socket) {
00579         close(ip_socket);
00580         ip_socket = 0;
00581     }
00582 }
00583 
00584 
00585 /*
00586 ====================
00587 NET_ErrorString
00588 ====================
00589 */
00590 char *NET_ErrorString (void)
00591 {
00592     int     code;
00593 
00594     code = errno;
00595     return strerror (code);
00596 }
00597 
00598 // sleeps msec or until net socket is ready
00599 void NET_Sleep(int msec)
00600 {
00601     struct timeval timeout;
00602     fd_set  fdset;
00603     extern qboolean stdin_active;
00604 
00605     if (!ip_socket || !com_dedicated->integer)
00606         return; // we're not a server, just run full speed
00607 
00608     FD_ZERO(&fdset);
00609     if (stdin_active)
00610         FD_SET(0, &fdset); // stdin is processed too
00611     FD_SET(ip_socket, &fdset); // network socket
00612     timeout.tv_sec = msec/1000;
00613     timeout.tv_usec = (msec%1000)*1000;
00614     select(ip_socket+1, &fdset, NULL, NULL, &timeout);
00615 }
00616 

Generated on Thu Aug 25 12:38:04 2005 for Quake III Arena by  doxygen 1.3.9.1