about summary refs log tree commit homepage
path: root/lib/yahns/client_expire.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yahns/client_expire.rb')
-rw-r--r--lib/yahns/client_expire.rb40
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/yahns/client_expire.rb b/lib/yahns/client_expire.rb
new file mode 100644
index 0000000..7da9498
--- /dev/null
+++ b/lib/yahns/client_expire.rb
@@ -0,0 +1,40 @@
+# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# included in Yahns::HttpClient
+#
+# this provides the ability to expire idle clients once we hit a soft limit
+# on idle clients
+#
+# we absolutely DO NOT issue IO#close in here, only BasicSocket#shutdown
+module Yahns::ClientExpire # :nodoc:
+  def yahns_expire(timeout) # rarely called
+    return 0 if closed? # still racy, but avoid the exception in most cases
+
+    info = Raindrops::TCP_Info.new(self)
+    return 0 if info.tcpi_state != 1 # TCP_ESTABLISHED == 1
+
+    # Linux struct tcp_info timers are in milliseconds
+    timeout *= 1000
+
+    send_timedout = !!(info.tcpi_last_data_sent > timeout)
+
+    # tcpi_last_data_recv is not valid unless tcpi_ato (ACK timeout) is set
+    if 0 == info.tcpi_ato
+      sd = send_timedout && (info.tcpi_last_ack_recv > timeout)
+    else
+      sd = send_timedout && (info.tcpi_last_data_recv > timeout)
+    end
+    if sd
+      shutdown
+      1
+    else
+      0
+    end
+  # we also do not expire UNIX domain sockets
+  # (since those are the most trusted of local clients)
+  # the IO#closed? check is racy
+  rescue
+    0
+  end
+end