Mercurial > ~darius > hgwebdir.cgi > paradise_client
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 */