rnd-19981017-1
[rocksndiamonds.git] / src / network.c
index db7fc95f980d13811ac05718e16a5eff50959ffd..092de4d0a3d55819e61c87d3a3e0601b2be4f4d9 100644 (file)
@@ -62,23 +62,13 @@ int nread = 0, nwrite = 0;
 
 static void sysmsg(char *s)
 {
-  if (verbose)
+  if (options.verbose)
   {
     printf("** %s\n", s);
     fflush(stdout);
   }
 }
 
-static void *mmalloc(int n)
-{
-  void *r;
-
-  r = malloc(n);
-  if (r == NULL)
-    fatal("Out of memory");
-  return r;
-}
-
 static void u_sleep(int i)
 {
   struct timeval tm;
@@ -98,13 +88,13 @@ static void flushbuf()
 
 static void sendbuf(int len)
 {
-  if (!standalone)
+  if (options.network)
   {
     realbuf[0] = realbuf[1] = realbuf[2] = 0;
     realbuf[3] = (unsigned char)len;
     buf[0] = 0;
     if (nwrite + 4 + len >= MAX_BUFFER_SIZE)
-      fatal("Internal error: send buffer overflow");
+      Error(ERR_EXIT, "internal error: network send buffer overflow");
     memcpy(writbuf + nwrite, realbuf, 4 + len);
     nwrite += 4 + len;
 
@@ -123,7 +113,8 @@ struct user *finduser(unsigned char c)
     if (u->nr == c)
       return u;
   
-  fatal("Protocol error: reference to non-existing user");
+  Error(ERR_EXIT, "protocol error: reference to non-existing user %d", c);
+
   return NULL; /* so that gcc -Wall doesn't complain */
 }
 
@@ -148,7 +139,7 @@ static void StartNetworkServer(int port)
   switch (fork())
   {
     case 0:
-      NetworkServer(port, serveronly);
+      NetworkServer(port, options.serveronly);
 
       /* never reached */
       exit(0);
@@ -156,7 +147,7 @@ static void StartNetworkServer(int port)
     case -1:
       Error(ERR_RETURN,
            "cannot create network server process - no network games");
-      standalone = TRUE;
+      options.network = FALSE;
       return;
 
     default:
@@ -165,7 +156,7 @@ static void StartNetworkServer(int port)
   }
 }
 
-BOOL ConnectToServer(char *host, int port)
+boolean ConnectToServer(char *host, int port)
 {
   struct hostent *hp;
   struct sockaddr_in s;
@@ -178,7 +169,8 @@ BOOL ConnectToServer(char *host, int port)
     {
       hp = gethostbyname(host);
       if (!hp)
-       fatal("Host not found");
+       Error(ERR_EXIT, "cannot locate host '%s'", host);
+
       s.sin_addr = *(struct in_addr *)(hp->h_addr_list[0]);
     }
   }
@@ -190,9 +182,11 @@ BOOL ConnectToServer(char *host, int port)
 
   s.sin_port = htons(port);
   s.sin_family = AF_INET;
+
   sfd = socket(PF_INET, SOCK_STREAM, 0);
   if (sfd < 0)
-    fatal("Out of file descriptors");
+    Error(ERR_EXIT, "out of file descriptors");
+
   if ((tcpproto = getprotobyname("tcp")) != NULL)
     setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
 
@@ -208,18 +202,22 @@ BOOL ConnectToServer(char *host, int port)
       {
        u_sleep(500000);
        close(sfd);
+
        sfd = socket(PF_INET, SOCK_STREAM, 0);
        if (sfd < 0)
-         fatal("Out of file descriptors");
-       setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY, (char *)&on, sizeof(int));
+         Error(ERR_EXIT, "out of file descriptors");
+
+       setsockopt(sfd, tcpproto->p_proto, TCP_NODELAY,
+                  (char *)&on, sizeof(int));
+
        if (connect(sfd, (struct sockaddr *)&s, sizeof(s)) >= 0)
          break;
       }
       if (i==6)
-       fatal("Can't connect to server");
+       Error(ERR_EXIT, "cannot connect to server");
     }
     else
-      fatal("Can't connect to server");
+      Error(ERR_EXIT, "cannot connect to server");
   }
 
   return(TRUE);
@@ -314,12 +312,22 @@ static void Handle_OP_YOUR_NUMBER()
 {
   int new_client_nr = buf[2];
   int new_index_nr = new_client_nr - 1;
+  struct PlayerInfo *old_local_player = local_player;
+  struct PlayerInfo *new_local_player = &stored_player[new_index_nr];
 
   printf("OP_YOUR_NUMBER: %d\n", buf[0]);
   me.nr = new_client_nr;
 
-  stored_player[new_index_nr] = *local_player;
-  local_player = &stored_player[new_index_nr];
+  if (old_local_player != new_local_player)
+  {
+    /* copy existing player settings and change to new player */
+
+    *new_local_player = *old_local_player;
+    old_local_player->connected = FALSE;
+    old_local_player->local = FALSE;
+
+    local_player = new_local_player;
+  }
 
   TestPlayer = new_index_nr;
 
@@ -333,38 +341,62 @@ static void Handle_OP_YOUR_NUMBER()
 static void Handle_OP_NUMBER_WANTED()
 {
   int client_nr_wanted = buf[2];
+  int old_client_nr = buf[0];
   int new_client_nr = buf[3];
+  int old_index_nr = old_client_nr - 1;
   int new_index_nr = new_client_nr - 1;
+  int index_nr_wanted = client_nr_wanted - 1;
+  struct PlayerInfo *old_player = &stored_player[old_index_nr];
+  struct PlayerInfo *new_player = &stored_player[new_index_nr];
 
   printf("OP_NUMBER_WANTED: %d\n", buf[0]);
 
-  if (new_client_nr != client_nr_wanted)
+  if (new_client_nr == client_nr_wanted)       /* switching succeeded */
+  {
+    struct user *u;
+
+    if (old_client_nr != client_nr_wanted)     /* client's nr has changed */
+    {
+      sprintf(msgbuf, "client %d switches to # %d",
+             old_client_nr, new_client_nr);
+      sysmsg(msgbuf);
+    }
+    else if (old_client_nr == me.nr)           /* local player keeps his nr */
+    {
+      sprintf(msgbuf, "keeping client # %d", new_client_nr);
+      sysmsg(msgbuf);
+    }
+
+    if (old_client_nr != new_client_nr)
+    {
+      /* copy existing player settings and change to new player */
+
+      *new_player = *old_player;
+      old_player->connected = FALSE;
+      old_player->local = FALSE;
+    }
+
+    u = finduser(old_client_nr);
+    u->nr = new_client_nr;
+
+    if (old_player == local_player)            /* local player switched */
+      local_player = new_player;
+
+
+    TestPlayer = new_index_nr;
+  }
+  else if (old_client_nr == me.nr)             /* failed -- local player? */
   {
     char *color[] = { "yellow", "red", "green", "blue" };
 
-    sprintf(msgbuf, "Sorry ! You are %s player !",
-           color[new_index_nr]);
+    sprintf(msgbuf, "Sorry ! %s player still exists ! You are %s player !",
+           color[index_nr_wanted], color[new_index_nr]);
     Request(msgbuf, REQ_CONFIRM);
 
     sprintf(msgbuf, "cannot switch -- you keep client # %d",
            new_client_nr);
     sysmsg(msgbuf);
   }
-  else
-  {
-    if (me.nr != client_nr_wanted)
-      sprintf(msgbuf, "switching to client # %d", new_client_nr);
-    else
-      sprintf(msgbuf, "keeping client # %d", new_client_nr);
-    sysmsg(msgbuf);
-
-    me.nr = new_client_nr;
-
-    stored_player[new_index_nr] = *local_player;
-    local_player = &stored_player[new_index_nr];
-
-    TestPlayer = new_index_nr;
-  }
 }
 
 static void Handle_OP_NICKNAME(unsigned int len)
@@ -382,23 +414,27 @@ static void Handle_OP_NICKNAME(unsigned int len)
 static void Handle_OP_PLAYER_CONNECTED()
 {
   struct user *u, *v = NULL;
+  int new_client_nr = buf[0];
+  int new_index_nr = new_client_nr - 1;
 
-  printf("OP_PLAYER_CONNECTED: %d\n", buf[0]);
-  sprintf(msgbuf, "new client %d connected", buf[0]);
+  printf("OP_PLAYER_CONNECTED: %d\n", new_client_nr);
+  sprintf(msgbuf, "new client %d connected", new_client_nr);
   sysmsg(msgbuf);
 
   for (u = &me; u; u = u->next)
   {
-    if (u->nr == buf[0])
+    if (u->nr == new_client_nr)
       Error(ERR_EXIT, "multiplayer server sent duplicate player id");
     else
       v = u;
   }
 
-  v->next = u = mmalloc(sizeof(struct user));
-  u->nr = buf[0];
+  v->next = u = checked_malloc(sizeof(struct user));
+  u->nr = new_client_nr;
   u->name[0] = '\0';
   u->next = NULL;
+
+  stored_player[new_index_nr].connected = TRUE;
 }
 
 static void Handle_OP_PLAYER_DISCONNECTED()
@@ -462,7 +498,7 @@ static void Handle_OP_START_PLAYING()
 
 
 
-  if (autorecord_on)
+  if (setup.autorecord_on)
     TapeStartRecording();
 
 
@@ -511,11 +547,14 @@ static void Handle_OP_STOP_PLAYING()
   DrawMainMenu();
 }
 
-static void Handle_OP_MOVE_FIGURE()
+static void Handle_OP_MOVE_FIGURE(unsigned int len)
 {
   int frame_nr;
   int i;
 
+  if (!network_playing)
+    return;
+
   frame_nr =
     (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | (buf[5]);
 
@@ -527,11 +566,10 @@ static void Handle_OP_MOVE_FIGURE()
     Error(ERR_EXIT,   "this should not happen -- please debug");
   }
 
+  /* copy valid player actions */
   for (i=0; i<MAX_PLAYERS; i++)
-  {
-    if (stored_player[i].active)
-      network_player_action[i] = buf[6 + i];
-  }
+    network_player_action[i] =
+      (i < len - 6 && stored_player[i].active ? buf[6 + i] : 0);
 
   network_player_action_received = TRUE;
 
@@ -542,7 +580,7 @@ static void Handle_OP_MOVE_FIGURE()
   */
 }
 
-static void handlemessages()
+static void HandleNetworkingMessages()
 {
   unsigned int len;
 
@@ -550,11 +588,11 @@ static void handlemessages()
   {
     len = readbuf[3];
     if (readbuf[0] || readbuf[1] || readbuf[2])
-      fatal("Wrong server line length");
+      Error(ERR_EXIT, "wrong network server line length");
 
     memcpy(buf, &readbuf[4], len);
     nread -= 4 + len;
-    copydown(readbuf, readbuf + 4 + len, nread);
+    memmove(readbuf, readbuf + 4 + len, nread);
 
     switch(buf[1])
     {
@@ -599,7 +637,7 @@ static void handlemessages()
        break;
 
       case OP_MOVE_FIGURE:
-       Handle_OP_MOVE_FIGURE();
+       Handle_OP_MOVE_FIGURE(len);
        break;
 
       case OP_WON:
@@ -640,9 +678,6 @@ void HandleNetworking()
   fd_set rfds;
   int r = 0;
 
-  if (standalone)
-    return;
-
   flushbuf();
 
   FD_ZERO(&rfds);
@@ -651,10 +686,7 @@ void HandleNetworking()
   r = select(sfd + 1, &rfds, NULL, NULL, &tv);
 
   if (r < 0 && errno != EINTR)
-  {
-    perror("select");
-    fatal("fatal: select() failed");
-  }
+    Error(ERR_EXIT, "HandleNetworking(): select() failed");
 
   if (r < 0)
     FD_ZERO(&rfds);
@@ -666,11 +698,13 @@ void HandleNetworking()
     r = read(sfd, readbuf + nread, MAX_BUFFER_SIZE - nread);
 
     if (r < 0)
-      fatal("Error reading from server");
+      Error(ERR_EXIT, "error reading from network server");
+
     if (r == 0)
-      fatal("Connection to server lost");
+      Error(ERR_EXIT, "connection to network server lost");
+
     nread += r;
 
-    handlemessages();
+    HandleNetworkingMessages();
   }
 }