DEADSOFTWARE

Master: Fix timeouts
[d2df-sdl.git] / src / mastersrv / master.c
index b344dac83894c7855f7b0dde3b25b40535fc2290..ca1c129895cb851f83c68d026288706b462bf011 100644 (file)
@@ -3,9 +3,10 @@
 #include <string.h>
 #include <enet/enet.h>
 #include <enet/types.h>
+#include <time.h>
 
-#define MS_VERSION "0.1"
-#define MS_MAXSRVS 32
+#define MS_VERSION "0.2"
+#define MS_MAXSRVS 128
 #define MS_TIMEOUT 100
 
 #define NET_CHANS 2
 #define LC_MS_UPD  "\nUpdated server #%d (%s:%d):\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
 #define LC_MS_RM   "\nRemoved server #%d (%s:%d) by request.\n"
 #define LC_MS_TIME "\nServer #%d (%s:%d) timed out.\n"
-#define LC_MS_LIST "\nSent server list to %x:%u.\n"
+#define LC_MS_LIST "\nSent server list to %x:%u (ver. %s).\n"
 #define LC_MS_DIE  "\nD2DF master server shutting down...\n"
 #define LC_MS_CONN "\nIncoming connection from %x:%u...\n"
+#define LC_MS_MOTD "\nMOTD: %s\n"
+#define LC_MS_URGENT "\nURGENT: %s\n"
 
+#define MS_URGENT_FILE "urgent.txt"
+#define MS_MOTD_FILE "motd.txt"
 
 struct ms_server_s {
   enet_uint8 used;
@@ -40,14 +45,17 @@ struct ms_server_s {
   enet_uint8  s_mode;
   enet_uint8  s_protocol;
   enet_uint16 s_port;
-  enet_uint32 ttl;
+  time_t      deathtime;
 };
 
 typedef struct ms_server_s ms_server;
 
 const char ms_game_ver[] = "0.63";
+char ms_motd[255] = "";
+char ms_urgent[255] = "";
+
 int ms_port = 25660;
-int ms_timeout = 100000;
+int ms_timeout = 100;
 
 size_t b_read = 0;
 size_t b_write = 0;
@@ -59,6 +67,30 @@ ENetPeer  *ms_peers[NET_MAXCLIENTS];
 ms_server  ms_srv[MS_MAXSRVS];
 enet_uint8 ms_count = 0;
 
+// fake servers to show on old versions of the game
+static const ms_server ms_fake_srv[] = {
+  {
+    .used = 1,
+    .s_ip = "0.0.0.0",
+    .s_name = "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
+              "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
+              "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
+              "doom2d.org !",
+    .s_map = "! Your game is outdated. "
+             "Get latest version at doom2d.org !",
+    .s_protocol = 255,
+  },
+  {
+    .used = 1,
+    .s_ip = "0.0.0.0",
+    .s_name = "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
+              "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
+    .s_map = "! Forward ports 25666 and 57133 before hosting !",
+    .s_protocol = 255,
+  },
+};
+
+#define MS_FAKESRVS (sizeof(ms_fake_srv) / sizeof(ms_fake_srv[0]))
 
 void i_usage () {
   printf("Usage: d2df_master -p port_number [-t timeout_seconds]\n");
@@ -102,13 +134,34 @@ void d_getargs (int argc, char *argv[]) {
         ms_port = atoi(argv[++i]);
       }
     } else if (!strcmp(argv[i], "-t") & (i + 1 < argc)) {
-        ms_timeout = atoi(argv[++i]) * 1000;
+        ms_timeout = atoi(argv[++i]);
+    }
+  }
+}
+
+
+int d_readtextfile (const char *fname, char *buf, size_t max) {
+  FILE *f = fopen(fname, "r");
+  char *const end = buf + max - 1;
+  char *p = buf;
+  if (f) {
+    char ln[max];
+    char *const lend = ln + max - 1;
+    while(p < end && fgets(ln, sizeof(ln), f)) {
+      for (char *n = ln; n < lend && *n && *n != '\r' && *n != '\n'; ++n) {
+        *(p++) = *n;
+        if (p == end) break;
+      }
     }
+    *p = '\0';
+    fclose(f);
+    return 0;
   }
+  return 1;
 }
 
 
-enet_uint8  b_read_uint8 (enet_uint8 buf[], size_t *pos) {
+enet_uint8 b_read_uint8 (enet_uint8 buf[], size_t *pos) {
   return buf[(*pos)++];
 }
 
@@ -181,6 +234,12 @@ int main (int argc, char *argv[]) {
 
   printf(LC_MS_INIT, ms_port);
 
+  d_readtextfile(MS_MOTD_FILE, ms_motd, sizeof(ms_motd));
+  d_readtextfile(MS_URGENT_FILE, ms_urgent, sizeof(ms_urgent));
+
+  if (ms_motd[0]) printf(LC_MS_MOTD, ms_motd);
+  if (ms_urgent[0]) printf(LC_MS_URGENT, ms_urgent);
+
   for (int i = 0; i < NET_MAXCLIENTS; ++i) ms_peers[i] = NULL;
 
   for (int i = 0; i < MS_MAXSRVS; ++i) {
@@ -188,7 +247,7 @@ int main (int argc, char *argv[]) {
     ms_srv[i].s_ip[0] = '\0';
     ms_srv[i].s_name[0] = '\0';
     ms_srv[i].s_map[0] = '\0';
-    ms_srv[i].ttl = 0;
+    ms_srv[i].deathtime = 0;
   }
 
   ENetAddress addr;
@@ -212,6 +271,7 @@ int main (int argc, char *argv[]) {
 
   char *name = NULL;
   char *map = NULL;
+  char *clientver = NULL;
   enet_uint8 gm = 0;
   enet_uint16 pl = 0;
   enet_uint16 mpl = 0;
@@ -219,7 +279,7 @@ int main (int argc, char *argv[]) {
   enet_uint8 proto = 0;
   enet_uint8 pw = 0;
   while (!shutdown) {
-    while (enet_host_service(ms_host, &event, 1) > 0) {
+    while (enet_host_service(ms_host, &event, 5000) > 0) {
       switch (event.type) {
         case ENET_EVENT_TYPE_CONNECT:
           printf(LC_MS_CONN, event.peer->address.host, event.peer->address.port);
@@ -249,29 +309,29 @@ int main (int argc, char *argv[]) {
               for (int i = 0; i < MS_MAXSRVS; ++i) {
                 if (ms_srv[i].used) {
                   if ((strncmp(ip, ms_srv[i].s_ip, 16) == 0) && (ms_srv[i].s_port == port)) {
-                    strncpy(ms_srv[i].s_map, map, 255);
-                    strncpy(ms_srv[i].s_name, name, 255);
+                    strncpy(ms_srv[i].s_map, map, sizeof(ms_srv[i].s_map));
+                    strncpy(ms_srv[i].s_name, name, sizeof(ms_srv[i].s_name));
                     ms_srv[i].s_plrs = pl;
                     ms_srv[i].s_maxplrs = mpl;
                     ms_srv[i].s_pw = pw;
                     ms_srv[i].s_mode = gm;
 
-                    ms_srv[i].ttl = ms_timeout;
+                    ms_srv[i].deathtime = time(NULL) + ms_timeout;
 
                     printf(LC_MS_UPD, i, ip, port, name, map, gm, pl, mpl, proto, pw);
                     break;
                   }
                 } else {
-                    strncpy(ms_srv[i].s_ip, ip, 16);
-                    strncpy(ms_srv[i].s_map, map, 255);
-                    strncpy(ms_srv[i].s_name, name, 255);
+                    strncpy(ms_srv[i].s_ip, ip, sizeof(ms_srv[i].s_ip));
+                    strncpy(ms_srv[i].s_map, map, sizeof(ms_srv[i].s_map));
+                    strncpy(ms_srv[i].s_name, name, sizeof(ms_srv[i].s_name));
                     ms_srv[i].s_port = port;
                     ms_srv[i].s_plrs = pl;
                     ms_srv[i].s_maxplrs = mpl;
                     ms_srv[i].s_pw = pw;
                     ms_srv[i].s_mode = gm;
                     ms_srv[i].s_protocol = proto;
-                    ms_srv[i].ttl = ms_timeout;
+                    ms_srv[i].deathtime = time(NULL) + ms_timeout;
 
                     ms_srv[i].used = 1;
 
@@ -299,18 +359,41 @@ int main (int argc, char *argv[]) {
               break;
             case NET_MSG_LIST:
               if (!event.peer) continue;
+
               b_write = 0;
               b_write_uint8(b_send, &b_write, NET_MSG_LIST);
-              b_write_uint8(b_send, &b_write, ms_count);
+
+              if (event.packet->dataLength > 2) {
+                // holy shit a fresh client
+                clientver = b_read_dstring(event.packet->data, &b_read);
+                b_write_uint8(b_send, &b_write, ms_count);
+              } else {
+                // old client, feed them bullshit first
+                b_write_uint8(b_send, &b_write, ms_count + 2);
+                for (int i = 0; i < MS_FAKESRVS; ++i)
+                  b_write_server(b_send, &b_write, ms_fake_srv[i]);
+              }
+
               for (int i = 0; i < MS_MAXSRVS; ++i) {
                 if (ms_srv[i].used) b_write_server(b_send, &b_write, ms_srv[i]);
               }
 
+              if (clientver) {
+                // TODO: check if this client is outdated (?) and send back new verstring
+                // for now just write the same shit back
+                b_write_dstring(b_send, &b_write, clientver);
+                // write the motd and urgent message
+                b_write_dstring(b_send, &b_write, ms_motd);
+                b_write_dstring(b_send, &b_write, ms_urgent);
+              }
+
               ENetPacket *p = enet_packet_create(b_send, b_write, ENET_PACKET_FLAG_RELIABLE);
               enet_peer_send(event.peer, NET_CH_MAIN, p);
               enet_host_flush(ms_host);
 
-              printf(LC_MS_LIST, event.peer->address.host, event.peer->address.port);
+              printf(LC_MS_LIST, event.peer->address.host, event.peer->address.port, clientver ? clientver : "<old>");
+              free(clientver);
+              clientver = NULL;
               break;
           }
 
@@ -322,9 +405,10 @@ int main (int argc, char *argv[]) {
       }
     }
 
+    time_t now = time(NULL);
     for (int i = 0; i < MS_MAXSRVS; ++i) {
       if (ms_srv[i].used) {
-        if (--(ms_srv[i].ttl) == 0) {
+        if (ms_srv[i].deathtime <= now) {
           ms_srv[i].used = 0;
           printf(LC_MS_TIME, i, ms_srv[i].s_ip, ms_srv[i].s_port);
           --ms_count;