1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
18 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <arpa/inet.h>
37 #define DEFAULTPORT 19503
72 char name[MAXNICKLEN+2];
88 unsigned char realbuf[512], readbuf[BUFLEN], writbuf[BUFLEN];
89 unsigned char *buf = realbuf + 4;
90 int nread = 0, nwrite = 0;
92 /* like memcpy, but guaranteed to handle overlap when s <= t */
93 void copydown(char *s, char *t, int n)
101 printf("** %s\n", s);
107 fprintf(stderr, "%s.\n", s);
117 fatal("Out of memory");
124 tm.tv_sec = i / 1000000;
125 tm.tv_usec = i % 1000000;
126 select(0, NULL, NULL, NULL, &tm);
133 write(sfd, writbuf, nwrite);
138 void sendbuf(int len)
142 realbuf[0] = realbuf[1] = realbuf[2] = 0;
143 realbuf[3] = (unsigned char)len;
145 if (nwrite + 4 + len >= BUFLEN)
146 fatal("Internal error: send buffer overflow");
147 memcpy(writbuf + nwrite, realbuf, 4 + len);
152 struct user *finduser(unsigned char c)
156 for (u = &me; u; u = u->next)
160 fatal("Protocol error: reference to non-existing user");
161 return NULL; /* so that gcc -Wall doesn't complain */
164 char *get_user_name(unsigned char c)
169 return("the server");
173 for (u = &me; u; u = u->next)
174 if (u->nr == c && u->name && strlen(u->name))
185 options[0] = options[1] = NULL;
187 options[n++] = "-norestart";
189 options[n++] = "-nospeedup";
196 XTRISPATH "/rnd_server",
200 "rnd_server", "-once", "-v", options[0], options[1], NULL);
202 fprintf(stderr, "Can't start server '%s'.\n",
204 XTRISPATH "/rnd_server"
213 fatal("fork() failed");
220 BOOL ConnectToServer(char *host, int port)
223 struct sockaddr_in s;
224 struct protoent *tcpproto;
229 if ((s.sin_addr.s_addr = inet_addr(host)) == -1)
231 hp = gethostbyname(host);
233 fatal("Host not found");
234 s.sin_addr = *(struct in_addr *)(hp->h_addr_list[0]);
238 s.sin_addr.s_addr = inet_addr("127.0.0.1");
243 s.sin_port = htons(port);
244 s.sin_family = AF_INET;
245 sfd = socket(PF_INET, SOCK_STREAM, 0);
247 fatal("Out of file descriptors");
248 if ((tcpproto = getprotobyname("tcp")) != NULL)
249 setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
251 if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) < 0)
255 printf("No rocksndiamonds server on localhost - starting up one ...\n");
261 sfd = socket(PF_INET, SOCK_STREAM, 0);
263 fatal("Out of file descriptors");
264 setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
265 if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) >= 0)
269 fatal("Can't connect to server");
272 fatal("Can't connect to server");
278 void SendToServer_Nickname(char *nickname)
280 static char msgbuf[300];
283 memcpy(&buf[2], nickname, strlen(nickname));
284 sendbuf(2 + strlen(nickname));
285 sprintf(msgbuf, "you set your nick to \"%s\"", nickname);
289 void SendToServer_ProtocolVersion()
292 buf[2] = PROT_VERS_1;
293 buf[3] = PROT_VERS_2;
294 buf[4] = PROT_VERS_3;
298 void SendToServer_StartPlaying()
301 buf[2] = (unsigned char)(level_nr / 256);
302 buf[3] = (unsigned char)(level_nr % 256);
303 buf[4] = (unsigned char)(leveldir_nr / 256);
304 buf[5] = (unsigned char)(leveldir_nr % 256);
305 strcpy(&buf[6], leveldir[leveldir_nr].name);
306 sendbuf(strlen(leveldir[leveldir_nr].name)+1 + 6);
309 void SendToServer_MovePlayer(byte player_action)
312 buf[2] = player_action;
316 void handlemessages()
319 struct user *u, *v = NULL;
320 static char msgbuf[300];
322 while (nread >= 4 && nread >= 4 + readbuf[3])
325 if (readbuf[0] || readbuf[1] || readbuf[2])
326 fatal("Wrong server line length");
328 memcpy(buf, &readbuf[4], len);
330 copydown(readbuf, readbuf + 4 + len, nread);
335 printf("OP_YOUARE: %d\n", buf[0]);
338 TestPlayer = buf[0] - 1;
343 printf("OP_NEW: %d\n", buf[0]);
344 sprintf(msgbuf, "new client %d connected", buf[0]);
347 for (u = &me; u; u = u->next)
350 Error(ERR_EXIT, "multiplayer server sent duplicate player id");
355 v->next = u = mmalloc(sizeof(struct user));
363 printf("OP_NICK: %d\n", buf[0]);
364 u = finduser(buf[0]);
366 sprintf(msgbuf, "client %d calls itself \"%s\"", buf[0], &buf[2]);
368 strncpy(u->name, &buf[2], MAXNICKLEN);
372 printf("OP_GONE: %d\n", buf[0]);
373 u = finduser(buf[0]);
374 sprintf(msgbuf, "client %d (%s) disconnected",
375 buf[0], get_user_name(buf[0]));
378 for (v = &me; v; v = v->next)
386 Error(ERR_RETURN, "protocol version mismatch");
387 Error(ERR_EXIT, "server expects %d.%d.x instead of %d.%d.%d",
388 buf[2], buf[3], PROT_VERS_1, PROT_VERS_2, PROT_VERS_3);
392 printf("OP_PLAY: %d\n", buf[0]);
393 sprintf(msgbuf, "client %d starts game [level %d from levedir %d (%s)]\n",
395 (buf[2] << 8) + buf[3],
396 (buf[4] << 8) + buf[5],
400 if (strcmp(leveldir[(buf[4] << 8) + buf[5]].name, &buf[6]) == 0)
402 leveldir_nr = (buf[4] << 8) + buf[5];
404 local_player->leveldir_nr = leveldir_nr;
405 LoadPlayerInfo(PLAYER_LEVEL);
406 SavePlayerInfo(PLAYER_SETUP);
408 level_nr = (buf[2] << 8) + buf[3];
411 LoadLevelTape(level_nr);
418 TapeStartRecording();
420 game_status = PLAYING;
426 Error(ERR_RETURN, "no such level directory: '%s'", &buf[6]);
433 printf("OP_MOVE: %d\n", buf[0]);
434 sprintf(msgbuf, "client %d moves player [0x%02x]", buf[0], buf[2]);
440 printf("OP_PAUSE: %d\n", buf[0]);
441 sprintf(msgbuf, "client %d pauses game", buf[0]);
446 printf("OP_CONT: %d\n", buf[0]);
447 sprintf(msgbuf, "client %d continues game", buf[0]);
452 printf("OP_WON: %d\n", buf[0]);
453 sprintf(msgbuf, "client %d wins the game", buf[0]);
458 printf("OP_ZERO: %d\n", buf[0]);
459 sprintf(msgbuf, "client %d resets game counters", buf[0]);
464 printf("OP_MSG: %d\n", buf[0]);
465 sprintf(msgbuf, "client %d sends message", buf[0]);
469 printf("OP_MSG: %d\n", buf[0]);
470 sprintf(msgbuf, "client %d has lost", buf[0]);
474 printf("OP_MSG: %d\n", buf[0]);
475 sprintf(msgbuf, "client %d sets level to %d", buf[0], buf[2]);
483 void HandleNetworking()
485 static struct timeval tv = { 0, 0 };
497 r = select(sfd + 1, &rfds, NULL, NULL, &tv);
499 if (r < 0 && errno != EINTR)
502 fatal("fatal: select() failed");
508 if (FD_ISSET(sfd, &rfds))
512 r = read(sfd, readbuf + nread, BUFLEN - nread);
515 fatal("Error reading from server");
517 fatal("Connection to server lost");