btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * dnschild.c
 *
 * Copyright (c) 2004,2005 Martin Murray <mmurray@monkey.org>
 * All rights reserved.
 *
 */

#include "copyright.h"
#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include "externs.h"
#include "debug.h"

static struct dns_query_state_t {
	DESC *desc;
	struct event ev;
	struct dns_query_state_t *next;
	int pid;
	int fd;
} *running = NULL;

static int running_queries = 0;
static int dnschild_state = 0;

static struct timeval query_timeout = { 60, 0 };

static void dnschild_finish(int fd, short event, void *arg);

int dnschild_init()
{
	dprintk("dnschild initialized.");
	dnschild_state = 1;
	return 1;
}

void *dnschild_request(DESC * d)
{
	int fds[2];
	struct dns_query_state_t *dqst;
	char address[1024];
	char outbuffer[255];
	int length;
    int result;

	if(!dnschild_state) {
		dprintk("bailing query, dnschild is shut down.");
		return 0;
	}

	dqst = malloc(sizeof(struct dns_query_state_t));
	memset(dqst, 0, sizeof(struct dns_query_state_t));

	dqst->desc = d;

	if(pipe(fds) < 0) {
		log_perror("DNS", "ERR", NULL, "pipe");
	}

	event_set(&dqst->ev, fds[0], EV_TIMEOUT | EV_READ, dnschild_finish, dqst);
	event_add(&dqst->ev, &query_timeout);

	dqst->pid = fork();
	if(dqst->pid == 0) {
        close(fds[0]);
		/* begin child section */
		unbind_signals();
        memset(address, 0, 1023);
		if((result=getnameinfo((struct sockaddr *) &d->saddr, d->saddr_len,
					   address, 1023, NULL, 0, NI_NAMEREQD))) {
			length = snprintf(outbuffer, 255, "0%s/%s", gai_strerror(result), strerror(errno));
			outbuffer[length++] = '\0';
			write(fds[1], outbuffer, length);
		} else {
			length = snprintf(outbuffer, 255, "1%s", address);
			outbuffer[length++] = '\0';
			write(fds[1], outbuffer, length);
		}
		close(fds[1]);
		exit(0);
		/* end child section */
	}
	dqst->fd = fds[0];
    close(fds[1]);
	dqst->next = running;
	running = dqst;
	running_queries++;
	return (void *) dqst;
}

void dnschild_destruct()
{
	struct dns_query_state_t *dqst;
	dprintk("dnschild expiring queries and shutting down.");
	dnschild_state = 0;
	while (running) {
		dqst = running;
		dprintk("dnschild query for %s aborting early.", dqst->desc->addr);
		if(event_pending(&dqst->ev, EV_READ, NULL))
			event_del(&dqst->ev);
		close(dqst->fd);
		dqst->desc->outstanding_dnschild_query = NULL;
		running = running->next;
		free(dqst);
	}
}

void dnschild_kill(void *arg)
{
	struct dns_query_state_t *dqst = (struct dns_query_state_t *) arg, *iter;

	dprintk("dnschild query for %s aborting early.", dqst->desc->addr);

	iter = running;
	if(running == dqst) {
		running = dqst->next;
	} else {
		while (iter) {
			if(iter->next == dqst) {
				iter->next = dqst->next;
				break;
			}
			iter = iter->next;
		}
	}

	if(event_pending(&dqst->ev, EV_READ, NULL))
		event_del(&dqst->ev);
	dqst->desc->outstanding_dnschild_query = NULL;
	close(dqst->fd);
	free(dqst);
}

static void dnschild_finish(int fd, short event, void *arg)
{
	char buffer[2048];
	struct dns_query_state_t *dqst = (struct dns_query_state_t *) arg, *iter;

	iter = running;
	if(running == dqst) {
		running = dqst->next;
	} else {
		while (iter) {
			if(iter->next == dqst) {
				iter->next = dqst->next;
				break;
			}
			iter = iter->next;
		}
	}

	dqst->desc->outstanding_dnschild_query = NULL;

	if(event & EV_TIMEOUT || !dnschild_state) {
		kill(dqst->pid, SIGTERM);
		log_perror("DNS", "ERR", NULL, "dnschild failed to finish.");
		close(fd);
		free(dqst);
		return;
	}

	read(fd, buffer, 2048);

	if(buffer[0] == '0') {
		dprintk("dnschild failed with error: %s", buffer + 1);
		close(fd);
		free(dqst);
		return;
	}

	strncpy(dqst->desc->addr, buffer + 1, sizeof(dqst->desc->addr) - 1);
	dprintk("dnschild resolved %s correctly.", buffer + 1);
	close(fd);
	free(dqst);
	return;
}