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