diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parsemeta.c	Sat Dec 06 05:41:29 1997 +0000
@@ -0,0 +1,487 @@
+/* $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 */