CfgUSBLoader/source/dns.c
2015-01-17 10:11:08 +00:00

132 lines
3.1 KiB
C

#include "dns.h"
#include "gettext.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)
{
u32 ip;
// check if it's already in numeric form
ip = inet_addr(domain);
if (ip != (u32)-1) return ip;
//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;
}
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(gt("Configuration error, MAX_DNS_ENTRIES reached while the list is empty"));
printf("\n");
exit(1);
} else if(previousnode == NULL)
{
firstdnsentry = NULL;
} else {
previousnode->nextnode = NULL;
}
free(node->domain);
free(node);
dnsentrycount--;
}
return newnode->ip;
}