#include "dns.h" #include "utils.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) { SAFE_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; } SAFE_FREE(node->domain); SAFE_FREE(node); dnsentrycount--; } return newnode->ip; }