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