rnd-19981010-1
[rocksndiamonds.git] / src / netserv.c
1 /*
2  *   A server for a multi-player version of Tetris
3  *
4  *   Copyright (C) 1996 Roger Espel Llima <roger.espel.llima@pobox.com>
5  *
6  *   Started: 10 Oct 1996
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation. See the file COPYING for details.
11  *
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <signal.h>
21 #include <sys/socket.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <netinet/in.h>
25 #include <netinet/tcp.h>
26 #include <arpa/inet.h>
27 #include <netdb.h>
28
29 #include "netserv.h"
30
31
32
33 extern int verbose;
34
35 extern void copydown(char *, char *, int);
36 extern void fatal(char *);
37
38
39
40 static int clients = 0;
41 static int bots = 0;
42 static int onceonly = 0;
43 static int timetoplay = 0;
44 static int is_daemon = 0;
45 static int level = 5;
46 static int mode = -1;
47 static int paused = 0;
48
49 struct user
50 {
51   int fd;
52   unsigned char nick[16];
53   unsigned char number;
54   struct user *next, *nextvictim;
55   char active;
56   char introduced;
57   unsigned char readbuf[MAX_BUFFER_SIZE];
58   int nread;
59   unsigned char writbuf[MAX_BUFFER_SIZE];
60   int nwrite;
61   char playing;
62   char isbot;
63   int lines;
64   unsigned int games;
65   unsigned char action;
66   int action_received;
67 };
68
69 static struct user *user0 = NULL;
70
71 #define NEXT(u) ((u)->next ? (u)->next : user0)
72
73 static struct sockaddr_in saddr;
74 static int lfd;
75 static unsigned char realbuf[512], *buf = realbuf + 4;
76
77 static int interrupt;
78 static int tcp = -1;
79
80 static unsigned long frame_counter = 0;
81
82 static fd_set fds;
83
84 void syserr(char *s)
85 {
86   if (!is_daemon)
87     fprintf(stderr, "fatal: %s failed.\n", s);
88   exit(1);
89 }
90
91 void addtobuffer(struct user *u, unsigned char *b, int len)
92 {
93   if (u->nwrite + len >= MAX_BUFFER_SIZE)
94     fatal("Internal error: send buffer overflow");
95   memcpy(u->writbuf + u->nwrite, b, len);
96   u->nwrite += len;
97 }
98
99 void flushuser(struct user *u)
100 {
101   if (u->nwrite)
102   {
103     write(u->fd, u->writbuf, u->nwrite);
104     u->nwrite = 0;
105   }
106 }
107
108 void broadcast(struct user *except, int len, int activeonly)
109 {
110   struct user *u;
111
112   realbuf[0] = realbuf[1] = realbuf[2] = 0;
113   realbuf[3] = (unsigned char)len;
114   for (u=user0; u; u=u->next)
115     if (u != except && (u->active || !activeonly) && u->introduced)
116       addtobuffer(u, realbuf, 4 + len);
117 }
118
119 void sendtoone(struct user *to, int len)
120 {
121   realbuf[0] = realbuf[1] = realbuf[2] = 0;
122   realbuf[3] = (unsigned char)len;
123   addtobuffer(to, realbuf, 4 + len);
124 }
125
126 void dropuser(struct user *u)
127 {
128   struct user *v, *w;
129   
130   if (verbose)
131     printf("RND_SERVER: dropping client %d (%s)\n", u->number, u->nick);
132
133   if (u == user0)
134     user0 = u->next;
135   else
136   {
137     for (v=user0; v; v=v->next)
138     {
139       if (v->next && v->next == u)
140       {
141         v->next = u->next;
142         break;
143       }
144     }
145   }
146   close(u->fd);
147
148   if (u->introduced)
149   {
150     buf[0] = u->number;
151     buf[1] = OP_PLAYER_DISCONNECTED;
152     broadcast(u, 2, 0);
153   }
154
155   for (v=user0; v; v=v->next)
156   {
157     if (v->nextvictim == u)
158     {
159       for (w=NEXT(v); w!=v; w=NEXT(w))
160       {
161         if (w->active && w->playing)
162         {
163           v->nextvictim = w;
164           break;
165         }
166       }
167       if (v->nextvictim == u)
168         v->nextvictim = NULL;
169     }
170   }
171
172   if (u->isbot)
173     bots--;
174
175   free(u);
176   clients--;
177
178   if (onceonly && clients == bots)
179   {
180     if (verbose)
181     {
182       printf("RND_SERVER: no clients left\n");
183       printf("RND_SERVER: aborting\n");
184     }
185     exit(0);
186   }
187
188   if (clients == 0)
189   {
190     mode = -1;
191     level = 5;
192     timetoplay = 0;
193   }
194 }
195
196 void do_play()
197 {
198   struct user *v, *w;
199
200   for (w=user0; w; w=w->next)
201   {
202     if (w->introduced)
203     {
204       w->active = 1;
205       w->playing = 1;
206       w->lines = 0;
207       w->nextvictim = NULL;
208       for (v=NEXT(w); v!=w; v=NEXT(v))
209       {
210         if (v->introduced)
211         {
212           w->nextvictim = v;
213           break;
214         }
215       }
216     }
217   }
218
219   /*
220   if (paused)
221   {
222     paused = 0;
223     buf[1] = OP_CONT;
224     broadcast(NULL, 2, 0);
225   }
226   buf[1] = OP_START_PLAYING;
227   broadcast(NULL, 2, 0);
228   */
229
230   /* reset frame counter */
231   frame_counter = 0;
232
233   /* reset player actions */
234   for (v=user0; v; v=v->next)
235   {
236     v->action = 0;
237     v->action_received = 0;
238   }
239
240   broadcast(NULL, 10 + strlen(&buf[10])+1, 0);
241
242 }
243
244 void new_connect(int fd)
245 {
246   struct user *u, *v;
247   unsigned char nxn;
248
249   u = malloc(sizeof (struct user));
250   if (!u)
251     fatal("Out of memory");
252   u->fd = fd;
253   u->nick[0] = 0;
254   u->next = user0;
255   u->nextvictim = NULL;
256   u->active = 0;
257   u->nread = 0;
258   u->nwrite = 0;
259   u->playing = 0;
260   u->isbot = 0;
261   u->introduced = 0;
262   u->games = 0;
263   u->action = 0;
264   u->action_received = 0;
265
266   user0 = u;
267
268   nxn = 1;
269
270 again:
271   v = u->next;
272   while(v)
273   {
274     if (v->number == nxn)
275     {
276       nxn++;
277       goto again;
278     }
279     v = v->next;
280   }
281
282   u->number = nxn;
283   if (verbose)
284     printf("RND_SERVER: client %d connecting from %s\n", nxn, inet_ntoa(saddr.sin_addr));
285   clients++;
286
287   buf[0] = 0;
288   buf[1] = OP_YOUR_NUMBER;
289   buf[2] = u->number;
290   sendtoone(u, 3);
291 }
292
293 void NetworkServer(int port, int onceonly)
294 {
295   int i, sl, on;
296   struct user *u, *v, *w;
297   int mfd;
298   int r; 
299   unsigned int len;
300   struct protoent *tcpproto;
301   struct timeval tv;
302   int is_daemon = 0;
303
304 #ifndef NeXT
305   struct sigaction sact;
306 #endif
307
308   if (port == 0)
309     port = DEFAULTPORT;
310
311   if ((tcpproto = getprotobyname("tcp")) != NULL)
312     tcp = tcpproto->p_proto;
313
314 #ifdef NeXT
315   signal(SIGPIPE, SIG_IGN);
316 #else
317   sact.sa_handler = SIG_IGN;
318   sigemptyset(&sact.sa_mask);
319   sact.sa_flags = 0;
320   sigaction(SIGPIPE, &sact, NULL);
321 #endif
322
323
324   lfd = socket(PF_INET, SOCK_STREAM, 0);
325   saddr.sin_family = AF_INET;
326   saddr.sin_addr.s_addr = htonl(INADDR_ANY);
327   saddr.sin_port = htons(port);
328
329   if (lfd < 0)
330     syserr("socket");
331   on = 1;
332
333   setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int));
334   if (bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
335     syserr("bind");
336
337   listen(lfd, 5);
338
339   if (is_daemon)
340   {
341     /* become a daemon, breaking all ties with the controlling terminal */
342     verbose = 0;
343     for (i=0; i<255; i++)
344     {
345       if (i != lfd)
346         close(i);
347     }
348     if (fork())
349       exit(0);
350     setsid();
351     if (fork())
352       exit(0);
353     chdir("/");
354     /* open a fake stdin, stdout, stderr, just in case */
355     open("/dev/null", O_RDONLY);
356     open("/dev/null", O_WRONLY);
357     open("/dev/null", O_WRONLY);
358   }
359
360   if (verbose)
361   {
362     printf("rocksndiamonds network server: started up, listening on port %d\n",
363            port);
364     printf("rocksndiamonds network server: using protocol version %d.%d.%d\n",
365            PROT_VERS_1, PROT_VERS_2, PROT_VERS_3);
366   }
367
368   while(1)
369   {
370     interrupt = 0;
371
372     if (timetoplay && time(NULL) >= timetoplay)
373     {
374       buf[0] = 0;
375       do_play();
376       if (verbose)
377         printf("RND_SERVER: everyone lost... restarting game\n");
378       timetoplay = 0;
379     }
380
381     for (u=user0; u; u=u->next)
382       flushuser(u);
383
384     FD_ZERO(&fds);
385     mfd = lfd;
386     u = user0;
387     while (u)
388     {
389       FD_SET(u->fd, &fds);
390       if (u->fd > mfd)
391         mfd = u->fd;
392       u = u->next;
393     }
394     FD_SET(lfd, &fds);
395     tv.tv_sec = 0;
396     tv.tv_usec = 500000;
397     if ((sl = select(mfd + 1, &fds, NULL, NULL, &tv)) < 0)
398       if (errno != EINTR)
399         syserr("select");
400       else continue;
401     
402     if (sl < 0)
403       continue;
404
405     if (clients > 0 && clients == bots)
406     {
407       if (verbose)
408         printf("RND_SERVER: only bots left... dropping all bots\n");
409       while (user0)
410         dropuser(user0);
411       continue;
412     }
413     
414     if (sl == 0)
415       continue;
416
417     if (FD_ISSET(lfd, &fds))
418     {
419       int newfd, slen;
420
421       slen = sizeof(saddr);
422       newfd = accept(lfd, (struct sockaddr *)&saddr, &slen);
423       if (newfd < 0)
424       {
425         if (errno != EINTR)
426           syserr("accept");
427       }
428       else
429       {
430         if (tcp != -1)
431         {
432           on = 1;
433           setsockopt(newfd, tcp, TCP_NODELAY, (char *)&on, sizeof(int));
434         }
435         new_connect(newfd);
436       }
437       continue;
438     }
439
440     u = user0;
441
442     do
443     {
444       if (FD_ISSET(u->fd, &fds))
445       {
446         r = read(u->fd, u->readbuf + u->nread, MAX_BUFFER_SIZE - u->nread);
447         if (r <= 0)
448         {
449           if (verbose)
450             printf("RND_SERVER: EOF from client %d (%s)\n", u->number, u->nick);
451           dropuser(u);
452           interrupt = 1;
453           break;
454         }
455         u->nread += r;
456         while (u->nread >= 4 && u->nread >= 4 + u->readbuf[3])
457         {
458           len = u->readbuf[3];
459           if (u->readbuf[0] || u->readbuf[1] || u->readbuf[2])
460           {
461             if (verbose)
462               printf("RND_SERVER: crap from client %d (%s)\n", u->number, u->nick);
463             write(u->fd, "\033]50;kanji24\007\033#8\033(0", 19);
464             dropuser(u);
465             interrupt = 1;
466             break;
467           }
468           memcpy(buf, &u->readbuf[4], len);
469           u->nread -= 4 + len;
470           copydown(u->readbuf, u->readbuf + 4 + len, u->nread);
471
472           buf[0] = u->number;
473           if (!u->introduced && buf[1] != OP_NICKNAME)
474           {
475             if (verbose)
476               printf("RND_SERVER: !(client %d)->introduced && buf[1]==%d (expected OP_NICKNAME)\n", buf[0], buf[1]);
477
478             dropuser(u);
479             interrupt = 1;
480             break;
481           }
482
483           switch(buf[1])
484           {
485             case OP_NICKNAME:
486               if (len>16)
487                 len=16;
488               memcpy(u->nick, &buf[2], len-2);
489               u->nick[len-2] = 0;
490               for (i=0; i<len-2; i++)
491               {
492                 if (u->nick[i] < ' ' || 
493                     (u->nick[i] > 0x7e && u->nick[i] <= 0xa0))
494                 {
495                   u->nick[i] = 0;
496                   break;
497                 }
498               }
499
500               if (!u->introduced)
501               {
502                 buf[0] = u->number;
503                 buf[1] = OP_PLAYER_CONNECTED;
504                 broadcast(u, 2, 0);
505               }
506               
507               if (verbose)
508                 printf("RND_SERVER: client %d calls itself \"%s\"\n", u->number, u->nick);
509               buf[1] = OP_NICKNAME;
510               broadcast(u, len, 0);
511
512               if (!u->introduced)
513               {
514                 for (v=user0; v; v=v->next)
515                 {
516                   if (v != u && v->introduced)
517                   {
518                     buf[0] = v->number;
519                     buf[1] = OP_PLAYER_CONNECTED;
520                     buf[2] = (v->games >> 8);
521                     buf[3] = (v->games & 0xff);
522                     sendtoone(u, 4);
523                     buf[1] = OP_NICKNAME;
524                     memcpy(&buf[2], v->nick, 14);
525                     sendtoone(u, 2+strlen(v->nick));
526                   }
527                 }
528                 if (level != 5)
529                 {
530                   buf[0] = 0;
531                   buf[1] = OP_LEVEL;
532                   buf[2] = level;
533                   sendtoone(u, 3);
534                 }
535                 if (mode >= 0)
536                 {
537                   buf[1] = OP_MODE;
538                   buf[2] = mode;
539                   sendtoone(u, 3);
540                 }
541               }
542
543               u->introduced = 1;
544               break;
545
546             case OP_KILL:
547               for (v=user0; v; v=v->next)
548               {
549                 if (v->number == buf[2])
550                   break;
551               }
552               if (v)
553               {
554                 if (v->isbot)
555                 {
556                   if (verbose)
557                     printf("RND_SERVER: client %d (%s) kills bot %d (%s)\n", u->number, u->nick, v->number, v->nick);
558
559                   dropuser(v);
560                   interrupt = 1;
561                   break;
562                 }
563                 else
564                 {
565                   if (verbose)
566                     printf("RND_SERVER: client %d (%s) attempting to kill non-bot %d (%s)\n", u->number, u->nick, v->number, v->nick);
567                 }
568               }
569               break;
570
571             case OP_START_PLAYING:
572               if (verbose)
573                 printf("RND_SERVER: client %d (%s) starts game [level %d from levedir %d (%s)]\n",
574                        u->number, u->nick,
575                        (buf[2] << 8) + buf[3],
576                        (buf[4] << 8) + buf[5],
577                        &buf[6]);
578               timetoplay = 0;
579               do_play();
580               break;
581
582             case OP_MOVE_FIGURE:
583             {
584               int actions_complete = 1;
585               int last_client_nr = 0;
586
587               /* store player action */
588               for (v=user0; v; v=v->next)
589               {
590                 if (v->number == u->number)
591                 {
592                   v->action = buf[2];
593                   v->action_received = 1;
594                 }
595               }
596
597               /* check if server received action from each player */
598               for (v=user0; v; v=v->next)
599               {
600                 if (!v->action_received)
601                 {
602                   actions_complete = 0;
603                   break;
604                 }
605               }
606
607               if (!actions_complete)
608                 break;
609
610               /* broadcast actions of all players to all players */
611               for (v=user0; v; v=v->next)
612               {
613                 buf[6 + v->number-1] = v->action;
614                 v->action = 0;
615                 v->action_received = 0;
616
617                 if (v->number > last_client_nr)
618                   last_client_nr = v->number;
619               }
620
621               buf[2] = (unsigned char)((frame_counter >> 24) & 0xff);
622               buf[3] = (unsigned char)((frame_counter >> 16) & 0xff);
623               buf[4] = (unsigned char)((frame_counter >>  8) & 0xff);
624               buf[5] = (unsigned char)((frame_counter >>  0) & 0xff);
625
626               broadcast(NULL, 6 + last_client_nr, 0);
627
628               frame_counter++;
629
630               /*
631               if (verbose)
632                 printf("RND_SERVER: frame %d: client %d (%s) moves player [0x%02x]\n",
633                        frame_counter,
634                        u->number, u->nick, buf[2]);
635               */
636
637               break;
638             }
639             
640             case OP_MODE:
641               mode = buf[2];
642               if (verbose)
643                 printf("RND_SERVER: client %d (%s) sets mode %d (%s)\n", u->number, u->nick, buf[2], buf[2] == 0 ? "normal" : (buf[2] == 1 ? "fun" : "unknown"));
644               broadcast(NULL, 3, 0);
645               break;
646
647             case OP_PAUSE:
648               if (verbose)
649                 printf("RND_SERVER: client %d (%s) pauses game\n", u->number, u->nick);
650               broadcast(NULL, 2, 0);
651               paused = 1;
652               break;
653
654             case OP_CONT:
655               if (verbose)
656                 printf("RND_SERVER: client %d (%s) continues game\n", u->number, u->nick);
657               broadcast(NULL, 2, 0);
658               paused = 0;
659               break;
660
661             case OP_BOT:
662               if (!u->isbot)
663                 bots++;
664               u->isbot = 1;
665               if (verbose)
666                 printf("RND_SERVER: client %d (%s) declares itself to be a bot\n", u->number, u->nick);
667               break;
668             
669             case OP_LEVEL:
670               level = buf[2];
671               if (verbose)
672                 printf("RND_SERVER: client %d (%s) sets level %d\n", u->number, u->nick, buf[2]);
673               broadcast(NULL, 3, 0);
674               break;
675
676             case OP_LOST:
677               {
678                 struct user *won = NULL;
679
680                 if (verbose)
681                   printf("RND_SERVER: client %d (%s) has lost\n", u->number, u->nick);
682                 u->playing = 0;
683                 broadcast(u, 2, 1);
684                 i = 0;
685                 for (v=user0; v; v=v->next)
686                 {
687                   if (v->nextvictim == u)
688                   {
689                     for (w=NEXT(v); w!=v; w=NEXT(w))
690                     {
691                       if (w->active && w->playing)
692                       {
693                         v->nextvictim = w;
694                         break;
695                       }
696                     }
697                     if (v->nextvictim == u)
698                       v->nextvictim = NULL;
699                   }
700                 }
701                 for (v=user0; v; v=v->next)
702                 {
703                   if (v->playing)
704                   {
705                     i++;
706                     won = v;
707                   }
708                 }
709                 if (i == 1)
710                 {
711                   buf[0] = won->number;
712                   buf[1] = OP_WON;
713                   won->games++;
714                   broadcast(NULL, 2, 0);
715                 }
716                 else if (i == 0)
717                 {
718                   buf[0] = u->number;
719                   buf[1] = OP_WON;
720                   u->games++;
721                   broadcast(NULL, 2, 0);
722                 }
723                 if (i < 2 && clients > 1)
724                   timetoplay = time(NULL) + 4;
725               }
726               break;
727             
728             case OP_ZERO:
729               broadcast(NULL, 2, 0);
730               if (verbose)
731                 printf("RND_SERVER: client %d (%s) resets the game counters\n", u->number, u->nick);
732               for (v=user0; v; v=v->next)
733                 v->games = 0;
734               break;
735
736             case OP_CLEAR:
737             case OP_GROW:
738               broadcast(u, 2, 1);
739               break;
740
741             case OP_MSG:
742               buf[len] = '\0';
743               if (verbose)
744                 printf("RND_SERVER: client %d (%s) sends message: %s\n", u->number, u->nick, &buf[2]);
745               broadcast(u, len, 0);
746               break;
747
748             case OP_NUMBER_WANTED:
749             {
750               int nr_wanted = buf[2];
751               int nr_is_free = 1;
752
753               if (verbose)
754                 printf("RND_SERVER: client %d (%s) wants to switch to # %d\n",
755                        u->number, u->nick, nr_wanted);
756
757               for (v=user0; v; v=v->next)
758               {
759                 if (v->number == nr_wanted)
760                 {
761                   nr_is_free = 0;
762                   break;
763                 }
764               }
765
766               if (verbose)
767               {
768                 if (nr_is_free)
769                   printf("RND_SERVER: client %d (%s) switches to # %d\n",
770                          u->number, u->nick, nr_wanted);
771                 else if (u->number == nr_wanted)
772                   printf("RND_SERVER: client %d (%s) still has # %d\n",
773                          u->number, u->nick, nr_wanted);
774                 else
775                   printf("RND_SERVER: client %d (%s) cannot switch (client %d still exists)\n",
776                          u->number, u->nick, nr_wanted);
777               }
778
779               if (nr_is_free)
780                 u->number = nr_wanted;
781
782               buf[0] = 0;
783               buf[1] = OP_NUMBER_WANTED;
784               buf[2] = nr_wanted;
785               buf[3] = u->number;
786               sendtoone(u, 4);
787               break;
788             }
789
790             case OP_PROTOCOL_VERSION:
791               if (len != 5 || buf[2] != PROT_VERS_1 || buf[3] != PROT_VERS_2)
792               {
793                 if (verbose)
794                   printf("RND_SERVER: client %d (%s) has wrong protocol version %d.%d.%d\n", u->number, u->nick, buf[2], buf[3], buf[4]);
795
796                 buf[0] = 0;
797                 buf[1] = OP_BADVERS;
798                 buf[2] = PROT_VERS_1;
799                 buf[3] = PROT_VERS_2;
800                 buf[4] = PROT_VERS_3;
801                 sendtoone(u, 5);
802                 flushuser(u);
803
804                 dropuser(u);
805                 interrupt = 1;
806               }
807               else
808               {
809                 if (verbose)
810                   printf("RND_SERVER: client %d (%s) uses protocol version %d.%d.%d\n", u->number, u->nick, buf[2], buf[3], buf[4]);
811               }
812               break;
813
814             case OP_LINES:
815               if (len != 3)
816               {
817                 if (verbose)
818                   printf("RND_SERVER: client %d (%s) sends crap for an OP_LINES\n", u->number, u->nick);
819
820                 dropuser(u);
821                 interrupt = 1;
822                 break;
823               }
824               if (u->nextvictim)
825               {
826                 if (verbose)
827                   printf("RND_SERVER: client %d (%s) sends %d %s to client %d (%s)\n", u->number, u->nick, (int)buf[2], buf[2] == 1 ? "line" : "lines", u->nextvictim->number, u->nextvictim->nick);
828                 sendtoone(u->nextvictim, 3);
829                 buf[3] = u->nextvictim->number;
830                 buf[1] = OP_LINESTO;
831                 broadcast(u->nextvictim, 4, 1);
832                 for (v=NEXT(u->nextvictim); v!=u->nextvictim; v=NEXT(v))
833                 {
834                   if (v->active && v != u && v->playing)
835                   {
836                     u->nextvictim = v;
837                     break;
838                   }
839                 }
840               }
841               else if (verbose)
842                 printf("RND_SERVER: client %d (%s) makes %d %s but has no victim\n", u->number, u->nick, (int)buf[2], buf[2] == 1 ? "line" : "lines");
843               break;
844             
845             default:
846               if (verbose)
847                 printf("RND_SERVER: opcode %d from client %d (%s) not understood\n", buf[0], u->number, u->nick);
848           }
849         }
850       }
851
852       if (u && !interrupt)
853         u = u->next;
854     }
855     while (u && !interrupt);
856   }
857 }