--- deliantra/server/socket/loop.C 2007/07/29 02:24:34 1.65
+++ deliantra/server/socket/loop.C 2007/11/08 19:43:30 1.70
@@ -1,11 +1,11 @@
/*
- * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
+ * This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
- * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
+ * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
* Copyright (©) 2002-2003,2007 Mark Wedel & The Crossfire Development Team
* Copyright (©) 1992,2007 Frank Tore Johansen
*
- * Crossfire TRT is free software: you can redistribute it and/or modify
+ * Deliantra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
@@ -18,7 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
- * The authors can be reached via e-mail to
+ * The authors can be reached via e-mail to
*/
/**
@@ -51,6 +51,9 @@
#define MAX_QUEUE_DEPTH 50
#define MAX_QUEUE_BACKLOG 3.
+// disconnect a socket after this many seconds without an ack
+#define SOCKET_TIMEOUT 8.
+
void
client::reset_state ()
{
@@ -108,33 +111,6 @@
}
void
-flush_sockets (void)
-{
- for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
- (*i)->flush ();
-}
-
-/**
- * This checks the sockets for input, does the right thing.
- *
- * A bit of this code is grabbed out of socket.c
- * There are 2 lists we need to look through - init_sockets is a list
- *
- */
-void
-doeric_server (void)
-{
- //TODO: should not be done here, either
- for (unsigned i = 0; i < clients.size (); ++i)
- {
- client *ns = clients [i];
-
- ns->tick ();
- ns->refcnt_chk ();
- }
-}
-
-void
client::tick ()
{
if (!pl || destroyed ())
@@ -158,6 +134,56 @@
if (update_look)
esrv_draw_look (pl);
+ mapinfo_queue_run ();
+
+#if HAVE_TCP_INFO
+ // check time of last ack, and, if too old, kill connection
+ socklen_t len = sizeof (tcpi);
+
+ if (!getsockopt (fd, IPPROTO_TCP, TCP_INFO, &tcpi, &len) && len == sizeof (tcpi))
+ {
+ if (tcpi.tcpi_snd_mss)
+ mss = tcpi.tcpi_snd_mss;
+
+#if 0
+ fprintf (stderr, "uack %d ack %d lost %d ret %d fack %d sst %d cwnd %d mss %d pmtu %d advmss %d EXC %d\n",
+ tcpi.tcpi_unacked,
+ tcpi.tcpi_sacked,
+ tcpi.tcpi_lost,
+ tcpi.tcpi_retrans,
+ tcpi.tcpi_fackets,
+ tcpi.tcpi_snd_ssthresh, tcpi.tcpi_snd_cwnd, tcpi.tcpi_advmss, tcpi.tcpi_pmtu, tcpi.tcpi_advmss,
+
+ tcpi.tcpi_snd_cwnd - (tcpi.tcpi_unacked - tcpi.tcpi_sacked));
+#endif
+
+ // fast-time-out a player by checking for missign acks
+ // do this only when player is active
+ if (pl && pl->active
+ && tcpi.tcpi_last_ack_recv > int (SOCKET_TIMEOUT * 1000))
+ {
+ send_msg (NDI_RED | NDI_REPLY, "connection-timeout", "safety disconnect due to tcp/ip timeout (no packets received)");
+ write_outputbuffer ();
+
+ LOG (llevDebug, "connection on fd %d closed due to ack timeout (%u/%u/%u)\n", fd,
+ (unsigned)tcpi.tcpi_last_ack_recv, (unsigned)tcpi.tcpi_last_data_sent, (unsigned)tcpi.tcpi_unacked);
+ destroy ();
+ }
+ }
+#endif
+
+ rate_avail = min (max_rate + mss, rate_avail + max_rate);
+
+ int max_send = rate_avail;
+
+#if HAVE_TCP_INFO
+ // further restrict the available bandwidth by the excess bandwidth available
+ max_send = min (max_send, (tcpi.tcpi_snd_cwnd - tcpi.tcpi_unacked + tcpi.tcpi_sacked) * mss);
+#endif
+
+ // if we can split images, round to next-lowest mss
+ if (fxix) max_send -= max_send % mss;
+
if (ixface.empty ())
{
// regularly send a new face when queue is empty
@@ -168,41 +194,27 @@
if (!faces_sent [scrub_idx])
if (faceinfo *f = face_info (scrub_idx))
- if (f->type == FT_FACE) // only scrub faces for now
+ if (f->type == FT_FACE || f->type == FT_SOUND) // only scrub faces and sounds for now
{
send_face (scrub_idx, -120);
flush_fx ();
- bg_scrub = 1; // send up to one face per tick, unless an image was requested
+ bg_scrub = 1; // send up to one fx per tick, unless an image was requested
break;
}
}
-
- rate_avail = max_rate - outputbuffer_len ();
}
else
{
- int ol = outputbuffer_len ();
-
- rate_avail = min (max_rate + mss, rate_avail + max_rate);
-
- int avail = rate_avail;
-
- // if we can split images, round to next-lowest mss
- if (fxix) avail -= avail % mss;
-
- rate_avail -= ol;
- avail -= ol;
-
-#if HAVE_TCP_INFO
- // further restrict the available bandwidth by the excess bandwidth available
- avail = max (0, min (avail, (tcpi.tcpi_snd_cwnd - tcpi.tcpi_unacked + tcpi.tcpi_sacked) * mss));
-#endif
-
bg_scrub = BG_SCRUB_RATE;
- while (avail > 0)
+ for (;;)
{
+ int avail = max_send - outputbuffer_len ();
+
+ if (avail <= 0)
+ break;
+
ixsend &ix = ixface.back ();
if (facedata *d = face_data (ix.idx, faceset))
@@ -241,13 +253,6 @@
else
ix.ofs = 0;
- int consumed = outputbuffer_len () - ol;
-
- avail -= consumed;
- rate_avail -= consumed;
-
- ol = outputbuffer_len ();
-
if (!ix.ofs)
{
ixface.pop_back ();
@@ -257,5 +262,28 @@
}
}
}
+
+ rate_avail -= outputbuffer_len ();
+}
+
+void
+client::flush_sockets (void)
+{
+ for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
+ (*i)->flush ();
+}
+
+void
+client::clock (void)
+{
+ for (sockvec::iterator i = clients.begin (); i != clients.end (); ++i)
+ (*i)->tick ();
+
+ // give them all the same chances
+ flush_sockets ();
+
+ //TODO: should not be done here, either
+ for (unsigned i = 0; i < clients.size (); ++i)
+ clients[i]->refcnt_chk ();
}