tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore.  All rights reserved. */
/* hostname.c,v 2.11 1996/12/23 22:15:19 dmoore Exp */
#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "db.h"
#include "buffer.h"
#include "hostname.h"
#include "params.h"
#include "externs.h"

/* Number of seconds to add to delay each time a consecutive name server
   failure occurs. */
#define TIME_TO_DELAY 300
#define MAX_TIME_TO_DELAY 900

struct host_info {
    ip_addr_t ip_address;	/* Actually address. */
    const char *name;		/* Hostname for address. */
};


/* last_checked is only used if a lookup for a given host doesn't complete.
   The host won't be attempted to be looked up again for timeout seconds. */
static time_t last_checked;
static int timeout = 0;
static hash_tab *hostname_table = NULL; /* Table mapping addresses to names. */
static int hosts_loaded = 0;	/* 0 if need to reload from file. */


static unsigned long hash_host_entry(const void *entry)
{
    return ((const struct host_info *) entry)->ip_address;
}


static int compare_host_entries(const void *entry1, const void *entry2)
{
    const struct host_info *host1 = entry1;
    const struct host_info *host2 = entry2;

    return ((host1->ip_address) != (host2->ip_address));
}


static void delete_host_entry(void *entry)
{
    struct host_info *host = entry;
    
    if (!host) return;

    if (host->name) FREE_STRING(host->name);
    FREE(host);
}


const char *lookup_host(ip_addr_t addr, int try_nameservice)
{
    struct host_info match;
    struct host_info *result;
    struct hostent *he;
    time_t now;
    static Buffer buf;

#ifndef HOSTNAMES
    try_nameservice = HOSTNAME_NO_RESOLVE;
#endif

    if (!hosts_loaded)
	init_hostnames();

    match.ip_address = addr;

    result = find_hash_entry(hostname_table, &match);
    if (result) {
	/* Found a solution. */
	return result->name;
    }

    /* No entry stored in table.  If hostname resolution is desired, then
       try that now. */

    if (try_nameservice) {
	/* Check that enough time has elasped since last lookup.  In case
	   the nameserver appears to be down. */

	now = time(NULL);
	if (difftime(now, last_checked) > timeout) {
	    last_checked = now;
	    timeout += TIME_TO_DELAY;
	    if (timeout > MAX_TIME_TO_DELAY)
		timeout = MAX_TIME_TO_DELAY;

	    /* Hmm, if there is no name for a given address we
	       treat it as a failure, but there might just not
	       be a name for it.  Look into checking herror. */
	    
	    he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
	    if (he && he->h_name) {
		/* Looked up successfully, store it in the table, and return
		   the result. */
	    
		MALLOC(result, struct host_info, 1);
		result->ip_address = addr;
		result->name = ALLOC_STRING(he->h_name);
		
		add_hash_entry(hostname_table, result);
	    
		timeout = 0;
		return result->name;
	    }
	}
    }

    /* Here if lookup failed any place above. */
    addr = ntohl(addr);
    Bufsprint(&buf, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
            (addr >> 8) & 0xff, addr & 0xff);
    return Buftext(&buf);
    
}


void init_hostnames(void)
{
    last_checked = time(NULL);
    timeout = 0;

    if (!hostname_table) {
	hostname_table = init_hash_table("Hostname table",
					 compare_host_entries,
					 hash_host_entry,
					 delete_host_entry,
					 HOST_HASH_SIZE);
    }

    hosts_loaded = 1;

    {
	/* Stick in sdnp1/2 for now. :) */
	struct host_info *temp;
	
	MALLOC(temp, struct host_info, 1);
	temp->ip_address = htonl(2230281190UL);
	temp->name = ALLOC_STRING("OJ's.machine");
	add_hash_entry(hostname_table, temp);
	
	MALLOC(temp, struct host_info, 1);
	temp->ip_address = htonl(2230275850UL);
	temp->name = ALLOC_STRING("OJ's.machine");
	add_hash_entry(hostname_table, temp);
    }

}


void clear_hostnames(void)
{
    clear_hash_table(hostname_table);
    hostname_table = NULL;
    hosts_loaded = 0;
}