mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-13 23:15:09 +01:00
123 lines
3.0 KiB
C
123 lines
3.0 KiB
C
|
#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;
|
||
|
}
|