about summary refs log tree commit homepage
path: root/test
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2012-12-27 01:16:56 +0000
committerEric Wong <normalperson@yhbt.net>2012-12-27 01:23:34 +0000
commitf61cef65b8a8816160c622324b4f1aad55034e4a (patch)
treed5c5b285acb51b12bf407e03f304ab602c283a3d /test
parent7a3fc55424338ad458cc719d4cb3c4e28802d5cb (diff)
downloadkgio-f61cef65b8a8816160c622324b4f1aad55034e4a.tar.gz
Server support just requires exposing one constant for
setsockopt: Kgio::TCP_FASTOPEN

Client support implements a new Kgio::Socket#fastopen method.
This new method wraps the the sendto() syscall.  With TCP Fast
Open, the sendto() syscall is overloaded for stream sockets to
implement the functionality of both connect() + write()

Since it only makes sense to use _blocking_ I/O for sendto(),
TFO clients are only supported in Ruby implementations with
native threads.
Diffstat (limited to 'test')
-rw-r--r--test/test_tfo.rb70
1 files changed, 70 insertions, 0 deletions
diff --git a/test/test_tfo.rb b/test/test_tfo.rb
new file mode 100644
index 0000000..846e273
--- /dev/null
+++ b/test/test_tfo.rb
@@ -0,0 +1,70 @@
+require 'test/unit'
+require 'kgio'
+
+class TestTFO < Test::Unit::TestCase
+  def test_constants
+    if `uname -s`.chomp == "Linux" && `uname -r`.to_f >= 3.7
+      assert_equal 23, Kgio::TCP_FASTOPEN
+      assert_equal 0x20000000, Kgio::MSG_FASTOPEN
+    end
+  end
+
+  def fastopen_ok?
+    if RUBY_PLATFORM =~ /linux/
+      tfo = File.read("/proc/sys/net/ipv4/tcp_fastopen").to_i
+      client_enable = 1
+      server_enable = 2
+      enable = client_enable | server_enable
+      (tfo & enable) == enable
+    else
+      false
+    end
+  end
+
+  def test_tfo_client_server
+    unless fastopen_ok?
+      warn "TCP Fast Open not enabled on this system (check kernel docs)"
+      return
+    end
+    addr = '127.0.0.1'
+    qlen = 1024
+    s = Kgio::TCPServer.new(addr, 0)
+    s.setsockopt(:TCP, Kgio::TCP_FASTOPEN, qlen)
+    port = s.local_address.ip_port
+    addr = Socket.pack_sockaddr_in(port, addr)
+    c = Kgio::Socket.new(:INET, :STREAM)
+    assert_nil c.fastopen("HELLO", addr)
+    a = s.accept
+    assert_equal "HELLO", a.read(5)
+    c.close
+    a.close
+
+    # ensure empty sends work
+    c = Kgio::Socket.new(:INET, :STREAM)
+    assert_nil c.fastopen("", addr)
+    a = s.accept
+    Thread.new { c.close }
+    assert_nil a.read(1)
+    a.close
+
+    # try a monster packet
+    buf = 'x' * (1024 * 1024 * 320)
+
+    c = Kgio::Socket.new(:INET, :STREAM)
+    thr = Thread.new do
+      a = s.accept
+      assert_equal buf.size, a.read(buf.size).size
+      a.close
+    end
+    assert_nil c.fastopen(buf, addr)
+    thr.join
+    c.close
+
+    # allow timeouts
+    c = Kgio::Socket.new(:INET, :STREAM)
+    c.setsockopt(:SOCKET, :SNDTIMEO, [ 0, 10 ].pack("l_l_"))
+    unsent = c.fastopen(buf, addr)
+    c.close
+    assert_equal s.accept.read.size + unsent.size, buf.size
+  end if defined?(Addrinfo) && defined?(Kgio::TCP_FASTOPEN)
+end