#include "dns.h" /** * Resolves a domainname to an ip address * It makes use of net_gethostbyname from libogc, which in turn makes use of a Wii BIOS function * Just like the net_gethostbyname function this function is NOT threadsafe! * * @param char* The domain name to resolve * @return u32 The ipaddress represented by four bytes inside an u32 (in network order) */ u32 getipbyname( char *domain ) { //Care should be taken when using net_gethostbyname, //it returns a static buffer which makes it not threadsafe //TODO: implement some locking mechanism to make below code atomic struct hostent *host = net_gethostbyname( domain ); if ( host == NULL ) { return 0; } u32 *ip = ( u32* )host->h_addr_list[0]; return *ip; } //Defines how many DNS entries should be cached by getipbynamecached() #define MAX_DNS_CACHE_ENTRIES 20 //The cache is defined as a linked list, //The last resolved domain name will always be at the front //This will allow heavily used domainnames to always stay cached struct dnsentry { char *domain; u32 ip; struct dnsentry *nextnode; } ; static struct dnsentry *firstdnsentry = NULL; static int dnsentrycount = 0; /** * Performs the same function as getipbyname(), * except that it will prevent extremely expensive net_gethostbyname() calls by caching the result */ u32 getipbynamecached( char *domain ) { //Search if this domainname is already cached struct dnsentry *node = firstdnsentry; struct dnsentry *previousnode = NULL; while ( node != NULL ) { if ( strcmp( node->domain, domain ) == 0 ) { //DNS node found in the cache, move it to the front of the list if ( previousnode != NULL ) previousnode->nextnode = node->nextnode; if ( node != firstdnsentry ) node->nextnode = firstdnsentry; firstdnsentry = node; return node->ip; } //Go to the next element in the list previousnode = node; node = node->nextnode; } u32 ip = getipbyname( domain ); //No cache of this domain could be found, create a cache node and add it to the front of the cache struct dnsentry *newnode = malloc( sizeof( struct dnsentry ) ); if ( newnode == NULL ) { return ip; } newnode->ip = ip; newnode->domain = malloc( strlen( domain ) + 1 ); if ( newnode->domain == NULL ) { free( newnode ); return ip; } strcpy( newnode->domain, domain ); newnode->nextnode = firstdnsentry; firstdnsentry = newnode; dnsentrycount++; //If the cache grows too big delete the last (and probably least important) node of the list if ( dnsentrycount > MAX_DNS_CACHE_ENTRIES ) { struct dnsentry *node = firstdnsentry; struct dnsentry *previousnode = NULL; //Fetch the last two elements of the list while ( node->nextnode != NULL ) { previousnode = node; node = node->nextnode; } if ( node == NULL ) { printf( "Configuration error, MAX_DNS_ENTRIES reached while the list is empty\n" ); exit( 1 ); } else if ( previousnode == NULL ) { firstdnsentry = NULL; } else { previousnode->nextnode = NULL; } free( node->domain ); free( node ); dnsentrycount--; } return newnode->ip; }