comparison parsemeta.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
comparison
equal deleted inserted replaced
2:fba0b6e6cdc7 3:5a977ccbc7a9
1 /* $Id: parsemeta.c,v 1.1.1.1 1997/12/06 05:41:29 darius Exp $ */
2
3 /*
4 * meta.c - Nick Trown May 1993
5 */
6
7 #ifdef METASERVER
8
9 #include "copyright.h"
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <stdlib.h>
16 #include <sys/socket.h>
17 #include <unistd.h>
18
19 #ifdef RS6K
20 #include <sys/select.h>
21 #include <fcntl.h>
22 #endif
23
24 #ifndef DNET
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #endif
28 #include <netdb.h>
29 #include <errno.h>
30 #include "Wlib.h"
31 #include "defs.h"
32 #include "struct.h"
33 #include "data.h"
34 #include "proto.h"
35
36 #include <string.h>
37 #if !defined(SYSV) && !defined(apollo) && !defined(SVR4)
38 #include <strings.h>
39 #endif
40
41 #define BUF 4096
42
43 static void metarefresh P((int i));
44 static void metadone P((void));
45
46 int pid = 0;
47 int num_servers = 0;
48 int max_servers = 20;
49 struct servers *serverlist = NULL;
50 char *keystrings[] = {"OPEN:", "Wait queue:", "Nobody"};
51
52 /*
53 I was planning to use this function a lot but it doesn't look like
54 I need it more than once. It finds the next number after position
55 'start'.
56 */
57
58 int
59 getnumber(string, start)
60 char *string;
61 int start;
62 {
63 #if 0 /* this is stupid [BDyess] */
64 char temp[LINE];
65 int c;
66 int tc = 0;
67
68 for (c = start; c <= (int) strlen(string); c++) {
69 if ((string[c] >= '0') && (string[c] <= '9')) {
70 temp[tc++] = string[c];
71 } else if (tc > 0) {
72 temp[tc] = '\0';
73 return (atoi(temp));
74 }
75 }
76 return 0;
77 #endif /*0*/
78
79 string += start;
80 while(!isdigit(*string) && *string) string++;
81 return atoi(string);
82 }
83
84
85 /*
86 The connection to the metaserver is by Andy McFadden.
87 This calls the metaserver and parses the output into something
88 useful
89 */
90
91 static int
92 open_port(host, port, verbose)
93 char *host;
94 int port;
95 int verbose;
96 {
97 #ifdef DNET
98 return DNetOpenMeta(host, port);
99 #else
100 struct sockaddr_in addr;
101 struct hostent *hp;
102 int s;
103
104
105 /* Connect to the metaserver */
106 /* get numeric form */
107 if ((addr.sin_addr.s_addr = inet_addr(host)) == -1) {
108 if ((hp = gethostbyname(host)) == NULL) {
109 if (verbose)
110 fprintf(stderr, "unknown host '%s'\n", host);
111 return (-1);
112 } else {
113 addr.sin_addr.s_addr = *(long *) hp->h_addr;
114 }
115 }
116 addr.sin_family = AF_INET;
117 addr.sin_port = htons(port);
118 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
119 if (verbose)
120 perror("socket");
121 return (-1);
122 }
123 if (connect(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
124 if (verbose)
125 perror("connect");
126 close(s);
127 return (-1);
128 }
129 return (s);
130 #endif /* DNET */
131 }
132
133 static int
134 readmeta(s)
135 int s;
136 {
137 int cc, lc = 0, c, tc;
138
139 static char buf[BUF + 1];
140 static char *numstr;
141 static char line[LINE + 1];
142
143 #ifndef DEBUG
144 while (1) {
145 #ifdef DNET /* annoying... */
146 if ((cc = sock_read(s, buf, BUF)) < 0) {
147 #else /* } */ /* to balance the {'s for emacs */
148 if ((cc = sock_read(s, buf, BUF)) <= 0) {
149 if (cc < 0)
150 perror("read");
151 #endif /* DNET */
152 sock_close(s);
153 return (cc);
154 }
155 #else
156 /*
157 cat the output of the metaserver port 3521 to a file called "output"
158 for testing purposes
159 */
160 s = open("output", O_RDONLY);
161
162 if ((cc = read(s, buf, BUF)) <= 0) {
163 if (cc < 0)
164 perror("read");
165 close(s);
166 return (cc);
167 }
168 fwrite(buf, cc, 1, stdout);
169 close(s);
170 #endif
171
172 for (c = 0; c < cc; c++) {
173 if (buf[c] != '\n') /* Break up the buffer into lines */
174 line[lc++] = buf[c];
175 else {
176 line[lc] = 0; /* random problems without this. No terminator
177 means invalid strlen(). [BDyess] */
178 if (sscanf(line, "-h %s -p %d %d", /* parse line */
179 serverlist[num_servers].address,
180 &serverlist[num_servers].port,
181 &serverlist[num_servers].time) == 3) {
182 /* get what type of server it is */
183 serverlist[num_servers].typeflag = line[strlen(line) - 1];
184 if (serverlist[num_servers].typeflag == 'P') {
185 serverlist[num_servers].status = 2;
186 serverlist[num_servers].players = 0;
187 } else
188 serverlist[num_servers].status = -1;
189
190 /*
191 I don't have it checking the servers with nobody playing
192 because the menu window would then be too large to fit on
193 a 1024 x 768 window. :( - NBT
194 */
195
196 for (tc = 0; tc < KEY; tc++)
197 if ((numstr = strstr(line, keystrings[tc]))) {
198 serverlist[num_servers].status = tc;
199 serverlist[num_servers].players = getnumber(numstr, 0);
200 }
201 if (strrchr(line, 'R'))
202 serverlist[num_servers].RSA_client = 1;
203 else
204 serverlist[num_servers].RSA_client = 0;
205
206 if (serverlist[num_servers].status >= 0 &&
207 (serverlist[num_servers].status != 2 ||
208 serverlist[num_servers].typeflag == 'P')) {
209
210 #ifdef DEBUG
211 printf("HOST:%-30s PORT:%-6d %12s %-5d %d\n",
212 serverlist[num_servers].address,
213 serverlist[num_servers].port,
214 keystrings[serverlist[num_servers].status],
215 serverlist[num_servers].players,
216 serverlist[num_servers].RSA_client);
217 #endif
218
219 serverlist[num_servers].hilited = 0;
220 num_servers++; /* It's valid */
221 if(num_servers == max_servers) {
222 /* double the size every time it's exceeded [BDyess] */
223 serverlist = (struct servers*) realloc(serverlist,
224 sizeof(struct servers) * (max_servers *= 2));
225 }
226 }
227 }
228 lc = 0;
229 /*line[0] = '\0'; silly [BDyess] */
230 }
231 }
232 }
233 /* close(s); */
234 }
235
236
237 void
238 parsemeta()
239 {
240 int s;
241
242 num_servers = 0;
243
244 /* serverlist is now dynamic and grows. This fixes the random coredump
245 and data corruption problems the previous static method caused.
246 [BDyess] */
247 if(serverlist) free(serverlist);
248 serverlist = (struct servers*) malloc(sizeof(struct servers) * max_servers);
249
250 if (serverName) {
251 strcpy(serverlist[num_servers].address, serverName);
252 serverlist[num_servers].port = xtrekPort;
253
254 #ifdef RSA
255 serverlist[num_servers].RSA_client = RSA_Client;
256 #endif
257
258 serverlist[num_servers].status = KEY + 1;
259 serverlist[num_servers].players = 0;
260 num_servers++;
261 }
262 printf("connecting to metaserver...");
263 fflush(stdout);
264
265 #ifdef DEBUG
266 readmeta(0);
267 #else
268 if ((s = open_port(metaserverAddress, METAPORT, 1)) > 0) {
269 readmeta(s);
270 } else {
271 printf("failed (%s , %d)\n", metaserverAddress, METAPORT);
272 }
273 #endif
274 printf("\n");
275 }
276
277
278 /* Show the meta server menu window */
279
280 void
281 metawindow()
282 {
283 register int i;
284 static int old_num_servers = -1;
285
286 if (old_num_servers != num_servers) {
287 if (metaWin)
288 W_DestroyWindow(metaWin);
289 metaWin = W_MakeMenu("MetaServer List", WINSIDE + 10, -BORDER + 10, 69,
290 num_servers + 2, NULL, 2);
291 }
292 for (i = 0; i < num_servers; i++)
293 metarefresh(i);
294
295 /* add refresh option [BDyess] */
296 W_WriteText(metaWin, 0, num_servers, textColor, "Refresh", 7, 0);
297
298 /* Add quit option */
299 W_WriteText(metaWin, 0, num_servers + 1, textColor, "Quit", 4, W_RegularFont);
300
301 /* Map window */
302 if (!W_IsMapped(metaWin))
303 W_MapWindow(metaWin);
304 }
305
306 /*
307 * Refresh item i
308 */
309 static void
310 metarefresh(i)
311 int i;
312 {
313 char buf[BUFSIZ];
314
315 if (serverlist[i].status < KEY) {
316 sprintf(buf, "%-40s %12s ",
317 serverlist[i].address,
318 keystrings[serverlist[i].status]);
319 if (serverlist[i].status != 2)
320 sprintf(buf + strlen(buf), "%-5d ", serverlist[i].players);
321 else
322 strcat(buf, " ");
323 switch (serverlist[i].typeflag) {
324 case 'P':
325 strcat(buf, "Paradise");
326 break;
327 case 'B':
328 strcat(buf, "Bronco");
329 break;
330 case 'C':
331 strcat(buf, "Chaos");
332 break;
333 case 'I':
334 strcat(buf, "INL");
335 break;
336 case 'S':
337 strcat(buf, "Sturgeon");
338 break;
339 case 'H':
340 strcat(buf, "Hockey");
341 break;
342 case 'F':
343 strcat(buf, "Dogfight");
344 break;
345 }
346 } else if (serverlist[i].status == KEY) { /* For when I have checking
347 code */
348 sprintf(buf, "%-40s CANNOT CONNECT", serverlist[i].address);
349 } else if (serverlist[i].status == KEY + 1) {
350 sprintf(buf, "%-40s DEFAULT SERVER", serverlist[i].address);
351 }
352 W_WriteText(metaWin, 0, i,
353 serverlist[i].hilited ? W_Yellow : textColor,
354 buf, (int)strlen(buf),
355 serverlist[i].hilited ? W_HighlightFont : W_RegularFont);
356 }
357
358
359 /*
360 Check selection to see if was valid. If it was then we have a winner!
361 */
362 static void
363 metaaction(data)
364 W_Event *data;
365 {
366 int s;
367 static time_t lastRefresh = 0;
368 static time_t t;
369
370 if ((data->y >= 0) && (data->y < num_servers)) {
371 xtrekPort = serverlist[data->y].port;
372 serverName = serverlist[data->y].address;
373
374 #ifdef RSA
375 RSA_Client = serverlist[data->y].RSA_client;
376 #endif
377 serverlist[data->y].hilited = 1;
378 metarefresh(data->y);
379
380 if ((s = open_port(serverName, xtrekPort, 0)) <= 0) {
381 serverlist[data->y].status = KEY;
382 serverlist[data->y].hilited = 0;
383 metarefresh(data->y);
384 } else {
385 sock_close(s);
386 #ifndef AMIGA
387 /* allow spawning off multiple clients [BDyess] */
388 if (metaFork) {
389 /* just blink yellow [BDyess] */
390 serverlist[data->y].hilited = 0;
391 metarefresh(data->y);
392 pid = fork();
393 } else
394 #else
395 /*
396 OUCH. fork() sucks ;-) Using "run" is equivalent to appending
397 a & to a command in Unix. (my shell allows &, but it's not
398 built in to AmigaDOS.) This is a stupid kludge. I
399 should write a silly shell or rexx script to do all the
400 metaserver stuff instead, and not compile PARSEMETA at all.
401 */
402 if (metaFork) {
403 extern char *command_line; /* main.c, argv */
404 extern int global_argc;
405 int ac;
406 char buf2[256];
407 char buf[80];
408
409 sprintf(buf,"run %s ",command_line[0]);
410 for(ac=1;ac<global_argc;ac++) {
411 if(strcmp(command_line[ac], "-m") == 0)
412 ac++;
413 else {
414 strcat(buf,command_line[ac]);
415 strcat(buf," ");
416 }
417 }
418 printf(buf2,"-h %s -p %d", command_line[0], serverName, xtrekPort);
419 strcat(buf, buf2);
420 Execute(buf, Input(), Output());
421 } else
422 #endif /* AMIGA */
423 {
424 pid = 1;
425 metadone();
426 }
427 }
428 } else if (data->y == num_servers) { /* refresh [BDyess] */
429 /*
430 they can bang on refresh all day, but it won't refresh any faster
431 than once/minute. [BDyess]
432 */
433 if ((t = time(NULL)) < lastRefresh + 60)
434 return;
435 lastRefresh = t;
436 parsemeta(); /* connect and parse info */
437 metawindow(); /* refresh */
438 } else { /* quit */
439 metadone();
440 exit(0);
441 }
442 }
443
444
445 /*
446 Unmap the metaWindow
447 */
448
449 static void
450 metadone()
451 {
452 /* Unmap window */
453 W_UnmapWindow(metaWin);
454 }
455
456
457 /*
458 My own little input() function. I needed this so I don't have
459 to use all the bull in the main input(). Plus to use it I'd have
460 to call mapAll() first and the client would read in the default
461 server and then call it up before I can select a server.
462 */
463
464 void
465 metainput()
466 {
467 W_Event data;
468
469 while (W_IsMapped(metaWin) && pid == 0) {
470 W_GetEvent(&data);
471 switch ((int) data.type) {
472 case W_EV_KEY:
473 if (data.Window == metaWin)
474 metaaction(&data);
475 break;
476 case W_EV_BUTTON:
477 if (data.Window == metaWin)
478 metaaction(&data);
479 break;
480 case W_EV_EXPOSE:
481 break;
482 default:
483 break;
484 }
485 }
486 }
487 #endif /* METASERVER */