hostlookup.c

Go to the documentation of this file.
00001 
00025 #include "iothread.h"
00026 #include "hostlookup.h"
00027 #include "text.h"
00028 #include <string.h>
00029 #ifndef NDEBUG
00030 #include <stdio.h>
00031 #endif
00032 #include <assert.h>
00033 #ifndef WIN32
00034 #include <sys/socket.h>
00035 #include <arpa/inet.h>
00036 #include <netdb.h>
00037 #include <unistd.h>
00038 #endif
00039 #include <SDL.h>
00040 
00046 static struct addrinfo *addrLookup = NULL;
00047 
00053 static char *lookupName = NULL;
00054 
00066 static int conditionCode = 0;
00067 
00073 static INetAddr hostaddr;
00074 
00075 char localhostName[MAX_HOST_LEN] = { 0 };
00076 
00077 char localhostAddrStr[INET6_ADDRSTRLEN] = { 0 };
00078 
00087 static void DoAddrLookup(void *name) {
00088     struct addrinfo hint;
00089     hint.ai_flags = AI_CANONNAME;
00090     hint.ai_family = 0; // AF_INET or AF_INET6
00091     hint.ai_socktype = SOCK_DGRAM;
00092     hint.ai_protocol = 0;
00093     hint.ai_addrlen = 0;
00094     hint.ai_addr = NULL;
00095     hint.ai_canonname = NULL;
00096     hint.ai_next = NULL;
00097     
00098     if (addrLookup) freeaddrinfo(addrLookup);
00099     conditionCode = getaddrinfo(name, NULL, &hint, &addrLookup);
00100 }
00101 
00109 static void DoNameLookup(void *address) {
00110     SocketAddr addr;
00111     assert(lookupName != NULL);
00112     if (address == NULL) {
00113         if (hostaddr.family == AF_INET6) {
00114             addr.ipv6.sin6_family = AF_INET6;
00115             addr.ipv6.sin6_addr = hostaddr.ipv6;
00116             addr.length = sizeof(struct sockaddr_in6);
00117         }
00118         else {
00119             addr.ipv4.sin_family = AF_INET;
00120             addr.ipv4.sin_addr = hostaddr.ipv4;
00121             addr.length = sizeof(struct sockaddr_in);
00122         }
00123         address = &addr;
00124     }
00125     if ((conditionCode = getnameinfo(&(((SocketAddr*)address)->addr),
00126     ((SocketAddr*)address)->length, lookupName, MAX_HOST_LEN, 0, 0, 0)) == 0) {
00127         // success; assure a null terminated string
00128         lookupName[MAX_HOST_LEN - 1] = 0;
00129     }
00130 }
00131 
00132 void StartAddrLookup(char *name) {
00133     // wait for another lookup to finish
00134     #ifndef NDEBUG
00135     /*
00136     if (conditionCode > 0) {
00137         printf("Waiting for previous lookup before working on %s\n", name);
00138     }
00139     */
00140     #endif
00141     while (conditionCode > 0) {
00142         SDL_Delay(1);
00143     }
00144     conditionCode = 1;
00145     QueueOperation(DoAddrLookup, name);
00146 }
00147 
00148 #ifdef WIN32
00149 int inet_pton(int fam, char *straddr, void *addr) {
00150     // check for valid family
00151     if (fam == AF_INET) {
00152         // convert the address
00153         if ((((struct in_addr*)addr)->s_addr = inet_addr(straddr)) != -1) {
00154             // success!
00155             return 1;
00156         }
00157         // bad address
00158         return 0;
00159     }
00160     // bad family -- no IPv6 support
00161     return -1;
00162 }
00163 #endif
00164 
00165 Bool StartStrNameLookup(char *addrstr, char *name) {
00166     // wait for another lookup to finish
00167     #ifndef NDEBUG
00168     /*
00169     if (conditionCode > 0) {
00170         printf("Waiting for previous lookup before working on %s\n", addrstr);
00171     }
00172     */
00173     #endif
00174     while (conditionCode > 0) {
00175         SDL_Delay(1);
00176     }
00177     // flag that the operation has not yet finished
00178     conditionCode = 1;
00179     // attempt to parse the string as a numeric address
00180     if ((inet_pton(hostaddr.family = AF_INET, addrstr, &hostaddr) > 0) ||
00181     (inet_pton(hostaddr.family = AF_INET6, addrstr, &hostaddr) > 0)) {
00182         // store the string where the hostname will be written
00183         lookupName = name;
00184         // start looking for the name
00185         QueueOperation(DoNameLookup, NULL);
00186         // success to this point
00187         return TRUE;
00188     }
00189     // bad address
00190     conditionCode = 0;
00191     return FALSE;
00192 }
00193 
00194 void StartNameLookup(SocketAddr *addr, char *name) {
00195     // wait for another lookup to finish
00196     #ifndef NDEBUG
00197     /*
00198     if (conditionCode > 0) {
00199         printf("Waiting for previous lookup before working on another\n");
00200     }
00201     */
00202     #endif
00203     while (conditionCode > 0) {
00204         SDL_Delay(1);
00205     }
00206     // flag that the operation has not yet finished
00207     conditionCode = 1;
00208     // store the string where the hostname will be written
00209     lookupName = name;
00210     // start looking for the name
00211     QueueOperation(DoNameLookup, addr);
00212 }
00213 
00214 int LookupResult(char *name, INetAddr *addr) {
00215     // see if a lookup is in progress
00216     if (conditionCode == 1) return 0;
00217     // check for an error
00218     if (conditionCode != 0) {
00219         // The gai_strerror() function is not availble for gcc linked programs
00220         // on Windows, although the function is implemented in Winsock.
00221         #ifndef NDEBUG
00222         if (addrLookup == NULL) {
00223             prnfile(stderr, strings[STRING_ERR_HOSTLOOK],
00224             gai_strerror(conditionCode));
00225         }
00226         #endif
00227         return -1;
00228     }
00229     // looking for a hostname
00230     if (addrLookup == NULL) {
00231         if (addr != NULL) {
00232             if ((addr->family = hostaddr.family) == AF_INET6) {
00233                 addr->ipv6 = hostaddr.ipv6;
00234             }
00235             else {
00236                 addr->ipv4 = hostaddr.ipv4;
00237             }
00238         }
00239     }
00240     // looking for an IP
00241     else {
00242         // request for a host name
00243         if (name != NULL) {
00244             // a name is present
00245             if (addrLookup->ai_canonname) {
00246                 // copy it over
00247                 strncpy(name, addrLookup->ai_canonname, MAX_HOST_LEN);
00248                 // assure null termination
00249                 name[MAX_HOST_LEN - 1] = 0;
00250             }
00251             else {
00252                 // no name is present; make it an empty string
00253                 name[0] = 0;
00254             }
00255         }
00256         // request for an address
00257         if (addr != NULL) {
00258             // check for the family of the result (IPv6?)
00259             if ((addr->family = addrLookup->ai_family) == AF_INET6) {
00260                 addr->ipv6 =
00261                 ((struct sockaddr_in6*)(addrLookup->ai_addr))->sin6_addr;
00262             }
00263             else {
00264                 addr->ipv4 =
00265                 ((struct sockaddr_in*)(addrLookup->ai_addr))->sin_addr;
00266             }
00267         }
00268         // remove the dynamically allocated data from getaddrinfo()
00269         freeaddrinfo(addrLookup);
00270         addrLookup = NULL;
00271     }
00272     conditionCode = 0;
00273     return 1;
00274 }
00275 
00276 void DoHostnameLookup(void *ignore) {
00277     conditionCode = 1;
00278     // find what the local system thinks it's called
00279     gethostname(localhostName, MAX_HOST_LEN);
00280     // assure null termination
00281     localhostName[MAX_HOST_LEN - 1] = 0;
00282     // start the process of finding a better name, if available
00283     DoAddrLookup(localhostName);
00284     // check for success and a name other than localhost
00285     if ((conditionCode++ == 0) && addrLookup->ai_canonname &&
00286     (strncmp("localhost", addrLookup->ai_canonname, MAX_HOST_LEN) != 0)) {
00287         // copy it over
00288         strncpy(localhostName, addrLookup->ai_canonname, MAX_HOST_LEN);
00289         // assure null termination
00290         localhostName[MAX_HOST_LEN - 1] = 0;
00291         // check for an address other than the loopback address
00292         if (((addrLookup->ai_family == AF_INET) &&
00293         (((struct sockaddr_in*)(addrLookup->ai_addr))->sin_addr.s_addr !=
00294         htonl(INADDR_LOOPBACK))) || ((addrLookup->ai_family == AF_INET6) &&
00295         !IN6_IS_ADDR_LOOPBACK(
00296         &(((struct sockaddr_in6*)(addrLookup->ai_addr))->sin6_addr)))) {
00297             // get a string containing the address for presentation to the user
00298             #ifdef WIN32
00299             // windows lacks the standard inet_ntop() function, so work
00300             char *addrstr;                                 // around it
00301             if ((addrstr = 
00302             inet_ntoa(((struct sockaddr_in*)(addrLookup->ai_addr))->sin_addr))
00303             != NULL) {
00304                 strcpy(localhostAddrStr, addrstr);
00305             }
00306             #else
00307             // convert the address to a string and test for success
00308             if (inet_ntop(addrLookup->ai_family,
00309             (addrLookup->ai_family == AF_INET) ?
00310             (void*)&((struct sockaddr_in*)(addrLookup->ai_addr))->sin_addr :
00311             (void*)&((struct sockaddr_in6*)(addrLookup->ai_addr))->sin6_addr,
00312             localhostAddrStr, sizeof(localhostAddrStr)) == NULL) {
00313                 // failed for some reason, so make sure the string is NULL
00314                 // terminated with zero length
00315                 localhostAddrStr[0] = 0;
00316             }
00317             #endif
00318         }
00319     }
00320     // get rid of the result from getaddrinfo()
00321     freeaddrinfo(addrLookup);
00322     addrLookup = NULL;
00323     // allow another lookup operation
00324     conditionCode = 0;
00325 }
00326 

Generated on Mon May 28 04:41:39 2007 for Retro Tank Super Attack by  doxygen 1.5.2