unofficial version 0.7.2: mainly sync/reset fixes
[netris.git] / server.c
1 /*
2  * Netris -- A free networked version of T*tris
3  * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id: game.c,v 1.39 1999/05/16 06:56:27 mhw Exp $
20  */
21
22 #define NOEXT
23 #include "netris.h"
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <unistd.h>
30 #include <sys/socket.h>
31 #include <netdb.h>
32 #include <errno.h>
33 #include <setjmp.h>
34
35 #define HEADER_SIZE sizeof(netint4[3])
36
37 static struct option options[] = {
38         { "wait",               0, 0, 'w' },
39         { "port",               1, 0, 'p' },
40         { "min-players",1, 0, 'm' },
41         { "max-players",1, 0, 'x' },
42         { "continuous", 1, 0, 'c' },
43         { "speed",              1, 0, 'i' },
44         { "seed",               1, 0, 's' },
45         { "verbose",    0, 0, 'v' },
46         { "info",               0, 0, 'H' },
47         { "help",               0, 0, 'h' },
48         { 0,                    0, 0,  0 }
49 };
50
51 static char minplayers = 2;
52 static char playercount;
53 static char verbose = 0;
54
55 struct sockaddr_in addr;
56
57 static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" };
58
59 ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
60 static EventGenRec netGen[MAX_SCREENS] = {
61         { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE } };
62
63 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
64 static EventGenRec alarmGen =
65         { &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm };
66
67 static MyEventType ConnGenFunc(EventGenRec *gen, MyEvent *event);
68 static EventGenRec connGen =
69         { NULL, 0, FT_read, -1, ConnGenFunc, EM_connect };
70
71 static EventGenRec *nextGen = &alarmGen;
72
73 static sigjmp_buf close_env;
74
75
76 ExtFunc volatile void die(char *msg)
77 {
78         perror(msg);
79         exit(1);
80 } //die
81
82 ExtFunc int MyRead(int fd, void *data, int len)
83 {
84         int result, left;
85
86         left = len;
87         while (left > 0) {
88                 result = read(fd, data, left);
89                 if (result > 0) {
90                         data = ((char *)data) + result;
91                         left -= result;
92                 }
93                 else if (errno != EINTR)
94                         return result;
95         }
96         return len;
97 } //MyRead
98
99 ExtFunc int MyWrite(int fd, void *data, int len)
100 {
101         int result, left;
102
103         left = len;
104         while (left > 0) {
105                 result = write(fd, data, left);
106                 if (result > 0) {
107                         data = ((char *)data) + result;
108                         left -= result;
109                 }
110                 else if (errno != EINTR)
111                         return result;
112         }
113         return len;
114 } //MyWrite
115
116 ExtFunc void SendPacketTo(short playa, short uid, NetPacketType type, int size, void *data)
117 { //send to someone
118         netint4 header[3];
119
120         if (netGen[playa].fd >= 0) {
121                 header[0] = hton4(uid);
122                 header[1] = hton4(type);
123                 header[2] = hton4(size + HEADER_SIZE);
124                 if (MyWrite(netGen[playa].fd, header, HEADER_SIZE) != HEADER_SIZE)
125                         die("write (header)");
126                 if (size > 0 && data && MyWrite(netGen[playa].fd, data, size) != size)
127                         die("write");
128         }
129 } //SendPacketTo
130
131 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
132 {
133         return E_alarm;
134 } //AlarmGenFunc
135
136 ExtFunc void AddEventGen(EventGenRec *gen)
137 {
138         assert(gen->next == NULL);
139         assert(nextGen->next != (void*)0xffffffff);
140         gen->next = nextGen->next;
141         nextGen->next = gen;
142 } //AddEventGen
143
144 ExtFunc void RemoveEventGen(EventGenRec *gen)
145 {
146         // assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
147         if (gen->next) {
148                 while (nextGen->next != gen)
149                         nextGen = nextGen->next;
150                 nextGen->next = gen->next;
151                 gen->next = NULL;
152         }
153 } //RemoveEventGen
154
155 ExtFunc void AtExit(void (*handler)(void))
156 { //setup something to do at exit (^C)
157 #ifdef HAS_ON_EXIT
158         on_exit((void *)handler, NULL);
159 #else
160         atexit(handler);
161 #endif
162 } //AtExit
163
164 ExtFunc void SCloseNet(short playa)
165 { //kick some connection's ass!
166         MyEvent event;
167
168         if (netGen[playa].fd >= 0) {
169                 if (Players[playa].alive >= 0) {
170                         SendPacketTo(playa, 0, NP_endConn, 0, NULL);
171                         do{} while (WaitMyEvent(&event, EM_net) != E_lostConn);
172                 } //say bye to player
173                 close(netGen[playa].fd);
174                 netGen[playa].fd = -1;
175         }
176         if (netGen[playa].next)
177                 RemoveEventGen(&netGen[playa]);
178 } //SCloseNet
179
180 ExtFunc void CloseNets(void)
181 { //nou oogjes dicht en snaveltjes toe
182         int i;
183
184         fprintf(stderr, "- Closing connections...\n");
185         for (i = 1; i < MAX_SCREENS; i++)
186                 SCloseNet(i); //bye everybuddy
187         fprintf(stderr, "* All Done\n\n");
188 } //CloseNets
189
190 ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
191 { //poll
192         int i, retry = 0;
193         fd_set fds[FT_len];
194         EventGenRec *gen;
195         int result, anyReady, anySet;
196         struct timeval tv;
197
198         for (;;) {
199                 for (i = 0; i < FT_len; ++i)
200                         FD_ZERO(&fds[i]);
201                 anyReady = anySet = 0;
202                 gen = nextGen;
203                 do {
204                         if (gen->mask & mask) {
205                                 if (gen->ready)
206                                         anyReady = 1;
207                                 if (gen->fd >= 0) {
208                                         FD_SET(gen->fd, &fds[gen->fdType]);
209                                         anySet = 1;
210                                 }
211                         }
212                         gen = gen->next;
213                 } while (gen != nextGen);
214                 if (anySet) {
215                         tv.tv_sec = 0;
216                         tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
217                         result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
218                                         &fds[FT_except], anyReady ? &tv : NULL);
219                 }
220                 else {
221                         if (retry && !anyReady)
222                                 sleep(1);
223                         result = 0;
224                 }
225                 gen = nextGen;
226                 do {
227                         if ((gen->mask & mask)
228                                         && (gen->ready || (result > 0 && gen->fd >= 0
229                                                 && FD_ISSET(gen->fd, &fds[gen->fdType])))) {
230                                 gen->ready = 0;
231                                 event->type = gen->func(gen, event);
232                                 if (event->type != E_none) {
233                                         nextGen = gen->next;
234                                         return event->type;
235                                 }
236                         }
237                         gen = gen->next;
238                 } while (gen != nextGen);
239                 retry = 1;
240         }
241 } //WaitMyEvent
242
243 ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
244 { //receive
245         int result;
246         short uid, type, size;
247         netint4 *data = (netint4*)&(gen->buf);
248
249         result = MyRead(gen->fd, gen->buf + gen->bufSize,
250                 gen->bufGoal - gen->bufSize);
251         if (result < 0) {
252                 fprintf(stderr, "- Closed connection to player #%d\n", gen->player);
253                 return E_lostConn;
254         }
255         gen->bufSize += result;
256         if (gen->bufSize < gen->bufGoal)
257                 return E_none;
258         // *ugly* memcpy(data, gen->buf, sizeof(data));
259         uid = ntoh4(data[0]);
260         type = ntoh4(data[1]);
261         size = ntoh4(data[2]);
262         gen->bufGoal = size;
263         if (gen->bufSize < gen->bufGoal)
264                 return E_none;
265         gen->bufSize = 0;
266         gen->bufGoal = HEADER_SIZE;
267         event->u.net.sender = gen->player;
268         event->u.net.uid = uid;
269         event->u.net.type = type;
270         event->u.net.size = size - HEADER_SIZE;
271         event->u.net.data = gen->buf + HEADER_SIZE;
272         if (type == NP_endConn) {
273                 fprintf(stderr, "- Quit player #%d\n", gen->player);
274                 return E_lostConn;
275         } //client sent quit signal
276         return E_net;
277 } //NetGenFunc
278
279
280 static MyEventType ConnGenFunc(EventGenRec *gen, MyEvent *event)
281 {
282         int addrLen;
283         struct linger val2;
284         int new;
285
286         addrLen = sizeof(addr);
287         for (new = 1; new <= MAX_SCREENS; new++)
288                 if (netGen[new].fd < 0) break;
289         if (new > Game.maxplayers) return;
290
291         if ((netGen[new].fd =
292                 accept(gen->fd, (struct sockaddr *)&addr, &addrLen)) < 0)
293                         die("accept");
294         fprintf(stderr, "+ Connection: %s\n", inet_ntoa(addr.sin_addr));
295         val2.l_onoff = 1;
296         val2.l_linger = 0;
297         setsockopt(netGen[new].fd, SOL_SOCKET, SO_LINGER,(void *)&val2,
298                 sizeof(val2));
299         AddEventGen(&netGen[new]);
300         netGen[new].player = event->u.net.uid = new;
301                         { //new connection; netGen already initialized in GenFunc
302                                 struct hostent *host;
303
304                                 sprintf(Players[new].host, "%s", inet_ntoa(addr.sin_addr));
305                                 if (addr.sin_family == AF_INET) {
306                                         host = gethostbyaddr((void *)&addr.sin_addr,
307                                                         sizeof(struct in_addr), AF_INET);
308                                         if (host) {
309                                                 strncpy(Players[new].host, host->h_name,
310                                                         sizeof(Players[new].host) - 1);
311                                                 Players[new].host[sizeof(Players[new].host) - 1] = 0;
312                                         } //set player's hostname
313                                 }
314                         } //E_connect
315         return E_connect;
316 } //ConnGenFunc
317
318 ExtFunc void CountPlayers(void)
319 { //count number of players/teams
320         int i, j;
321         playercount = 0;
322         for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive > 0) {
323                 if (Players[i].team < 128) for (j = 1; j < i; j++)
324                         if (Players[j].alive > 0 && (Players[j].team == Players[i].team)) {
325                                 playercount--;
326                                 break;
327                         } //player of same team counted before
328                 playercount++;
329         } //player alive
330 } //CountPlayers
331
332 ExtFunc int StartServer(void)
333 {
334         MyEvent event;
335         netint2 currentpiece[MAX_SCREENS];
336         int playersReady = 0;
337         int paused = 1;
338         int i;
339         char teams[10][7] = { "", "Green", "Cyan", "Blue", "Purple",
340                                                         "Red", "Grey", "White", "*Orange" };
341
342         do {
343                 switch (WaitMyEvent(&event, EM_any)) {
344                         case E_lostConn: //client went away :(
345                                 Players[event.u.net.sender].alive = -1;
346                                 for (i = 1; i < MAX_SCREENS; i++)
347                                         if (Players[i].alive >= 0)
348                                                 SendPacketTo(i, event.u.net.sender,
349                                                         NP_part, sizeof(Players[0].alive),
350                                                         &Players[event.u.net.sender].alive);
351                                 SCloseNet(event.u.net.sender);
352                                 break; //NP_endConn
353                         case E_net:
354                                 if (verbose) fprintf(stderr, ": %d sent %d\n",
355                                         netGen[event.u.net.sender].fd, event.u.net.type);
356                                 switch(event.u.net.type) {
357                                         case NP_hello:
358 //                                              if (event.u.net.type != NP_hello) ByeClient(new);
359                                         {
360                                                 netint4 versiondata[2];
361                                                 char data[255];
362                                                 int major;
363
364                                                 memcpy(versiondata, event.u.net.data,
365                                                         sizeof(versiondata));
366                                                 major = ntoh4(versiondata[0]);
367                                                 protocolVersion = ntoh4(versiondata[1]);
368                                                 if (major != MAJOR_VERSION
369                                                 || protocolVersion != PROTOCOL_VERSION) {
370                                                         snprintf(data, sizeof(data),
371                                                                 "Version mismatch: received %d.%d",
372                                                                 major, protocolVersion);
373                                                         fprintf(stderr, "= Wrong version player #%d (%s)\n",
374                                                                 event.u.net.sender, data);
375                                                         SendPacketTo(event.u.net.sender, 0, NP_error,
376                                                                 strlen(data)+1, data);
377                                                         SCloseNet(event.u.net.sender);
378                                                 } //version mismatch
379                                                 fprintf(stderr, "* Accepted player #%d\n",
380                                                         event.u.net.sender);
381                                                 break;
382                                         } //NP_hello
383                                         case NP_newPlayer:
384                                         //receive player details and return other players
385                                                 memcpy(&Players[event.u.net.sender],
386                                                         event.u.net.data, event.u.net.size);
387                                                 if (Players[event.u.net.sender].team < 1
388                                                 || Players[event.u.net.sender].team > 7) {
389                                                         Players[event.u.net.sender].team =
390                                                                 event.u.net.sender % 7 + 1;
391                                                         SendPacketTo(event.u.net.sender,
392                                                                 event.u.net.sender, NP_team,
393                                                                 sizeof(Players[event.u.net.sender].team),
394                                                                 &Players[event.u.net.sender].team);
395                                                 } //invalid team
396                                                 if (Game.started < 2)
397                                                         Players[event.u.net.sender].flags |= SCF_paused;
398                                                 if (!Game.continuous && Game.started >= 2) {
399                                                         char data[40];
400                                                         strcpy(data, "Can't join: Game has already started");
401                                                         fprintf(stderr, "- Can't join player #%d in "
402                                                                 "non-continuous game\n", event.u.net.sender);
403                                                         SendPacketTo(event.u.net.sender, 0, NP_error,
404                                                                 strlen(data)+1, data);
405 //                                                      SCloseNet(event.u.net.sender, 0);
406                                                         break;
407                                                 } //can't join started game
408                                                 {
409                                                         static struct {
410                                                                 int playerflags;
411                                                                 int maxplayers; //1
412                                                                 int started;    //2
413                                                                 int continuous; //3
414                                                                 long seed;              //4
415                                                                 int initspeed;  //5
416                                                         } data;
417
418                                                         memcpy(&data, &Players[event.u.net.sender].flags,
419                                                                 sizeof(data.playerflags));
420                                                         memcpy(&data.maxplayers, &Game,
421                                                                 sizeof(data) - sizeof(data.playerflags));
422                                                         SendPacketTo(event.u.net.sender, 0, NP_gamedata,
423                                                                 sizeof(data), &data);
424                                                 } //send game options
425                                                 for (i = 1; i < MAX_SCREENS; i++)
426                                                         if (netGen[i].fd >= 0 && i != event.u.net.sender) {
427                                                                 SendPacketTo(event.u.net.sender, i,
428                                                                         NP_newPlayer, sizeof(Player)
429                                                                         - sizeof(Players[0].spy)
430                                                                         - sizeof(Players[0].small),
431                                                                         &Players[i]);
432                                                                 SendPacketTo(event.u.net.sender, i,
433                                                                         NP_newPiece, sizeof(currentpiece[i]),
434                                                                         &currentpiece[i]);
435                                                                 SendPacketTo(i, event.u.net.sender,
436                                                                         NP_newPlayer, sizeof(Player)
437                                                                         - sizeof(Players[0].spy)
438                                                                         - sizeof(Players[0].small),
439                                                                         &Players[event.u.net.sender]);
440                                                         } //send (to) players
441                                                 fprintf(stderr, "> Joined player #%d: %s <%s> (%s)\n",
442                                                         event.u.net.sender,
443                                                         Players[event.u.net.sender].name,
444                                                         Players[event.u.net.sender].host,
445                                                         teams[Players[event.u.net.sender].team]);
446                                                 if (++playersReady >= minplayers) {
447                                                         if (Game.started > 1)
448                                                                 SendPacketTo(event.u.net.sender, 0,
449                                                                         NP_start, 0, NULL);
450 /*                                                      else {
451                                                                 fprintf(stderr, "* Starting game (%010d)\n",
452                                                                         Game.seed);
453                                                                 for (i = 1; i < MAX_SCREENS; i++)
454                                                                         SendPacketTo(i, 0, NP_start, 0, NULL);
455                                                                 Game.started++;
456                                                         } //first goahead (to all)*/
457                                                 } //give go ahead
458                                                 break; //NP_playerdata
459                                         case NP_newPiece:
460                                                 memcpy(&currentpiece[event.u.net.sender],
461                                                         event.u.net.data, sizeof(currentpiece[0]));
462                                                 goto sendtoall;
463                                         case NP_argghhh:
464                                                 Players[event.u.net.sender].alive = 0;
465                                                 fprintf(stderr, "< Player #%d died\n",
466                                                         event.u.net.sender);
467                                                 //check for unpaused game
468                                         case NP_pause:
469                                         {
470                                                 Players[event.u.net.sender].flags ^= SCF_paused;
471                                                 paused = Game.started < 1;
472                                                 for (i = 1; i < MAX_SCREENS; i++)
473                                                         if (Players[i].alive > 0)
474                                                                 paused |= Players[i].flags & SCF_paused;
475                                                 fprintf(stderr, "* Player #%d (un)paused (pause=%d)\n",
476                                                         event.u.net.sender, paused);
477                                                 if (paused) paused = 1;
478                                                 goto sendtoall;
479                                         } //NP_pause
480                                         default: //relay data to all players
481                                         sendtoall:
482 //                                              if (event.u.net.type >= NP_pause)
483                                                 if (event.u.net.type >= NP_rotright
484                                                 && Game.started < 2)
485                                                         break;
486                                                 for (i = 1; i < MAX_SCREENS; i++)
487                                                         if (i != event.u.net.sender)
488                                                         if (event.u.net.type != NP_giveJunk ||
489                                                         Players[i].team != Players[event.u.net.sender].team)
490                                                                 SendPacketTo(i, event.u.net.sender,
491                                                                         event.u.net.type, event.u.net.size,
492                                                                         event.u.net.data);
493                                                 break; //>=NP_paused
494                                 }
495                                 break; //E_net
496                         case E_connect:
497                         { //new connection; netGen already initialized in GenFunc
498                                 char serverdata[255];
499
500                                 sprintf(serverdata, "Netris server %s", version_string);
501                                 SendPacketTo(event.u.net.uid, event.u.net.uid, NP_hello,
502                                         strlen(serverdata)+1, serverdata);
503                                 break;
504                         } //E_connect
505                 } //event
506                 CountPlayers();
507                 if (Game.started < 1) {
508                         if (playercount > 1) {
509                                 fprintf(stderr, "* Game (%010d) ready to start\n", Game.seed);
510                                 Game.started++;
511                         } //give goahead
512                 } //game not yet started
513                 else {
514                         if (playercount < 2) {
515                                 fprintf(stderr, "* Stopping game\n");
516                                 if (Game.seed) Game.seed++;
517                                 if (Game.started > 1) for (i = 1; i < MAX_SCREENS; i++)
518                                         if (Players[i].alive >= 0) {
519                                                 Players[i].alive = 1;
520                                                 Players[i].flags |= SCF_paused;
521                                                 SendPacketTo(i, 0, NP_stop,
522                                                         sizeof(Game.seed), &Game.seed);
523                                         } //transmit game stop and set players not ready
524                                 paused = 1;
525                                 Game.started = 0;
526                         } //too few players for game
527                         if (Game.started == 1 && !paused) {
528                                 Game.started++;
529                                 fprintf(stderr, "* Game starts\n");
530                                 for (i = 1; i < MAX_SCREENS; i++)
531                                         if (Players[i].alive > 0)
532                                                 SendPacketTo(i, 0, NP_start, 0, NULL);
533                         } //everybody ready to start
534                 } //game (ready to) start(ed)
535         } while (1);
536         fprintf(stderr, "* Exiting server\n");
537 } //StartServer
538
539
540 ExtFunc void Header(void)
541 {
542         fprintf(stderr,
543           "NETRIS Server %s\t(c) 2002 Shiar <shiar@shiar.org>\n\n",
544           version_string);
545 } //Header
546
547 ExtFunc void Usage(void)
548 {
549         Header();
550         fprintf(stderr,
551           "Usage: netris <options>\n"
552           "\n"
553           "  -h, --help\t\tPrint this usage information\n"
554           "  -H, --info\t\tShow distribution and warranty information\n"
555           "\n"
556           "  -p, --port <port>\tSet port number (default is %d)\n"
557           "\n"
558           "  -s, --seed <seed>\tStart with given random seed\n"
559           "  -i, --speed <sec>\tSet the initial step-down interval, in seconds\n"
560           "  -m, --min-players <2>\tNumber of players required before starting the game\n"
561           "  -x, --max-players <8>\tMaximum number of players allowed in the game\n"
562           "  -c, --continuous\tDon'n quit the game\n"
563           "\n", DEFAULT_PORT);
564 }
565
566 ExtFunc void DistInfo(void)
567 {
568         Header();
569         fprintf(stderr,
570           "This program is free software; you can redistribute it and/or modify\n"
571           "it under the terms of the GNU General Public License as published by\n"
572           "the Free Software Foundation; either version 2 of the License, or\n"
573           "(at your option) any later version.\n"
574           "\n"
575           "This program is distributed in the hope that it will be useful,\n"
576           "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
577           "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
578           "GNU General Public License for more details.\n"
579           "\n"
580           "You should have received a copy of the GNU General Public License\n"
581           "along with this program; if not, write to the Free Software\n"
582           "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
583           "\n");
584 } //DistInfo
585
586 ExtFunc void WriteConf(void)
587 {
588         FILE *file_out;
589
590         file_out = fopen(CONFIG_FILE, "w");
591         if (file_out == NULL) {
592                 perror("Error writing config file");
593                 exit(1);
594         }
595
596         fprintf(file_out, "### NETRIS %s Config file ###\n\n", version_string);
597
598         fclose(file_out);
599         fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE);
600 } //WriteConf
601
602 ExtFunc void HandleOption(char tag, char *value)
603 {
604         switch (tag) {
605                 case 'v':       //verbose
606                         verbose = 1;
607                         break;
608                 case 'p':       //port
609                         port = atoi(value);
610                         break;
611                 case 'c':       //min-players
612                         Game.continuous = atoi(value);
613                         break;
614                 case 'm':       //min-players
615                         minplayers = atoi(value);
616                         break;
617                 case 'x':       //max-players
618                         Game.maxplayers = atoi(value);
619                         if (Game.maxplayers >= MAX_SCREENS)
620                                 Game.maxplayers = MAX_SCREENS;
621                         break;
622                 case 'i':       //speed (of level 1)
623                         Game.initspeed = atof(value) * 1e6;
624                         break;
625                 case 's':       //seed
626                         Game.seed = atoi(value);
627                         break;
628                 case 'H':       //info
629                         DistInfo(); exit(0);
630                 case 'h':       //help
631                         Usage(); exit(0);
632                 default:
633                         break;
634         }
635 } //HandleParam
636
637 ExtFunc void ReadConf(char *filename)
638 {
639         FILE *file_in;
640         char buf[513];
641         int i;
642         char *ch;
643         char tag[81], value[81];
644
645         file_in = fopen(filename, "r");
646         if (file_in) {
647                 while (fgets(buf, 512, file_in) != NULL) {
648                         if ((ch = strchr(buf, '#')))
649                                 *ch = '\0'; // truncate string from # char
650                         for (i = strlen(buf)-1; i >= 0; i--)
651                                 if (buf[i] == ' ' || buf[i] == '\t'
652                                 || buf[i] == '\n' || buf[i] == 13)
653                                         buf[i] = '\0';
654                                 else break;
655
656                         sscanf(buf, "%80[^= \t] = %80[^\n]", tag, value);
657                         for (i = 0; options[i].name; i++){
658                                 if (!strcasecmp(options[i].name, tag)) {
659                                         HandleOption(options[i].val, value);
660                                         break;
661                                 }
662                         }
663                 }
664                 fclose(file_in);
665         } //read file
666         else {
667                 fprintf(stderr, "Unable to open config file %s.\n", filename);
668         } //defaults
669
670 } //ReadConf
671
672 ExtFunc void CatchInt(int sig)
673 {
674         siglongjmp(close_env, 1);
675 }
676
677 ExtFunc int main(int argc, char **argv)
678 {
679         char ch;
680
681         if (sigsetjmp(close_env, 1)) exit(0);
682         signal(SIGINT, CatchInt);
683         port = DEFAULT_PORT;
684         Game.maxplayers = 8;
685         Game.initspeed = DEFAULT_INTERVAL;
686         Game.seed = time(0);
687         {
688                 int i;
689
690                 for (i = 1; i < MAX_SCREENS; i++)
691                         Players[i].alive = -1;
692         }
693
694 //      if (getopt(argc, argv, "f:") == 'f')
695 //              ReadConf(optarg);
696 //      else
697         ReadConf(CONFIG_FILE);
698         while ((ch = getopt_long(argc, argv,
699                         "hHvp:i:s:c:m:x:", options, NULL)) != -1)
700                 HandleOption(ch, optarg);
701         if (optind < argc) {
702                 Usage();
703                 exit(1);
704         }
705 //      WriteConf();
706
707         Header();
708
709         {
710                 int i;
711
712                 for (i = 1; i < MAX_SCREENS; i++)
713                         memcpy(&netGen[i], &netGen[0], sizeof(EventGenRec));
714         } //setup netGen var
715
716         AtExit(CloseNets);
717
718         {
719                 int val1;
720
721                 memset(&addr, 0, sizeof(addr));
722                 addr.sin_family = AF_INET;
723                 addr.sin_port = htons(port);
724                 addr.sin_addr.s_addr = htonl(INADDR_ANY);
725                 if ((connGen.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
726                         die("socket");
727                 val1 = 1;
728                 setsockopt(connGen.fd, SOL_SOCKET, SO_REUSEADDR,
729                                 (void *)&val1, sizeof(val1));
730                 if (bind(connGen.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
731                         die("bind");
732                 if (listen(connGen.fd, 1) < 0)
733                         die("listen");
734
735                 AddEventGen(&connGen);
736         } //setup listening sock
737
738         StartServer(); //server loop
739
740         return 0;
741 }
742
743 /*
744  * vi: ts=4 ai
745  * vim: noai si
746  */