usbloadergx/source/network/dns.c

129 lines
3.4 KiB
C
Raw Normal View History

#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;
}