rnd-19981006-1
[rocksndiamonds.git] / src / network.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  network.c                                               *
12 ***********************************************************/
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <signal.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/wait.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26 #include <errno.h>
27
28 #include "network.h"
29 #include "game.h"
30 #include "tape.h"
31 #include "files.h"
32 #include "tools.h"
33 #include "misc.h"
34
35 int norestart = 0;
36 int nospeedup = 0;
37
38 #define DEFAULTPORT 19503
39
40 #define PROT_VERS_1 1
41 #define PROT_VERS_2 0
42 #define PROT_VERS_3 1
43
44 #define OP_NICK 1
45 #define OP_PLAY 2
46 #define OP_MOVE 3
47 #define OP_NRWANTED 4
48 #define OP_LOST 5
49 #define OP_GONE 6
50 #define OP_CLEAR 7
51 #define OP_NEW 8
52 #define OP_LINES 9
53 #define OP_GROW 10
54 #define OP_MODE 11
55 #define OP_LEVEL 12
56 #define OP_BOT 13
57 #define OP_KILL 14
58 #define OP_PAUSE 15
59 #define OP_CONT 16
60 #define OP_VERSION 17
61 #define OP_BADVERS 18
62 #define OP_MSG 19
63 #define OP_YOUARE 20
64 #define OP_LINESTO 21
65 #define OP_WON 22
66 #define OP_ZERO 23
67
68 #define MAXNICKLEN 14
69
70 struct user
71 {
72   byte nr;
73   char name[MAXNICKLEN+2];
74   struct user *next;
75 };
76
77 struct user me =
78 {
79   0,
80   "no name",
81   NULL
82 };
83
84 /* server stuff */
85
86 #define BUFLEN          4096
87
88 int sfd;
89 unsigned char realbuf[512], readbuf[BUFLEN], writbuf[BUFLEN];
90 unsigned char *buf = realbuf + 4;
91 int nread = 0, nwrite = 0;
92
93 /* like memcpy, but guaranteed to handle overlap when s <= t */
94 void copydown(char *s, char *t, int n)
95 {
96   for (; n; n--)
97     *(s++) = *(t++);
98 }
99
100 void sysmsg(char *s)
101 {
102   if (verbose)
103   {
104     printf("** %s\n", s);
105     fflush(stdout);
106   }
107 }
108
109 void fatal(char *s)
110 {
111   fprintf(stderr, "%s.\n", s);
112   exit(1);
113 }
114
115 void *mmalloc(int n)
116 {
117   void *r;
118
119   r = malloc(n);
120   if (r == NULL)
121     fatal("Out of memory");
122   return r;
123 }
124
125 void u_sleep(int i)
126 {
127   struct timeval tm;
128   tm.tv_sec = i / 1000000;
129   tm.tv_usec = i % 1000000;
130   select(0, NULL, NULL, NULL, &tm);
131 }
132
133 void flushbuf()
134 {
135   if (nwrite)
136   {
137     write(sfd, writbuf, nwrite);
138     nwrite = 0;
139   }
140 }
141
142 void sendbuf(int len)
143 {
144   if (!standalone)
145   {
146     realbuf[0] = realbuf[1] = realbuf[2] = 0;
147     realbuf[3] = (unsigned char)len;
148     buf[0] = 0;
149     if (nwrite + 4 + len >= BUFLEN)
150       fatal("Internal error: send buffer overflow");
151     memcpy(writbuf + nwrite, realbuf, 4 + len);
152     nwrite += 4 + len;
153
154
155     flushbuf();
156
157
158   }
159 }
160
161 struct user *finduser(unsigned char c)
162 {
163   struct user *u;
164
165   for (u = &me; u; u = u->next)
166     if (u->nr == c)
167       return u;
168   
169   fatal("Protocol error: reference to non-existing user");
170   return NULL; /* so that gcc -Wall doesn't complain */
171 }
172
173 char *get_user_name(unsigned char c)
174 {
175   struct user *u;
176
177   if (c == 0)
178     return("the server");
179   else if (c == me.nr)
180     return("you");
181   else
182     for (u = &me; u; u = u->next)
183       if (u->nr == c && u->name && strlen(u->name))
184         return(u->name);
185
186   return("no name");
187 }
188
189 void startserver()
190 {
191   char *options[2];
192   int n = 0;
193
194   options[0] = options[1] = NULL;
195   if (verbose)
196     options[n++] = "-v";
197   if (nospeedup)
198     options[n++] = "-nospeedup";
199
200   switch (fork())
201   {
202     case 0:
203       execlp(
204 #ifdef XTRISPATH
205       XTRISPATH "/rnd_server",
206 #else
207       "rnd_server",
208 #endif
209       "rnd_server", "-once", options[0], options[1], NULL);
210
211       fprintf(stderr, "Can't start server '%s'.\n",
212 #ifdef XTRISPATH
213         XTRISPATH "/rnd_server"
214 #else
215         "rnd_server"
216 #endif
217               );
218
219       _exit(1);
220     
221     case -1:
222       fatal("fork() failed");
223     
224     default:
225       return;
226   }
227 }
228
229 BOOL ConnectToServer(char *host, int port)
230 {
231   struct hostent *hp;
232   struct sockaddr_in s;
233   struct protoent *tcpproto;
234   int on = 1, i;
235
236   if (host)
237   {
238     if ((s.sin_addr.s_addr = inet_addr(host)) == -1)
239     {
240       hp = gethostbyname(host);
241       if (!hp)
242         fatal("Host not found");
243       s.sin_addr = *(struct in_addr *)(hp->h_addr_list[0]);
244     }
245   }
246   else
247     s.sin_addr.s_addr = inet_addr("127.0.0.1");
248
249   if (port == 0)
250     port = DEFAULTPORT;
251
252   s.sin_port = htons(port);
253   s.sin_family = AF_INET;
254   sfd = socket(PF_INET, SOCK_STREAM, 0);
255   if (sfd < 0)
256     fatal("Out of file descriptors");
257   if ((tcpproto = getprotobyname("tcp")) != NULL)
258     setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
259
260   if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) < 0)
261   {
262     if (!host)
263     {
264       printf("No rocksndiamonds server on localhost - starting up one ...\n");
265       startserver();
266       for (i=0; i<6; i++)
267       {
268         u_sleep(500000);
269         close(sfd);
270         sfd = socket(PF_INET, SOCK_STREAM, 0);
271         if (sfd < 0)
272           fatal("Out of file descriptors");
273         setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
274         if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) >= 0)
275           break;
276       }
277       if (i==6)
278         fatal("Can't connect to server");
279     }
280     else
281       fatal("Can't connect to server");
282   }
283
284   return(TRUE);
285 }
286
287 void SendToServer_Nickname(char *nickname)
288 {
289   static char msgbuf[300];
290
291   buf[1] = OP_NICK;
292   memcpy(&buf[2], nickname, strlen(nickname));
293   sendbuf(2 + strlen(nickname));
294   sprintf(msgbuf, "you set your nick to \"%s\"", nickname);
295   sysmsg(msgbuf);
296 }
297
298 void SendToServer_ProtocolVersion()
299 {
300   buf[1] = OP_VERSION;
301   buf[2] = PROT_VERS_1;
302   buf[3] = PROT_VERS_2;
303   buf[4] = PROT_VERS_3;
304
305   sendbuf(5);
306 }
307
308 void SendToServer_NrWanted(int nr_wanted)
309 {
310   buf[1] = OP_NRWANTED;
311   buf[2] = nr_wanted;
312
313   sendbuf(3);
314 }
315
316 void SendToServer_StartPlaying()
317 {
318   unsigned long new_random_seed = InitRND(NEW_RANDOMIZE);
319
320   buf[1] = OP_PLAY;
321   buf[2] = (byte)(level_nr >> 8);
322   buf[3] = (byte)(level_nr & 0xff);
323   buf[4] = (byte)(leveldir_nr >> 8);
324   buf[5] = (byte)(leveldir_nr & 0xff);
325
326   buf[6] = (unsigned char)((new_random_seed >> 24) & 0xff);
327   buf[7] = (unsigned char)((new_random_seed >> 16) & 0xff);
328   buf[8] = (unsigned char)((new_random_seed >>  8) & 0xff);
329   buf[9] = (unsigned char)((new_random_seed >>  0) & 0xff);
330
331   strcpy(&buf[10], leveldir[leveldir_nr].name);
332
333   sendbuf(10 + strlen(leveldir[leveldir_nr].name)+1);
334 }
335
336 void SendToServer_MovePlayer(byte player_action)
337 {
338   buf[1] = OP_MOVE;
339   buf[2] = player_action;
340
341   sendbuf(3);
342 }
343
344 void handlemessages()
345 {
346   unsigned int len;
347   struct user *u, *v = NULL;
348   static char msgbuf[300];
349
350   while (nread >= 4 && nread >= 4 + readbuf[3])
351   {
352     len = readbuf[3];
353     if (readbuf[0] || readbuf[1] || readbuf[2])
354       fatal("Wrong server line length");
355
356     memcpy(buf, &readbuf[4], len);
357     nread -= 4 + len;
358     copydown(readbuf, readbuf + 4 + len, nread);
359
360     switch(buf[1])
361     {
362       case OP_YOUARE:
363       {
364         int new_client_nr = buf[2];
365         int new_index_nr = new_client_nr - 1;
366
367         printf("OP_YOUARE: %d\n", buf[0]);
368         me.nr = new_client_nr;
369
370         stored_player[new_index_nr] = *local_player;
371         local_player = &stored_player[new_index_nr];
372
373         TestPlayer = new_index_nr;
374
375         if (me.nr > MAX_PLAYERS)
376           Error(ERR_EXIT, "sorry - no more than %d players", MAX_PLAYERS);
377
378         sprintf(msgbuf, "you get client # %d", new_client_nr);
379         sysmsg(msgbuf);
380
381         break;
382       }
383
384       case OP_NRWANTED:
385       {
386         int client_nr_wanted = buf[2];
387         int new_client_nr = buf[3];
388         int new_index_nr = new_client_nr - 1;
389
390         printf("OP_NRWANTED: %d\n", buf[0]);
391
392         if (new_client_nr != client_nr_wanted)
393         {
394           char *color[] = { "yellow", "red", "green", "blue" };
395
396           sprintf(msgbuf, "Sorry ! You are %s player !",
397                   color[new_index_nr]);
398           Request(msgbuf, REQ_CONFIRM);
399
400           sprintf(msgbuf, "cannot switch -- you keep client # %d",
401                   new_client_nr);
402           sysmsg(msgbuf);
403         }
404         else
405         {
406           if (me.nr != client_nr_wanted)
407             sprintf(msgbuf, "switching to client # %d", new_client_nr);
408           else
409             sprintf(msgbuf, "keeping client # %d", new_client_nr);
410           sysmsg(msgbuf);
411
412           me.nr = new_client_nr;
413
414           stored_player[new_index_nr] = *local_player;
415           local_player = &stored_player[new_index_nr];
416
417           TestPlayer = new_index_nr;
418         }
419
420         break;
421       }
422
423       case OP_NEW:
424         printf("OP_NEW: %d\n", buf[0]);
425         sprintf(msgbuf, "new client %d connected", buf[0]);
426         sysmsg(msgbuf);
427
428         for (u = &me; u; u = u->next)
429         {
430           if (u->nr == buf[0])
431             Error(ERR_EXIT, "multiplayer server sent duplicate player id");
432           else
433             v = u;
434         }
435
436         v->next = u = mmalloc(sizeof(struct user));
437         u->nr = buf[0];
438         u->name[0] = '\0';
439         u->next = NULL;
440
441         break;
442
443       case OP_NICK:
444         printf("OP_NICK: %d\n", buf[0]);
445         u = finduser(buf[0]);
446         buf[len] = 0;
447         sprintf(msgbuf, "client %d calls itself \"%s\"", buf[0], &buf[2]);
448         sysmsg(msgbuf);
449         strncpy(u->name, &buf[2], MAXNICKLEN);
450         break;
451       
452       case OP_GONE:
453         printf("OP_GONE: %d\n", buf[0]);
454         u = finduser(buf[0]);
455         sprintf(msgbuf, "client %d (%s) disconnected",
456                 buf[0], get_user_name(buf[0]));
457         sysmsg(msgbuf);
458
459         for (v = &me; v; v = v->next)
460           if (v->next == u)
461             v->next = u->next;
462         free(u);
463
464         break;
465
466       case OP_BADVERS:
467         Error(ERR_RETURN, "protocol version mismatch");
468         Error(ERR_EXIT, "server expects %d.%d.x instead of %d.%d.%d",
469               buf[2], buf[3], PROT_VERS_1, PROT_VERS_2, PROT_VERS_3);
470         break;
471
472       case OP_PLAY:
473       {
474         int new_level_nr, new_leveldir_nr;
475         unsigned long new_random_seed;
476         unsigned char *new_leveldir_name;
477
478         new_level_nr = (buf[2] << 8) + buf[3];
479         new_leveldir_nr = (buf[4] << 8) + buf[5];
480         new_random_seed =
481           (buf[6] << 24) | (buf[7] << 16) | (buf[8] << 8) | (buf[9]);
482         new_leveldir_name = &buf[10];
483
484         printf("OP_PLAY: %d\n", buf[0]);
485         sprintf(msgbuf, "client %d starts game [level %d from levedir %d (%s)]\n",
486                 buf[0],
487                 new_level_nr,
488                 new_leveldir_nr,
489                 new_leveldir_name);
490         sysmsg(msgbuf);
491
492
493         if (strcmp(leveldir[new_leveldir_nr].name, new_leveldir_name) != 0)
494           Error(ERR_RETURN, "no such level directory: '%s'",new_leveldir_name);
495
496         leveldir_nr = new_leveldir_nr;
497
498         local_player->leveldir_nr = leveldir_nr;
499         LoadPlayerInfo(PLAYER_LEVEL);
500         SavePlayerInfo(PLAYER_SETUP);
501
502         level_nr = new_level_nr;
503
504         TapeErase();
505         LoadLevelTape(level_nr);
506
507         GetPlayerConfig();
508         LoadLevel(level_nr);
509
510         if (autorecord_on)
511           TapeStartRecording();
512
513         tape.random_seed = new_random_seed;
514
515         InitRND(tape.random_seed);
516
517         /*
518         printf("tape.random_seed == %d\n", tape.random_seed);
519         */
520
521         game_status = PLAYING;
522         InitGame();
523
524         break;
525       }
526
527       case OP_MOVE:
528       {
529         int frame_nr;
530         int i;
531
532         frame_nr =
533           (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | (buf[5]);
534
535         if (frame_nr != FrameCounter)
536         {
537           Error(ERR_RETURN, "client and servers frame counters out of sync");
538           Error(ERR_RETURN, "frame counter of client is %d", FrameCounter);
539           Error(ERR_RETURN, "frame counter of server is %d", frame_nr);
540           Error(ERR_EXIT,   "this should not happen -- please debug");
541         }
542
543         for (i=0; i<MAX_PLAYERS; i++)
544         {
545           if (stored_player[i].active)
546             network_player_action[i] = buf[6 + i];
547         }
548
549         network_player_action_received = TRUE;
550
551         sprintf(msgbuf, "frame %d: client %d moves player [0x%02x]",
552                 FrameCounter, buf[0], buf[2]);
553         sysmsg(msgbuf);
554
555         break;
556       }
557
558       case OP_PAUSE:
559         printf("OP_PAUSE: %d\n", buf[0]);
560         sprintf(msgbuf, "client %d pauses game", buf[0]);
561         sysmsg(msgbuf);
562         break;
563
564       case OP_CONT:
565         printf("OP_CONT: %d\n", buf[0]);
566         sprintf(msgbuf, "client %d continues game", buf[0]);
567         sysmsg(msgbuf);
568         break;
569
570       case OP_WON:
571         printf("OP_WON: %d\n", buf[0]);
572         sprintf(msgbuf, "client %d wins the game", buf[0]);
573         sysmsg(msgbuf);
574         break;
575
576       case OP_ZERO:
577         printf("OP_ZERO: %d\n", buf[0]);
578         sprintf(msgbuf, "client %d resets game counters", buf[0]);
579         sysmsg(msgbuf);
580         break;
581
582       case OP_MSG:
583         printf("OP_MSG: %d\n", buf[0]);
584         sprintf(msgbuf, "client %d sends message", buf[0]);
585         break;
586       
587       case OP_LOST:
588         printf("OP_MSG: %d\n", buf[0]);
589         sprintf(msgbuf, "client %d has lost", buf[0]);
590         break;
591       
592       case OP_LEVEL:
593         printf("OP_MSG: %d\n", buf[0]);
594         sprintf(msgbuf, "client %d sets level to %d", buf[0], buf[2]);
595         break;
596     }
597   }
598
599   fflush(stdout);
600 }
601
602 void HandleNetworking()
603 {
604   static struct timeval tv = { 0, 0 };
605   fd_set rfds;
606   int r = 0;
607
608   if (standalone)
609     return;
610
611   flushbuf();
612
613   FD_ZERO(&rfds);
614   FD_SET(sfd, &rfds);
615
616   r = select(sfd + 1, &rfds, NULL, NULL, &tv);
617
618   if (r < 0 && errno != EINTR)
619   {
620     perror("select");
621     fatal("fatal: select() failed");
622   }
623
624   if (r < 0)
625     FD_ZERO(&rfds);
626
627   if (FD_ISSET(sfd, &rfds))
628   {
629     int r;
630
631     r = read(sfd, readbuf + nread, BUFLEN - nread);
632
633     if (r < 0)
634       fatal("Error reading from server");
635     if (r == 0)
636       fatal("Connection to server lost");
637     nread += r;
638
639     handlemessages();
640   }
641 }