added support for protocol version check as first protocol command
[rocksndiamonds.git] / src / netserv.c
index 71b23c959b0587ce5ce4231cfd8259d1165c3134..4b846f9da413425db5e86999fd149111f34ea77c 100644 (file)
@@ -9,20 +9,16 @@
 // netserv.c
 // ============================================================================
 
-#include "libgame/platform.h"
-
-#if defined(NETWORK_AVALIABLE)
-
 #include <fcntl.h>
 #include <sys/time.h>
 #include <signal.h>
 #include <errno.h>
 
-#include "main.h"
-
 #include "libgame/libgame.h"
 
 #include "netserv.h"
+#include "main.h"
+
 
 static int clients = 0;
 static int onceonly = 0;
@@ -47,7 +43,8 @@ static struct NetworkServerPlayerInfo *first_player = NULL;
 #define NEXT(player) ((player)->next ? (player)->next : first_player)
 
 /* TODO: peer address */
-static TCPsocket lfd;          /* listening socket */
+static TCPsocket lfd;          /* listening TCP socket */
+static UDPsocket udp;          /* listening UDP socket */
 static SDLNet_SocketSet fds;   /* socket set */
 
 static unsigned char realbuffer[512], *buffer = realbuffer + 4;
@@ -132,6 +129,7 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player)
   free(player);
   clients--;
 
+#if 0  /* do not terminate network server if last player disconnected */
   if (onceonly && clients == 0)
   {
     if (options.verbose)
@@ -141,6 +139,7 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player)
     }
     exit(0);
   }
+#endif
 }
 
 static void AddPlayer(TCPsocket fd)
@@ -452,7 +451,6 @@ int NetworkServerThread(void *ptr)
 
 void NetworkServer(int port, int serveronly)
 {
-  int sl;
   struct NetworkServerPlayerInfo *player;
   int r; 
   unsigned int len;
@@ -484,14 +482,28 @@ void NetworkServer(int port, int serveronly)
 #endif
 
   if (SDLNet_ResolveHost(&ip, NULL, port) == -1)
-    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_ResolveHost() failed");
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_ResolveHost() failed: %s",
+          SDLNet_GetError());
+
+  if ((fds = SDLNet_AllocSocketSet(MAX_PLAYERS + 1 + 1)) == NULL)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_AllocSocketSet() failed: %s"),
+      SDLNet_GetError();
+
+  if ((lfd = SDLNet_TCP_Open(&ip)) == NULL)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_Open() failed: %s"),
+      SDLNet_GetError();
 
-  lfd = SDLNet_TCP_Open(&ip);
-  if (!lfd)
-    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_Open() failed");
+  if (SDLNet_TCP_AddSocket(fds, lfd) == -1)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_AddSocket() failed: %s"),
+      SDLNet_GetError();
 
-  fds = SDLNet_AllocSocketSet(MAX_PLAYERS+1);
-  SDLNet_TCP_AddSocket(fds, lfd);
+  if ((udp = SDLNet_UDP_Open(port)) == NULL)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_UDP_Open() failed: %s",
+          SDLNet_GetError());
+
+  if (SDLNet_UDP_AddSocket(fds, udp) == -1)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_AddSocket() failed: %s"),
+      SDLNet_GetError();
 
   if (options.verbose)
   {
@@ -507,22 +519,15 @@ void NetworkServer(int port, int serveronly)
     for (player = first_player; player; player = player->next)
       flushuser(player);
 
-    if ((sl = SDLNet_CheckSockets(fds, 500000)) < 1)
-    {
-      Error(ERR_NETWORK_SERVER, "SDLNet_CheckSockets failed: %s",
-           SDLNet_GetError());
-      perror("SDLNet_CheckSockets");
-    }
-
-    if (sl < 0)
-      continue;
-    
-    if (sl == 0)
+    // wait for 100 ms for activity on open network sockets
+    if (SDLNet_CheckSockets(fds, 100) < 1)
       continue;
 
-    /* accept incoming connections */
+    /* accept incoming TCP connections */
     if (SDLNet_SocketReady(lfd))
     {
+      Error(ERR_DEBUG, "got TCP packet");
+
       TCPsocket newsock;
 
       newsock = SDLNet_TCP_Accept(lfd);
@@ -531,9 +536,25 @@ void NetworkServer(int port, int serveronly)
        AddPlayer(newsock);
     }
 
+    /* accept incoming UDP packets */
+    if (SDLNet_SocketReady(udp))
+    {
+      Error(ERR_DEBUG, "got UDP packet");
+
+      static UDPpacket packet;
+
+      int num_packets = SDLNet_UDP_Recv(udp, &packet);
+
+      if (num_packets == 1)
+      {
+        // bounce packet
+        SDLNet_UDP_Send(udp, -1, &packet);
+      }
+    }
+
     player = first_player;
 
-    do
+    while (player && !interrupt)
     {
       if (SDLNet_SocketReady(player->fd))
       {
@@ -568,10 +589,12 @@ void NetworkServer(int port, int serveronly)
          memmove(player->readbuffer, player->readbuffer + 4 + len, player->nread);
 
          buffer[0] = player->number;
-         if (!player->introduced && buffer[1] != OP_PLAYER_NAME)
+         if (!player->introduced &&
+             buffer[1] != OP_PLAYER_NAME &&
+             buffer[1] != OP_PROTOCOL_VERSION)
          {
            if (options.verbose)
-             Error(ERR_NETWORK_SERVER, "!(client %d)->introduced && buffer[1]==%d (expected OP_PLAYER_NAME)", buffer[0], buffer[1]);
+             Error(ERR_NETWORK_SERVER, "!(client %d)->introduced && buffer[1]==%d (expected OP_PLAYER_NAME or OP_PROTOCOL_VERSION)", buffer[0], buffer[1]);
 
            RemovePlayer(player);
            interrupt = 1;
@@ -632,8 +655,5 @@ void NetworkServer(int port, int serveronly)
       if (player && !interrupt)
        player = player->next;
     }
-    while (player && !interrupt);
   }
 }
-
-#endif /* NETWORK_AVALIABLE */