rnd-19981005-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
156 struct user *finduser(unsigned char c)
157 {
158   struct user *u;
159
160   for (u = &me; u; u = u->next)
161     if (u->nr == c)
162       return u;
163   
164   fatal("Protocol error: reference to non-existing user");
165   return NULL; /* so that gcc -Wall doesn't complain */
166 }
167
168 char *get_user_name(unsigned char c)
169 {
170   struct user *u;
171
172   if (c == 0)
173     return("the server");
174   else if (c == me.nr)
175     return("you");
176   else
177     for (u = &me; u; u = u->next)
178       if (u->nr == c && u->name && strlen(u->name))
179         return(u->name);
180
181   return("no name");
182 }
183
184 void startserver()
185 {
186   char *options[2];
187   int n = 0;
188
189   options[0] = options[1] = NULL;
190   if (verbose)
191     options[n++] = "-v";
192   if (nospeedup)
193     options[n++] = "-nospeedup";
194
195   switch (fork())
196   {
197     case 0:
198       execlp(
199 #ifdef XTRISPATH
200       XTRISPATH "/rnd_server",
201 #else
202       "rnd_server",
203 #endif
204       "rnd_server", "-once", options[0], options[1], NULL);
205
206       fprintf(stderr, "Can't start server '%s'.\n",
207 #ifdef XTRISPATH
208         XTRISPATH "/rnd_server"
209 #else
210         "rnd_server"
211 #endif
212               );
213
214       _exit(1);
215     
216     case -1:
217       fatal("fork() failed");
218     
219     default:
220       return;
221   }
222 }
223
224 BOOL ConnectToServer(char *host, int port)
225 {
226   struct hostent *hp;
227   struct sockaddr_in s;
228   struct protoent *tcpproto;
229   int on = 1, i;
230
231   if (host)
232   {
233     if ((s.sin_addr.s_addr = inet_addr(host)) == -1)
234     {
235       hp = gethostbyname(host);
236       if (!hp)
237         fatal("Host not found");
238       s.sin_addr = *(struct in_addr *)(hp->h_addr_list[0]);
239     }
240   }
241   else
242     s.sin_addr.s_addr = inet_addr("127.0.0.1");
243
244   if (port == 0)
245     port = DEFAULTPORT;
246
247   s.sin_port = htons(port);
248   s.sin_family = AF_INET;
249   sfd = socket(PF_INET, SOCK_STREAM, 0);
250   if (sfd < 0)
251     fatal("Out of file descriptors");
252   if ((tcpproto = getprotobyname("tcp")) != NULL)
253     setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
254
255   if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) < 0)
256   {
257     if (!host)
258     {
259       printf("No rocksndiamonds server on localhost - starting up one ...\n");
260       startserver();
261       for (i=0; i<6; i++)
262       {
263         u_sleep(500000);
264         close(sfd);
265         sfd = socket(PF_INET, SOCK_STREAM, 0);
266         if (sfd < 0)
267           fatal("Out of file descriptors");
268         setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
269         if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) >= 0)
270           break;
271       }
272       if (i==6)
273         fatal("Can't connect to server");
274     }
275     else
276       fatal("Can't connect to server");
277   }
278
279   return(TRUE);
280 }
281
282 void SendToServer_Nickname(char *nickname)
283 {
284   static char msgbuf[300];
285
286   buf[1] = OP_NICK;
287   memcpy(&buf[2], nickname, strlen(nickname));
288   sendbuf(2 + strlen(nickname));
289   sprintf(msgbuf, "you set your nick to \"%s\"", nickname);
290   sysmsg(msgbuf);
291 }
292
293 void SendToServer_ProtocolVersion()
294 {
295   buf[1] = OP_VERSION;
296   buf[2] = PROT_VERS_1;
297   buf[3] = PROT_VERS_2;
298   buf[4] = PROT_VERS_3;
299   sendbuf(5);
300 }
301
302 void SendToServer_NrWanted(int nr_wanted)
303 {
304   buf[1] = OP_NRWANTED;
305   buf[2] = nr_wanted;
306   sendbuf(3);
307 }
308
309 void SendToServer_StartPlaying()
310 {
311   buf[1] = OP_PLAY;
312   buf[2] = (byte)(level_nr >> 8);
313   buf[3] = (byte)(level_nr & 0xff);
314   buf[4] = (byte)(leveldir_nr >> 8);
315   buf[5] = (byte)(leveldir_nr & 0xff);
316   strcpy(&buf[6], leveldir[leveldir_nr].name);
317   sendbuf(strlen(leveldir[leveldir_nr].name)+1 + 6);
318 }
319
320 void SendToServer_MovePlayer(byte player_action, unsigned long frame_nr)
321 {
322   buf[1] = OP_MOVE;
323   buf[2] = player_action;
324
325   sendbuf(3);
326
327   /*
328   buf[3] = (byte)((frame_nr >> 24) & 0xff);
329   buf[4] = (byte)((frame_nr >> 16) & 0xff);
330   buf[5] = (byte)((frame_nr >>  8) & 0xff);
331   buf[6] = (byte)((frame_nr >>  0) & 0xff);
332
333   sendbuf(7);
334   */
335
336   /*
337   printf("%d: %x, %x, %x, %x\n", frame_nr, buf[3], buf[4], buf[5], buf[6]);
338   */
339
340
341
342   flushbuf();
343
344
345
346 }
347
348 void handlemessages()
349 {
350   unsigned int len;
351   struct user *u, *v = NULL;
352   static char msgbuf[300];
353
354   while (nread >= 4 && nread >= 4 + readbuf[3])
355   {
356     len = readbuf[3];
357     if (readbuf[0] || readbuf[1] || readbuf[2])
358       fatal("Wrong server line length");
359
360     memcpy(buf, &readbuf[4], len);
361     nread -= 4 + len;
362     copydown(readbuf, readbuf + 4 + len, nread);
363
364     switch(buf[1])
365     {
366       case OP_YOUARE:
367       {
368         int new_client_nr = buf[2];
369         int new_index_nr = new_client_nr - 1;
370
371         printf("OP_YOUARE: %d\n", buf[0]);
372         me.nr = new_client_nr;
373
374         stored_player[new_index_nr] = *local_player;
375         local_player = &stored_player[new_index_nr];
376
377         TestPlayer = new_index_nr;
378
379         if (me.nr > MAX_PLAYERS)
380           Error(ERR_EXIT, "sorry - no more than %d players", MAX_PLAYERS);
381
382         sprintf(msgbuf, "you get client # %d", new_client_nr);
383         sysmsg(msgbuf);
384
385         break;
386       }
387
388       case OP_NRWANTED:
389       {
390         int client_nr_wanted = buf[2];
391         int new_client_nr = buf[3];
392         int new_index_nr = new_client_nr - 1;
393
394         printf("OP_NRWANTED: %d\n", buf[0]);
395
396         if (new_client_nr != client_nr_wanted)
397         {
398           char *color[] = { "yellow", "red", "green", "blue" };
399
400           sprintf(msgbuf, "Sorry ! You are %s player !",
401                   color[new_index_nr]);
402           Request(msgbuf, REQ_CONFIRM);
403
404           sprintf(msgbuf, "cannot switch -- you keep client # %d",
405                   new_client_nr);
406           sysmsg(msgbuf);
407         }
408         else
409         {
410           if (me.nr != client_nr_wanted)
411             sprintf(msgbuf, "switching to client # %d", new_client_nr);
412           else
413             sprintf(msgbuf, "keeping client # %d", new_client_nr);
414           sysmsg(msgbuf);
415
416           me.nr = new_client_nr;
417
418           stored_player[new_index_nr] = *local_player;
419           local_player = &stored_player[new_index_nr];
420
421           TestPlayer = new_index_nr;
422         }
423
424         break;
425       }
426
427       case OP_NEW:
428         printf("OP_NEW: %d\n", buf[0]);
429         sprintf(msgbuf, "new client %d connected", buf[0]);
430         sysmsg(msgbuf);
431
432         for (u = &me; u; u = u->next)
433         {
434           if (u->nr == buf[0])
435             Error(ERR_EXIT, "multiplayer server sent duplicate player id");
436           else
437             v = u;
438         }
439
440         v->next = u = mmalloc(sizeof(struct user));
441         u->nr = buf[0];
442         u->name[0] = '\0';
443         u->next = NULL;
444
445         break;
446
447       case OP_NICK:
448         printf("OP_NICK: %d\n", buf[0]);
449         u = finduser(buf[0]);
450         buf[len] = 0;
451         sprintf(msgbuf, "client %d calls itself \"%s\"", buf[0], &buf[2]);
452         sysmsg(msgbuf);
453         strncpy(u->name, &buf[2], MAXNICKLEN);
454         break;
455       
456       case OP_GONE:
457         printf("OP_GONE: %d\n", buf[0]);
458         u = finduser(buf[0]);
459         sprintf(msgbuf, "client %d (%s) disconnected",
460                 buf[0], get_user_name(buf[0]));
461         sysmsg(msgbuf);
462
463         for (v = &me; v; v = v->next)
464           if (v->next == u)
465             v->next = u->next;
466         free(u);
467
468         break;
469
470       case OP_BADVERS:
471         Error(ERR_RETURN, "protocol version mismatch");
472         Error(ERR_EXIT, "server expects %d.%d.x instead of %d.%d.%d",
473               buf[2], buf[3], PROT_VERS_1, PROT_VERS_2, PROT_VERS_3);
474         break;
475
476       case OP_PLAY:
477         printf("OP_PLAY: %d\n", buf[0]);
478         sprintf(msgbuf, "client %d starts game [level %d from levedir %d (%s)]\n",
479                 buf[0],
480                 (buf[2] << 8) + buf[3],
481                 (buf[4] << 8) + buf[5],
482                 &buf[6]);
483         sysmsg(msgbuf);
484
485         if (strcmp(leveldir[(buf[4] << 8) + buf[5]].name, &buf[6]) == 0)
486         {
487           leveldir_nr = (buf[4] << 8) + buf[5];
488
489           local_player->leveldir_nr = leveldir_nr;
490           LoadPlayerInfo(PLAYER_LEVEL);
491           SavePlayerInfo(PLAYER_SETUP);
492
493           level_nr = (buf[2] << 8) + buf[3];
494
495           TapeErase();
496           LoadLevelTape(level_nr);
497
498           GetPlayerConfig();
499           LoadLevel(level_nr);
500
501           {
502             if (autorecord_on)
503               TapeStartRecording();
504
505             game_status = PLAYING;
506             InitGame();
507           }
508         }
509         else
510         {
511           Error(ERR_RETURN, "no such level directory: '%s'", &buf[6]);
512         }
513         break;
514
515       case OP_MOVE:
516       {
517         int frame_nr;
518         int i;
519
520         frame_nr =
521           (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | (buf[5]);
522
523         for (i=0; i<MAX_PLAYERS; i++)
524         {
525           if (stored_player[i].active)
526             network_player_action[i] = buf[6 + i];
527         }
528
529         network_player_action_stored = TRUE;
530
531         /*
532         printf("FrameCounter == %d, frame_nr = %d\n",
533                FrameCounter, frame_nr);
534         */
535
536         /*
537         if (buf[2])
538         */
539
540
541         /*
542         printf("OP_MOVE: %d\n", buf[0]);
543         */
544
545         sprintf(msgbuf, "frame %d: client %d moves player [0x%02x]",
546                 FrameCounter, buf[0], buf[2]);
547         sysmsg(msgbuf);
548
549         break;
550       }
551
552       case OP_PAUSE:
553         printf("OP_PAUSE: %d\n", buf[0]);
554         sprintf(msgbuf, "client %d pauses game", buf[0]);
555         sysmsg(msgbuf);
556         break;
557
558       case OP_CONT:
559         printf("OP_CONT: %d\n", buf[0]);
560         sprintf(msgbuf, "client %d continues game", buf[0]);
561         sysmsg(msgbuf);
562         break;
563
564       case OP_WON:
565         printf("OP_WON: %d\n", buf[0]);
566         sprintf(msgbuf, "client %d wins the game", buf[0]);
567         sysmsg(msgbuf);
568         break;
569
570       case OP_ZERO:
571         printf("OP_ZERO: %d\n", buf[0]);
572         sprintf(msgbuf, "client %d resets game counters", buf[0]);
573         sysmsg(msgbuf);
574         break;
575
576       case OP_MSG:
577         printf("OP_MSG: %d\n", buf[0]);
578         sprintf(msgbuf, "client %d sends message", buf[0]);
579         break;
580       
581       case OP_LOST:
582         printf("OP_MSG: %d\n", buf[0]);
583         sprintf(msgbuf, "client %d has lost", buf[0]);
584         break;
585       
586       case OP_LEVEL:
587         printf("OP_MSG: %d\n", buf[0]);
588         sprintf(msgbuf, "client %d sets level to %d", buf[0], buf[2]);
589         break;
590     }
591   }
592
593   fflush(stdout);
594 }
595
596 void HandleNetworking()
597 {
598   static struct timeval tv = { 0, 0 };
599   fd_set rfds;
600   int r = 0;
601
602   if (standalone)
603     return;
604
605   flushbuf();
606
607   FD_ZERO(&rfds);
608   FD_SET(sfd, &rfds);
609
610   r = select(sfd + 1, &rfds, NULL, NULL, &tv);
611
612   if (r < 0 && errno != EINTR)
613   {
614     perror("select");
615     fatal("fatal: select() failed");
616   }
617
618   if (r < 0)
619     FD_ZERO(&rfds);
620
621   if (FD_ISSET(sfd, &rfds))
622   {
623     int r;
624
625     r = read(sfd, readbuf + nread, BUFLEN - nread);
626
627     if (r < 0)
628       fatal("Error reading from server");
629     if (r == 0)
630       fatal("Connection to server lost");
631     nread += r;
632
633     handlemessages();
634   }
635 }