Fix io_close() to obey deadline for output, too
authorMarkus Armbruster <armbru@pond.sub.org>
Sun, 11 Mar 2012 09:06:04 +0000 (10:06 +0100)
committerMarkus Armbruster <armbru@pond.sub.org>
Thu, 26 Apr 2012 17:43:41 +0000 (19:43 +0200)
A client can delay thread exit indefinitely by not reading output.
Broken in commit 08b94556 (v4.3.20) "Reimplement max_idle without a
separate thread".  Until then, the idle thread aborted a stuck attempt
to flush output.

Denial of service seems possible.

Note that commit 904822e3 moved flushing the output queue from
player_login() to io_close().  It also made io_close() wait for the
client to close the connection.  That wait obeys the deadline.

src/lib/empthread/io.c

index af6b97dcf6a2a541c7bf99c54f2149ca79784c94..0a44916d7462da0cf1ec502268775e1d0ff2713b 100644 (file)
@@ -105,6 +105,16 @@ io_open(int fd, int flags, int bufsize)
     return iop;
 }
 
+/*
+ * Close IOP.
+ * Flush output and wait for the client to close the connection.
+ * Wait at most until DEADLINE.  (time_t)-1 means wait as long as it
+ * takes (no timeout).
+ * Both the flush and the wait can be separately cut short by
+ * empth_wakeup().  This is almost certainly not what you want.  If
+ * you need early wakeup, better fix this function not to go to sleep
+ * after wakeup during flush.
+ */
 void
 io_close(struct iop *iop, time_t deadline)
 {
@@ -112,7 +122,7 @@ io_close(struct iop *iop, time_t deadline)
     char buf[IO_BUFSIZE];
     int ret;
 
-    while (io_output(iop, (time_t)-1) > 0) ;
+    while (io_output(iop, deadline) > 0) ;
     shutdown(iop->fd, SHUT_WR);
     while (empth_select(iop->fd, EMPTH_FD_READ,
                        io_timeout(&timeout, deadline)) > 0) {