btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * This slave does iptoname conversions, and identquery lookups.
 * 
 * The philosophy is to keep this program as simple/small as possible.
 * It does normal fork()s, so the smaller it is, the faster it goes.
 * 
 * $Id: slave.c,v 1.2 2005/08/08 09:43:07 murrayma Exp $
 */

#include "config.h"

#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <signal.h>
#include "slave.h"
#include <arpa/inet.h>
#include <debug.h>

pid_t parent_pid;

#define MAX_STRING 8000
char *arg_for_errors;

char *format_inet_addr(dest, addr)
char *dest;
long addr;
{
    sprintf(dest, "%ld.%ld.%ld.%ld", (addr & 0xFF000000) >> 24,
	(addr & 0x00FF0000) >> 16, (addr & 0x0000FF00) >> 8,
	(addr & 0x000000FF));
    return (dest + strlen(dest));
}

/*
 * copy a string, returning pointer to the null terminator of dest 
 */
char *string_append(char *dest, const char *src)
{
    while ((*dest = *src)) {
	++dest;
	++src;
    }
    return (dest);
}

void child_timeout_signal()
{
    exit(1);
}

int query(ip, orig_arg)
char *ip;
char *orig_arg;
{
    char *comma;
    char *port_pair;
    struct hostent *hp;
    struct sockaddr_in sin;
    int s;
    FILE *f;
    char result[MAX_STRING];
    char buf[MAX_STRING];
    char buf2[MAX_STRING];
    char buf3[MAX_STRING];
    char arg[MAX_STRING];
    size_t len;
    char *p;
    unsigned long addr;


    addr = inet_addr(ip);
    if (addr == -1) {
	return (-1);
    }
    hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
    if (hp && !isdigit(*(hp->h_name))) {
	p = string_append(buf, ip);
	*p++ = ' ';
	p = string_append(p, hp->h_name);
	*p++ = '\n';
	*p++ = '\0';
    } else {
	sprintf(buf, "%s %s\n", ip, ip);
    }
    arg_for_errors = orig_arg;
    strcpy(arg, orig_arg);
    comma = (char *) strrchr(arg, ',');
    if (comma == NULL) {
	return (-1);
    }
    *comma = 0;
    port_pair = (char *) strrchr(arg, ',');
    if (port_pair == NULL) {
	return (-1);
    }
    *port_pair++ = 0;
    *comma = ',';

    hp = gethostbyname(arg);
    if (hp == NULL) {
	static struct hostent def;
	static struct in_addr defaddr;
	static char *alist[1];
	static char namebuf[128];

	defaddr.s_addr = inet_addr(arg);
	if (defaddr.s_addr == -1) {
	    return (-1);
	}
	strcpy(namebuf, arg);
	def.h_name = namebuf;
	def.h_addr_list = alist;
	def.h_addr = (char *) &defaddr;
	def.h_length = sizeof(struct in_addr);

	def.h_addrtype = AF_INET;
	def.h_aliases = 0;
	hp = &def;
    }
    sin.sin_family = hp->h_addrtype;
    bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
    sin.sin_port = htons(113);	/*
				 * ident port 
				 */
    s = socket(hp->h_addrtype, SOCK_STREAM, 0);
    if (s < 0) {
	return (-1);
    }
    if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
	if (errno != ECONNREFUSED && errno != ETIMEDOUT &&
	    errno != ENETUNREACH && errno != EHOSTUNREACH) {
	    close(s);
	    return (-1);
	}
	buf2[0] = '\0';
    } else {
	len = strlen(port_pair);
	if (write(s, port_pair, len) != len) {
	    close(s);
	    return (-1);
	}
	if (write(s, "\r\n", 2) != 2) {
	    close(s);
	    return (-1);
	}
	f = fdopen(s, "r");
	{
	    int c;

	    p = result;
	    while ((c = fgetc(f)) != EOF) {
		if (c == '\n')
		    break;
		if (isprint(c)) {
		    *p++ = c;
		    if (p - result == MAX_STRING - 1)
			break;
		}
	    }
	    *p = '\0';
	}
	(void) fclose(f);
	p = (char *) format_inet_addr(buf2, ntohl(sin.sin_addr.s_addr));
	*p++ = ' ';
	p = string_append(p, result);
	*p++ = '\n';
	*p++ = '\0';
    }
    sprintf(buf3, "%s%s", buf, buf2);
    write(1, buf3, strlen(buf3));
    return (0);
}

void child_signal()
{
    /*
     * collect any children 
     */

#ifdef NEXT
    while (wait3(NULL, WNOHANG, NULL) > 0);
#else
    while (waitpid(0, NULL, WNOHANG) > 0);
#endif
    signal(SIGCHLD, child_signal);
}

void alarm_signal()
{
    struct itimerval itime;
    struct timeval interval;

    if (getppid() != parent_pid) {
	exit(1);
    }
    signal(SIGALRM, alarm_signal);
    interval.tv_sec = 120;	/*
				 * 2 minutes 
				 */
    interval.tv_usec = 0;
    itime.it_interval = interval;
    itime.it_value = interval;
    setitimer(ITIMER_REAL, &itime, 0);
}


int main(argc, argv)
int argc;
char **argv;
{
    char arg[MAX_STRING + 1];
    char *p;
    int len;

    dprintk("slave booting.");
    parent_pid = getppid();
    if (parent_pid == 1) {
        exit(1);
    }
    alarm_signal();
    signal(SIGCHLD, child_signal);
    signal(SIGPIPE, SIG_DFL);
    for (;;) {
	len = read(0, arg, MAX_STRING);
	if (len == 0)
	    break;
	if (len < 0) {
	    if (errno == EINTR) {
		errno = 0;
		continue;
	    }
	    break;
	}
	arg[len] = '\0';
	p = strchr(arg, '\n');
	if (p)
	    *p = '\0';
	switch (fork()) {
	case -1:
	    exit(1);

	case 0:		/*
				   * child 
				 */
	    {
            dprintk("child booted.\n");
		/*
		 * we don't want to try this for more than 5
		 * * * * * minutes 
		 */
		struct itimerval itime;
		struct timeval interval;

		interval.tv_sec = 300;	/*
					 * 5 minutes 
					 */
		interval.tv_usec = 0;
		itime.it_interval = interval;
		itime.it_value = interval;
		signal(SIGALRM, child_timeout_signal);
		setitimer(ITIMER_REAL, &itime, 0);
	    }
	    exit(query(arg, p + 1) != 0);

	}
	/*
	 * collect any children 
	 */
#ifdef NEXT
	while (wait3(NULL, WNOHANG, NULL) > 0);
#else
	while (waitpid(0, NULL, WNOHANG) > 0);
#endif
    }
    exit(0);
}