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