view parsemeta.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
line wrap: on
line source

/* $Id: parsemeta.c,v 1.1.1.1 1997/12/06 05:41:29 darius Exp $ */

/*
 * meta.c     - Nick Trown    May 1993
 */

#ifdef METASERVER

#include "copyright.h"
#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>

#ifdef RS6K
#include <sys/select.h>
#include <fcntl.h>
#endif

#ifndef DNET
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <netdb.h>
#include <errno.h>
#include "Wlib.h"
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "proto.h"

#include <string.h>
#if !defined(SYSV) && !defined(apollo) && !defined(SVR4)
#include <strings.h>
#endif

#define BUF	4096

static void metarefresh P((int i));
static void metadone P((void));

int     pid = 0;
int     num_servers = 0;
int	max_servers = 20;
struct  servers *serverlist = NULL;
char    *keystrings[] = {"OPEN:", "Wait queue:", "Nobody"};

/*
   I was planning to use this function a lot but it doesn't look like
   I need it more than once. It finds the next number after position
   'start'.
 */

int
getnumber(string, start)
    char   *string;
    int     start;
{
#if 0  /* this is stupid [BDyess] */
    char    temp[LINE];
    int     c;
    int     tc = 0;

    for (c = start; c <= (int) strlen(string); c++) {
	if ((string[c] >= '0') && (string[c] <= '9')) {
	    temp[tc++] = string[c];
	} else if (tc > 0) {
	    temp[tc] = '\0';
	    return (atoi(temp));
	}
    }
    return 0;
#endif /*0*/

  string += start;
  while(!isdigit(*string) && *string) string++;
  return atoi(string);
}


/*
   The connection to the metaserver is by Andy McFadden.
   This calls the metaserver and parses the output into something
   useful
 */

static int
open_port(host, port, verbose)
    char   *host;
    int     port;
    int     verbose;
{
#ifdef DNET
    return DNetOpenMeta(host, port);
#else
    struct sockaddr_in addr;
    struct hostent *hp;
    int     s;


    /* Connect to the metaserver */
    /* get numeric form */
    if ((addr.sin_addr.s_addr = inet_addr(host)) == -1) {
	if ((hp = gethostbyname(host)) == NULL) {
	    if (verbose)
		fprintf(stderr, "unknown host '%s'\n", host);
	    return (-1);
	} else {
	    addr.sin_addr.s_addr = *(long *) hp->h_addr;
	}
    }
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	if (verbose)
	    perror("socket");
	return (-1);
    }
    if (connect(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
	if (verbose)
	    perror("connect");
	close(s);
	return (-1);
    }
    return (s);
#endif				/* DNET */
}

static int
readmeta(s)
    int     s;
{
    int     cc, lc = 0, c, tc;

    static char buf[BUF + 1];
    static char *numstr;
    static char line[LINE + 1];

#ifndef DEBUG
    while (1) {
#ifdef DNET			/* annoying... */
	if ((cc = sock_read(s, buf, BUF)) < 0) {
#else	/* } */			/* to balance the {'s for emacs */
	if ((cc = sock_read(s, buf, BUF)) <= 0) {
	    if (cc < 0)
		perror("read");
#endif				/* DNET */
	    sock_close(s);
	    return (cc);
	}
#else
    /*
       cat the output of the metaserver port 3521 to a file called "output"
       for testing purposes
    */
    s = open("output", O_RDONLY);

    if ((cc = read(s, buf, BUF)) <= 0) {
	if (cc < 0)
	    perror("read");
	close(s);
	return (cc);
    }
    fwrite(buf, cc, 1, stdout);
    close(s);
#endif

    for (c = 0; c < cc; c++) {
	if (buf[c] != '\n')	/* Break up the buffer into lines */
	    line[lc++] = buf[c];
	else {
	    line[lc] = 0;	/* random problems without this.  No terminator
	                           means invalid strlen().  [BDyess] */
	    if (sscanf(line, "-h %s -p %d %d",	/* parse line */
		       serverlist[num_servers].address,
		       &serverlist[num_servers].port,
		       &serverlist[num_servers].time) == 3) {
		/* get what type of server it is */
		serverlist[num_servers].typeflag = line[strlen(line) - 1];
		if (serverlist[num_servers].typeflag == 'P') {
		    serverlist[num_servers].status = 2;
		    serverlist[num_servers].players = 0;
		} else
		    serverlist[num_servers].status = -1;

		/*
		   I don't have it checking the servers with nobody playing
		   because the menu window would then be too large to fit on
		   a 1024 x 768 window. :(  - NBT
		*/

		for (tc = 0; tc < KEY; tc++)
		    if ((numstr = strstr(line, keystrings[tc]))) {
			serverlist[num_servers].status = tc;
			serverlist[num_servers].players = getnumber(numstr, 0);
		    }
		if (strrchr(line, 'R'))
		    serverlist[num_servers].RSA_client = 1;
		else
		    serverlist[num_servers].RSA_client = 0;

		if (serverlist[num_servers].status >= 0 &&
		    (serverlist[num_servers].status != 2 ||
		     serverlist[num_servers].typeflag == 'P')) {

#ifdef DEBUG
		    printf("HOST:%-30s PORT:%-6d %12s %-5d %d\n",
			   serverlist[num_servers].address,
			   serverlist[num_servers].port,
			   keystrings[serverlist[num_servers].status],
			   serverlist[num_servers].players,
			   serverlist[num_servers].RSA_client);
#endif

		    serverlist[num_servers].hilited = 0;
		    num_servers++;	/* It's valid */
		    if(num_servers == max_servers) {
		      /* double the size every time it's exceeded [BDyess] */
		      serverlist = (struct servers*) realloc(serverlist, 
		                   sizeof(struct servers) * (max_servers *= 2));
		    }
		}
	    }
	    lc = 0;
	    /*line[0] = '\0';  silly [BDyess] */
	}
    }
}
 /* close(s); */
}


void
parsemeta()
{
    int     s;

    num_servers = 0;

    /* serverlist is now dynamic and grows.  This fixes the random coredump
       and data corruption problems the previous static method caused. 
       [BDyess] */
    if(serverlist) free(serverlist);
    serverlist = (struct servers*) malloc(sizeof(struct servers) * max_servers);

    if (serverName) {
	strcpy(serverlist[num_servers].address, serverName);
	serverlist[num_servers].port = xtrekPort;

#ifdef RSA
	serverlist[num_servers].RSA_client = RSA_Client;
#endif

	serverlist[num_servers].status = KEY + 1;
	serverlist[num_servers].players = 0;
	num_servers++;
    }
    printf("connecting to metaserver...");
    fflush(stdout);

#ifdef DEBUG
    readmeta(0);
#else
    if ((s = open_port(metaserverAddress, METAPORT, 1)) > 0) {
	readmeta(s);
    } else {
	printf("failed (%s , %d)\n", metaserverAddress, METAPORT);
    }
#endif
    printf("\n");
}


/* Show the meta server menu window */

void
metawindow()
{
    register int i;
    static int old_num_servers = -1;

    if (old_num_servers != num_servers) {
	if (metaWin)
	    W_DestroyWindow(metaWin);
	metaWin = W_MakeMenu("MetaServer List", WINSIDE + 10, -BORDER + 10, 69,
			     num_servers + 2, NULL, 2);
    }
    for (i = 0; i < num_servers; i++)
	metarefresh(i);

    /* add refresh option [BDyess] */
    W_WriteText(metaWin, 0, num_servers, textColor, "Refresh", 7, 0);

    /* Add quit option */
    W_WriteText(metaWin, 0, num_servers + 1, textColor, "Quit", 4, W_RegularFont);

    /* Map window */
    if (!W_IsMapped(metaWin))
	W_MapWindow(metaWin);
}

/*
 * Refresh item i
 */
static void
metarefresh(i)
    int     i;
{
    char    buf[BUFSIZ];

    if (serverlist[i].status < KEY) {
	sprintf(buf, "%-40s %12s ",
		serverlist[i].address,
		keystrings[serverlist[i].status]);
	if (serverlist[i].status != 2)
	    sprintf(buf + strlen(buf), "%-5d ", serverlist[i].players);
	else
	    strcat(buf, "      ");
	switch (serverlist[i].typeflag) {
	case 'P':
	    strcat(buf, "Paradise");
	    break;
	case 'B':
	    strcat(buf, "Bronco");
	    break;
	case 'C':
	    strcat(buf, "Chaos");
	    break;
	case 'I':
	    strcat(buf, "INL");
	    break;
	case 'S':
	    strcat(buf, "Sturgeon");
	    break;
	case 'H':
	    strcat(buf, "Hockey");
	    break;
	case 'F':
	    strcat(buf, "Dogfight");
	    break;
	}
    } else if (serverlist[i].status == KEY) {	/* For when I have checking
						   code */
	sprintf(buf, "%-40s CANNOT CONNECT", serverlist[i].address);
    } else if (serverlist[i].status == KEY + 1) {
	sprintf(buf, "%-40s   DEFAULT SERVER", serverlist[i].address);
    }
    W_WriteText(metaWin, 0, i,
		serverlist[i].hilited ? W_Yellow : textColor,
		buf, (int)strlen(buf),
		serverlist[i].hilited ? W_HighlightFont : W_RegularFont);
}


/*
   Check selection to see if was valid. If it was then we have a winner!
 */
static void
metaaction(data)
    W_Event *data;
{
    int     s;
    static time_t lastRefresh = 0;
    static time_t t;

    if ((data->y >= 0) && (data->y < num_servers)) {
	xtrekPort = serverlist[data->y].port;
	serverName = serverlist[data->y].address;

#ifdef RSA
	RSA_Client = serverlist[data->y].RSA_client;
#endif
	serverlist[data->y].hilited = 1;
	metarefresh(data->y);

	if ((s = open_port(serverName, xtrekPort, 0)) <= 0) {
	    serverlist[data->y].status = KEY;
	    serverlist[data->y].hilited = 0;
	    metarefresh(data->y);
	} else {
	    sock_close(s);
#ifndef AMIGA
	    /* allow spawning off multiple clients [BDyess] */
	    if (metaFork) {
		/* just blink yellow [BDyess] */
		serverlist[data->y].hilited = 0;
		metarefresh(data->y);
		pid = fork();
	    } else
#else
	    /*
	       OUCH. fork() sucks ;-) Using "run" is equivalent to appending
	       a & to a command in Unix.  (my shell allows &, but it's not
	       built in to AmigaDOS.)  This is a stupid kludge.  I
	       should write a silly shell or rexx script to do all the
	       metaserver stuff instead, and not compile PARSEMETA at all.
	    */
	    if (metaFork) {
		extern char *command_line; /* main.c, argv */
		extern int global_argc;
		int ac;
		char buf2[256];
		char    buf[80];

		sprintf(buf,"run %s ",command_line[0]);
		for(ac=1;ac<global_argc;ac++) {
		    if(strcmp(command_line[ac], "-m") == 0)
			ac++;
		    else {
			strcat(buf,command_line[ac]);
			strcat(buf," ");
		    }
		}
		printf(buf2,"-h %s -p %d", command_line[0], serverName, xtrekPort);
		strcat(buf, buf2);
		Execute(buf, Input(), Output());
	    } else
#endif				/* AMIGA */
	    {
		pid = 1;
		metadone();
	    }
	}
    } else if (data->y == num_servers) {	/* refresh [BDyess] */
	/*
	   they can bang on refresh all day, but it won't refresh any faster
	   than once/minute. [BDyess]
	*/
	if ((t = time(NULL)) < lastRefresh + 60)
	    return;
	lastRefresh = t;
	parsemeta();		/* connect and parse info */
	metawindow();		/* refresh */
    } else {			/* quit */
	metadone();
	exit(0);
    }
}


/*
   Unmap the metaWindow
 */

static void
metadone()
{
    /* Unmap window */
    W_UnmapWindow(metaWin);
}


/*
   My own little input() function. I needed this so I don't have
   to use all the bull in the main input(). Plus to use it I'd have
   to call mapAll() first and the client would read in the default
   server and then call it up before I can select a server.
 */

void
metainput()
{
    W_Event data;

    while (W_IsMapped(metaWin) && pid == 0) {
	W_GetEvent(&data);
	switch ((int) data.type) {
	case W_EV_KEY:
	    if (data.Window == metaWin)
		metaaction(&data);
	    break;
	case W_EV_BUTTON:
	    if (data.Window == metaWin)
		metaaction(&data);
	    break;
	case W_EV_EXPOSE:
	    break;
	default:
	    break;
	}
    }
}
#endif				/* METASERVER */